24.01.10 최초 작성
USB Host | USB Device |
---|---|
master에 해당 | slave에 해당 |
wiring
VCC | GND | Data + | Data - |
---|---|---|---|
전원 | 접지 | Data + 끼리 연결 | Data - 끼리 연결 |
version
Known Name | Data Rate | Power Capabilities | |
---|---|---|---|
usb v1.1 | X | 12Mbps | 150mA |
usb v2.0 | High-Speed USB | 480Mbps | 500mA |
usb v3.0 | SuperSpeed USB | 5Gbps | 1.5A |
usb v3.1 | SuperSpeed+ USB | 10Gbps | 20A |
HID | CDC | MSC | Custom Device Class |
---|
각 장치 종류 마다 Host-Device
간 사용하는 프로토콜을 달리함
USB 장치에 여러개의 Interface
가 존재하고 Interface 내에 하나 혹은 여러개의 Endpoint
가 존재
Endpoint0
는 양방향 통신이 가능하며 Endpoint
는 Input/Output
중 하나의 역할을 담당함
여러 Endpoint
를 모아 특정 장치와 통신하는 통로로 사용함
USB class
종류
HID | CDC | MSC | Custom Device Class |
---|
Control
: enumeration에 사용
Interrupt
: 작은 크기의 데이터 통신 (마우스 ...)
Bulk
: 큰 크기의 데이터 통신에 사용하며 ACK
체크 사용 (Network, Mass storage...)
Isochronous
: 큰 데이터 데이터 통신에 사용하며 ACK
체크 하지 않음 (Audio, Video ...)
장치가 호스트에 연결되면 호스트가 장치를 감지하고 장치의 통신 속도를 알아냄
이후 device descriptor
에서부터 장치 정보를 받아옴
장치를 초기화하고 주소를 할당, configuration descriptor
를 통해 장치 설정 정보 가져옴
interface descriptor
가져와 USB class
정보를 가져옴
드라이버를 로드하면 장치 사용 준비 완료
descriptor
USB Device
: USB Gadget (USB class의 모음)
+ UDC (USB Device Controller의 드라이버)
linux-menuconfig
에서 sudo apt install wireshark
sudo modprobe usbmon //usb 통신 확인 가능하도록 설정
sudo wireshark
k_usb.c
: usb에 장치가 감지되면 device descriptor
, endpoint descriptor
를 화면에 출력k_usb_table
: 장치의 정보를 등록하고 연결된 장치가 이것과 일치하면 .probe
에 등록한 함수 호출#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
#define USB_VENDOR_ID 0xc0f4
#define USB_PRODUCT_ID 0x01e0
const struct usb_device_id k_usb_table[] = {
{USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID)},
{},
};
MODULE_DEVICE_TABLE(usb, k_usb_table);
static struct usb_driver k_usb_driver = {
.name = "K USB Driver",
.probe = k_usb_probe,
.disconnect = k_usb_disconnect,
.id_table = k_usb_table,
};
k_usb_probe()
: 장치에 할당된 endpoint
의 갯수를 세고 descriptor 출력하는 함수 호출static int k_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
unsigned int i;
unsigned int ep_count;
struct usb_host_interface *iface_desc = interface->cur_altsetting;
dev_info(&interface->dev, "Vendor ID : 0x%02x, Product ID : 0x%02x\n", id->idVendor, id->idProduct);
ep_count = iface_desc->desc.bNumEndpoints;
print_interface_descriptor(iface_desc->desc);
for (i = 0; i < ep_count; i++) {
print_usb_endpoint_descriptor(iface_desc->endpoint[i].desc);
}
return 0;
}
print_interface_descriptor()
, print_usb_endpoint_descriptor()
: 장치의 각 descriptor 출력void print_interface_descriptor(struct usb_interface_descriptor i)
{
pr_info("USB_INTERFACE_DESCRIPTOR:\n");
pr_info("bLength: 0x%x\n", i.bLength);
pr_info("bDescriptorType: 0x%x\n", i.bDescriptorType);
pr_info("bInterfaceNumber: 0x%x\n", i.bInterfaceNumber);
pr_info("bAlternateSetting: 0x%x\n", i.bAlternateSetting);
pr_info("bNumEndpoints: 0x%x\n", i.bNumEndpoints);
pr_info("bInterfaceClass: 0x%x\n", i.bInterfaceClass);
pr_info("bInterfaceSubClass: 0x%x\n", i.bInterfaceSubClass);
pr_info("bInterfaceProtocol: 0x%x\n", i.bInterfaceProtocol);
pr_info("iInterface: 0x%x\n", i.iInterface);
pr_info("\n");
}
void print_usb_endpoint_descriptor(struct usb_endpoint_descriptor e)
{
pr_info("USB_ENDPOINT_DESCRIPTOR:\n");
pr_info("bLength: 0x%x\n", e.bLength);
pr_info("bDescriptorType: 0x%x\n", e.bDescriptorType);
pr_info("bEndPointAddress: 0x%x\n", e.bEndpointAddress);
pr_info("bmAttributes: 0x%x\n", e.bmAttributes);
pr_info("wMaxPacketSize: 0x%x\n", e.wMaxPacketSize);
pr_info("bInterval: 0x%x\n", e.bInterval);
pr_info("\n");
}