一、USB设备描述符
一个USB设备描述符中可以有多个配置描述符,即USB设备可以有多种配置;一个配置描述符中可以有多个接口描述符,即USB设备可以支持多种功能(接口);一个接口描述符中可以有多个端点描述符。
一设备至少要包含设备描述符、配置描述符和接口描述符,如果USB设备没有端点描述符,则它仅仅用默认管道与主机进行数据传输。
接口,表示逻辑上的设备,比如USB声卡可以分为接口1-录音设备,接口2-播放设备。
访问设备时,即访问某个接口,接口表示逻辑设备。
传输数据时,即读写某个端口,端口是数据通道。
1.1 设备描述符
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength; //该结构体大小
__u8 bDescriptorType; //描述符类型 (此处应为0x01,即设备描述符)
__le16 bcdUSB; //usb版本号 200 -> USB2.0
__u8 bDeviceClass; //设备类
__u8 bDeviceSubClass; //设备类子类
__u8 bDeviceProtocol; //设备协议,以上三点都是USB官方定义
__u8 bMaxPacketSize0; //端点0最大包大小 (只能为8,16,32,64)
__le16 idVendor; //厂家id
__le16 idProduct; //产品id
__le16 bcdDevice; //设备出厂编号
__u8 iManufacturer; //描述厂商信息的字符串描述符的索引值
__u8 iProduct; //描述产品信息的字串描述符的索引值
__u8 iSerialNumber; //描述设备序列号信息的字串描述符的索引值
__u8 bNumConfigurations; //可能的配置描述符的数目
} __attribute__ ((packed));
1.2 配置描述符
struct usb_config_descriptor {
__u8 bLength; //该结构体大小
__u8 bDescriptorType;//描述符类型(本结构体中固定为0x02)
__le16 wTotalLength; //该配置下,信息的总长度(包括配置,接口,端点和设备类及厂商定义的描述符)
__u8 bNumInterfaces; //接口的个数
__u8 bConfigurationValue; //Set_Configuration命令所需要的参数值,用来选定此配置
__u8 iConfiguration; //描述该配置的字符串描述的索引值
__u8 bmAttributes;//供电模式的选择
__u8 bMaxPower;//设备从总线提取的最大电流
} __attribute__ ((packed));
1.3 接口描述符
struct usb_interface_descriptor {
__u8 bLength; //该结构体大小
__u8 bDescriptorType;//接口描述符的类型编号(0x04)
__u8 bInterfaceNumber; //该接口的编号
__u8 bAlternateSetting; //备用的接口描述符编号
__u8 bNumEndpoints; //该接口使用的端点数,不包括端点0
__u8 bInterfaceClass; //接口类
__u8 bInterfaceSubClass; //子类
__u8 bInterfaceProtocol; //协议
__u8 iInterface;//描述此接口的字串描述表的索引值
} __attribute__ ((packed));
配置描述符中包含了一个或多个接口描述符,这里的“接口”并不是指物理存在的接口,在这里把它称之为“功能”更易理解些,例如一个设备既有录音的功能又有扬声器的功能,则这个设备至少就有两个“接口”。
1.4 端点描述符
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
__u8 bLength; //端点描述符字节数大小(7个字节)
__u8 bDescriptorType;//端点描述符类型编号(0x05)
__u8 bEndpointAddress; //此描述表所描述的端点的地址、方向 :
// bit3~bit0:端点号,bit6~bit4:保留,
// bit7:方向,如果是控制端点则忽略,0-输出端点(主机到设备)1-输入端点(设备到主机)
__u8 bmAttributes; // 端点特性,bit1~bit0 表示传输类型,其他位保留
// 00-控制传输 01-实时传输 10-批量传输 11-中断传输
__le16 wMaxPacketSize; //端点收、发的最大包大小
__u8 bInterval; // 中断传输模式中主机查询端点的时间间隔。
// 对于实时传输的端点此域必需为1,表示周期为1ms。对于中断传输的端点此域值的范围为1ms到255ms
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点0(控制端点,一般一个设备只有一个控制端点)为双向端口外,其它均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小和端点号(也可称为端点地址)等。
除了描述符中描述的端点外,每个设备必须要有一个默认的控制型端点,地址为0,它的数据传输为双向,而且没有专门的描述符,只是在设备描述符中定义了它的最大包长度。主机通过此端点向设备发送命令,获得设备的各种描述符的信息,并通过它来配置设备。
1.5 字符描述符
struct usb_string_descriptor {
__u8 bLength; // 此描述表的字节数(bString域的数值N+2)
__u8 bDescriptorType; // 字串描述表类型(此处应为0x03)__le16 wData[1]; /* UTF-16LE encoded */
} __attribute__ ((packed));
1.6 人机接口描述符
USB 设备中有一大类就是 HID 设备,即 Human Interface Devices,人机接口设备。这类设备包括鼠标、键盘等,主要用于人与计算机进行交互。 它是 USB 协议最早支持的一种设备类。 HID 设备可以作为低速、全速、高速设备用。由于 HID 设备要求用户输入能得到及时响应,故其传输方式通常采用中断方式。
在 USB 协议中, HID 设备的定义放置在接口描述符中, USB 的设备描述符和配置描述符中不包含 HID 设备的信息。因此,对于某些特定的 HID 设备,可以定义多个接口,只有其中一个接口为 HID 设备类即可。
1.7 USB描述符的类型值
二、USB总线驱动程序
2.1 usb core
初始化内核USB总线及提供USB相关API,为设备驱动和HCD的交互提供桥梁。
usb_init
static int __init usb_init(void)
{
int retval;
if (usb_disabled()) {
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
usb_init_pool_max();usb_debugfs_init();
usb_acpi_register();
retval = bus_register(&usb_bus_type); -----------------(1)
if (retval)
goto bus_register_failed;
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
if (retval)
goto bus_notifier_failed;
retval = usb_major_init();
if (retval)
goto major_init_failed;
retval = usb_register(&usbfs_driver); ---------------------------(2)
if (retval)
goto driver_register_failed;
retval = usb_devio_init();
if (retval)
goto usb_devio_init_failed;
retval = usb_hub_init(); -----------------------------------(3)
if (retval)
goto hub_init_failed;
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);-------(4)
if (!retval)
goto out;usb_hub_cleanup();
hub_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
major_init_failed:
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
usb_acpi_unregister();
usb_debugfs_cleanup();
out:
return retval;
}
(1)USB是基于总线-驱动-设备模型的框架,其初始化阶段一个重点任务就是完成USB总线的创建。usb_bus_type提供了驱动和设备匹配的匹配函数,后面注册设备和驱动时会调用到。
usb_bus_type
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match, //调用这个匹配函数
.uevent = usb_uevent,
.need_parent_lock =