在Linux系统中,提供了主机侧和设备侧USB驱动框架。
从主机侧,需要编写USB驱动包括主机控制器驱动,设备驱动两类,USB
主机控制驱动程序控制插入其中的USB设备。
USB设备驱动程序控制该设备如何作为从设备与主机进行通信。
1.主机侧与设备侧USB驱动
USB采用树状拓扑结构,主机侧和设备侧的USB控制器分别为主机控制器和USB
设备控制器,每条总线上只有一个主机控制器,负责协调主机与设备间的通讯,而设备不能主动向主机发送任何数据。
从主机侧看,要实现的USB驱动包括两类:USB主机控制器驱动和USB设备驱动。
USB设备驱动MASS storage/CDC/HID | 控制USB设备如何与主机通信 |
USB核心 | 负责USB驱动管理和协议处理的主要工作。 1.通过定义一些数据结构,宏和函数功能,向上为设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口。 2.维护整个系统的USB设备信息。 3.完成设备热插拔控制,总线数据传输控制 |
USB主机控制器驱动OHCI/EHCI/UHCI | 控制插入其中的USB设备 |
主机控制器 | 只有一个主机控制器,负责协调主机与设备间的通讯 |
从设备上看,
Gardget Function 驱动(Mass storage/serial...) | 具体控制USB功能的实现,使设备表现出“网络连接”,“打印机”或者“USB Mass Storage” |
Gadet Function API | UDC驱动函数的简单包装 |
UDC驱动(omap/pxa2xx) | 直接访问硬件,控设备和主机间的地层通信 |
USB设备控制器 |
2.设备,配置,接口,端点
在USB设备逻辑中,包含设备,配置,接口和端点4个层次。
接口 | 1.代表一个节本功能,是USB设备驱动程序控制对象,一个复杂的USB设备可以有多个接口。 2.每个配置有多个接口,而设备接口是端点的汇集。 一个配置中所有接口都可以同时有效,并且被不同的驱动程序连接。 |
端点 | 是USB通信的最基本形式,每个USB设备接口在主机看来就是一个端点的集合。 主机只能通过端点与设备进行通信,以使用设备功能。 每个端点都有一定的属性,包括传述方向,总线访问频率,贷款,端点好,数据包的最大容量等。 一个端点只能一个方向上成在数据,从主机到设备(输入端点),或者从设备到主机(输出端点),因此端点可看作一个单向的管道。 |
设备通常有一个或者多个配置
配置通常有一个或者多个接口
接口通常有一个或者多个配置
接口有0个或者多个端点。
这种层次花配置信息在设备中通过一组标准的描述符来描述。
设备描述符 | 1.关于设备的通用信息,例如供应商 ID,产品ID,修订ID,支持设备类,自类和适合协议以及默认端点的最大包大小。 2.在LInux内核中,USB设备用usb_device结构体来描述,USB 设备描述符定义为usb_device_descriptor结构体。 |
配置描述符 | 此配置中的接口,支持的刮起和恢复的能力以及功率的要求。USB配置在内核中使用usb_host_config接口体描述,USB配置描述定义为结构体usb_config_descriptor |
接口描述符 | 接口类,子类和使用的协议,接口备用配置的数目和端点数目。 USB接口在内核中使用usb_interface结构体描述。 |
端点描述符 | 端点地址,方向和类型,支持的最大报打包大小,如果是中断类型的端点侧包括轮询频率。使用usb_host)endpoint接口体来描述。 |
设备描述符定义为usb_device_descriptor结构体
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor { //usb设备描述符
__u8 bLength;//长度
__u8 bDescriptorType;//描述符类型
__le16 bcdUSB;//usb SPEC的版本
__u8 bDeviceClass;//设别类型
__u8 bDeviceSubClass;//设备子类型
__u8 bDeviceProtocol;//协议
__u8 bMaxPacketSize0;//最大传输大小
__le16 idVendor;//厂商ID
__le16 idProduct;//设备ID
__le16 bcdDevice;//设备版本号
__u8 iManufacturer;//描述厂商字符串的索引
__u8 iProduct;//描述产品字符串的索引
__u8 iSerialNumber;//序列号
__u8 bNumConfigurations;//设备当前速度模式下支持的配置数量。有的设备可以在多个速度模式下操作,这里包括的只是当前速度模式下的配置数目,不是总的配置数目
} __attribute__ ((packed));
配置描述符:用结构体usb_config_descriptor描述。
struct usb_config_descriptor { //配置描述符
__u8 bLength;//描述符长度
__u8 bDescriptorType;//配置描述符的类型
__le16 wTotalLength;//使用GET_DESCRIPTOR请求从设备里获得配置描述符信息时,返回的数据长度
__u8 bNumInterfaces;//这个配置包含的接口数量
__u8 bConfigurationValue;//对于拥有多个配置的设备来说,可以拿这个值为参数,使用SET_CONFIGURATION请求来改变正在被使用的 USB配置,
bConfigurationValue就指明了将要激活哪个配置。咱们的设备虽然可以有多个配置,但同一时间却也只能有一个配置被激活。捎带着提一下,
SET_CONFIGURATION请求也是标准的设备请求之一,专门用来设置设备的配置。
__u8 iConfiguration;//描述配置信息的字符串描述符的索引值
__u8 bmAttributes;//这个字段表征了配置的一些特点,比如bit 6为1表示self-powered,bit 5为1表示这个配置支持远程唤醒。
另外,它的bit 7必须为1
__u8 bMaxPower;//设备正常运转时,从总线那里分得的最大电流值,以2mA为单位。
设备可以使用这个字段向hub表明自己需要的的电流,但如果设备需求过于旺盛,
请求的超出了hub所能给予的,hub就会直接拒绝还记得struct usb_device结构里的bus_mA吗?它就表示hub所能够给予的。计算机的usb端口可以提供最多500mA的电流
} __attribute__ ((packed));
接口描述符:用usb_interface_descriptor结构体描述
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;//接口描述符长度
__u8 bDescriptorType;//接口描述符类型
__u8 bInterfaceNumber;//接口号。每个配置可以包含多个接口,这个值就是它们的索引值。
__u8 bAlternateSetting;//接口使用的是哪个可选设置。协议里规定,接口默认使用的设置总为0号设置。
__u8 bNumEndpoints;//接口拥有的端点数量。这里并不包括端点0,因为端点0是控制传输,是所有的设备都必须提供的,
所以这里就没必要多此一举的包括它了。对于hub,因为它的传输是中断传输,所以此值为1(不包括端点0)
__u8 bInterfaceClass;//接口类型
__u8 bInterfaceSubClass;//接口子类型
__u8 bInterfaceProtocol;//接口所遵循的协议
__u8 iInterface;//描述该接口的字符串索引值
} __attribute__ ((packed));
端点描述符:定义为usb_endpoint_descriptor结构体
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {//USB 端点描述符(每个USB设备最多有16个端点)
__u8 bLength;//描述符的字节长度
__u8 bDescriptorType;//描述符类型,对于端点就是USB_DT_ENDPOIN
__u8 bEndpointAddress;//bit0~3表示端点地址,bit8 表示方向,输入还是输出
__u8 bmAttributes;//属性(bit0、bit1构成传输类型,00--控制,01--等时,10--批量,11--中断)
__le16 wMaxPacketSize;//端点一次可以处理的最大字节数
__u8 bInterval;//希望主机轮询自己的时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;//对于同步传送的端点,此域必须为1
} __attribute__ ((packed));
可以通过lsusb -v查看usb节电信息
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 3.10
bDeviceClass 9 Hub
bDeviceSubClass 0
bDeviceProtocol 3
bMaxPacketSize0 9
idVendor 0x1d6b Linux Foundation
idProduct 0x0003 3.0 root hub
bcdDevice 6.05
iManufacturer 3 Linux 6.5.0-35-generic xhci-hcd
iProduct 2 xHCI Host Controller
iSerial 1 0000:03:00.4
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x001f
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 9 Hub
bInterfaceSubClass 0
bInterfaceProtocol 0 Full speed (or root) hub
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0004 1x 4 bytes
bInterval 12
bMaxBurst 0