第一部分 USB驱动程序框架
app:
-------------------------------------------
USB设备驱动程序 // 知道数据含义
内核 --------------------------------------
USB总线驱动程序 // 1. 识别, 2. 找到匹配的设备驱动, 3. 提供USB读写函数 (它不知道数据含义)
-------------------------------------------
USB主机控制器
UHCI OHCI EHCI
硬件 -----------
USB设备
UHCI: intel, 低速(1.5Mbps)/全速(12Mbps)
OHCI: microsoft 低速/全速
EHCI: 高速(480Mbps)
第二部分 USB设备基础概念
在终端用户看来,USB设备为主机提供了多种多样的附加功能,如文件传输,声音播放等,但对USB主机来说,它与所有USB设备的接口都是一致的。一个USB设备由3个功能模块组成:USB总线接口、USB逻辑设备和功能单元:
a -- 这里的USB总线接口指的是USB设备中的串行接口引擎(SIE);
b -- USB逻辑设备被USB系统软件看作是一个端点的集合;
c -- 功能单元被客户软件看作是一个接口的集合。SIE、端点和接口都是USB设备的组成单元;
为了更好地描述USB设备的特征,USB提出了设备架构的概念。从这个角度来看,可以认为USB设备是由一些配置、接口和端点组成,即一个USB设备可以含有一个或多个配置(不同的配置使设备表现出不同的功能组合,在探测/连接期间需要从中选定一个),在每个配置中可含有一个或多个接口(一个配置中的所有接口可以同时有效,并可被不同的程序连接),在每个接口中可含有若干个端点(代表一个基本功能,每个端点都有一定的属性,其中包括传输方式、总线访问频率、带宽、端点号和数据包的最大容量等)。其中,配置和接口是对USB设备功能的抽象,实际的数据传输由端点来完成。在使用USB设备前,必须指明其采用的配置和接口。这个步骤一般是在设备接入主机时设备进行枚举时完成的。
usb设备非常复杂,有许多不同的逻辑单元组成,这些单元的关系如下:
设备描述符(usb_device_descriptor):关于设备的通用信息,如供货商ID及适用的协议等,在Linux内核中,USB设备用usb_device结构体来描述,位于include/uapi/linux/usb/ch9.h中,一个USB设备只能有一个设备描述符。
1 struct usb_device_descriptor { 2 __u8 bLength; //描述符长度 3 __u8 bDescriptorType; //描述符类型编号 4 5 __le16 bcdUSB; //USB版本号 6 __u8 bDeviceClass; //USB分配的设备类code 7 __u8 bDeviceSubClass; //USB分配的子类code 8 __u8 bDeviceProtocol; //USB分配的协议code 9 __u8 bMaxPacketSize0; //endpoint0最大包大小 10 __le16 idVendor; //厂商编号 11 __le16 idProduct; 12 __le16 bcdDevice; 13 __u8 iManufacturer; 14 __u8 iProduct; 15 __u8 iSerialNumber; 16 __u8 bNumConfigurations; //可能的配置数量 17 } __attribute__ ((packed));
配置描述符(usb_config_descriptor):一个USB设备可以包含一个或多个配置,如USB设备的低功耗模式和高功耗模式可分别对应一个配置。在使用USB设备前,必须为其选择一个合适的配置。配置描述符用于说明USB设备中各个配置的特性,如配置所含接口的个数等。USB设备的每一个配置都必须有一个配置描述符。
1 struct usb_config_descriptor { 2 __u8 bLength; 3 __u8 bDescriptorType; 4 5 __le16 wTotalLength; 6 __u8 bNumInterfaces; 7 __u8 bConfigurationValue; 8 __u8 iConfiguration; 9 __u8 bmAttributes; 10 __u8 bMaxPower; 11 } __attribute__ ((packed));
接口描述符(usb_interface_descriptor):一个配置可以包含一个或多个接口,例如对一个光驱来说,当用于文件传输时,使用其大容量存储接口;而当用于播放CD时,使用其音频接口。接口是端点的集合,可以包含一个或多个可替换设置,用户能够在USB处于配置状态时改变当前接口所含的个数和特性。接口描述符用于说明设备中各个接口的特性,如接口所属的设备类及其子类等。USB设备的每个接口(usb_interface)都必须有一个接口描述符。
1 struct usb_interface_descriptor { 2 __u8 bLength; 3 __u8 bDescriptorType; 4 5 __u8 bInterfaceNumber; 6 __u8 bAlternateSetting; 7 __u8 bNumEndpoints; 8 __u8 bInterfaceClass; 9 __u8 bInterfaceSubClass; 10 __u8 bInterfaceProtocol; 11 __u8 iInterface; 12 } __attribute__ ((packed));
端点描述符(usb_endpoint_descriptor):端点地址、方向、类型以及支持的最大包大小等。端点是USB设备中的实际物理单元,USB数据传输就是在主机和USB设备各个端点之间进行的。端点一般由USB接口芯片提供,例如Freescale公司的MC68HC908JB8和MC9S12UF32。USB设备中的每一个端点都有唯一的端点号,每个端点所支持的数据传输方向一般而言也是确定的:或是输入(IN),或是输出(OUT)。也有些芯片提供的端点的数据方向是可以配置的,例如MC68HC908JB8包含有两个用于数据收发的端点:端点1和端点2。其中端点1只能用于数据发送,即支持输入(IN)操作;端点2既能用于数据发送,也可用于数据接收,即支持输入(IN)和输出(OUT)操作。而MC9S12UF32具有6个端点。利用设备地址、端点号和传输方向就可以指定一个端点,并与它进行通信。端点的传输特性还决定了其与主机通信是所采用的传输类型,例如控制端点只能使用控制传输。根据端点的不同用途,可将端点分为两类:0号端点和非0号端点。0号端点比较特殊,它有数据输入IN和数据输出OUT两个物理单元,且只能支持控制传输。所有的USB设备都必须含有一个0号端点,用作默认控制管道。USB系统软件就是使用该管道与USB逻辑设备进行配置通信的。0号端点在USB设备上的以后就可以使用,而非0号端点必须要在配置以后才可以使用。
1 struct usb_endpoint_descriptor { 2 __u8 bLength; 3 __u8 bDescriptorType; 4 5 __u8 bEndpointAddress; 6 __u8 bmAttributes; 7 __le16 wMaxPacketSize; 8 __u8 bInterval; 9 10 /* NOTE: these two are _only_ in audio endpoints. */ 11 /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ 12 __u8 bRefresh; 13 __u8 bSynchAddress; 14 } __attribute__ ((packed));
第三部分