相关概念
1、USB是主从结构
所有的USB传输都是从USB主机发起,USB设备没有能力“主动”通知USB主机。
例子:USB鼠标滑动一下立刻产生数据,但是它没有能力通知PC机来取数据,只能被动等待PC机来读。
2、USB的传输类型
(1)控制传输:可靠的、时间有保证,比如:USB设备的识别过程
(2)批量传输:可靠、时间没有保证。比如:U盘
(3)中断传输:可靠、实时。比如:USB鼠标
(4)实时传输:不可靠、实时,比如:USB摄像头
3、USB的传输对象:端点(endpoint)
读U盘或写U盘,可以细化为:把数据写到U盘的端点1,从U盘的端点2里读出数据。
除了端点0外,每个端点只支持一个方向的数据传输。
端点0用于控制传输,既能输出也能输入。
4、每个端点都有传输类型,传输方向
5、术语里,程序里说的输入(in)、输出(out)都是基于USB主机的立场来说的。比如鼠标的数据是从鼠标传到PC机,对应的端点称为“输入端点”
6、USB总线驱动程序的作用
(1)识别USB设备
(2)查找并安装对应的的设备驱动程序
(3)只提供USB读写函数,并不了解数据的含义,只有对应的设备驱动程序了解
USB驱动程序框架
应用层
-----------------------------------------------------------------------
USB设备驱动程序(可以有很多个)
内核层 ------------------------------------------------
USB总线驱动程序
-----------------------------------------------------------------------
硬件层 USB主机控制器
USB设备(和USB设备驱动程序一一对应)
其中,USB主机控制器有3种规范:
UHCI: Intel公司规范,低速(1.5Mbps)/高速(12Mbps)
OHCI:微软公司规范,低速/高速
EHCI:高速(480Mbps)
USB总线驱动程序
下面重点分析一下识别USB设备的流程:
1.1 分配地址
1.2 告诉USB设备(set address)
1.3 发出命令获取描述符
描述符的信息可以在include/linux/usb/Ch9.h看到,另外各种描述符的关系如下所示:
一个硬件设备都有一个对应的设备描述符
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations; //配置个数
} __attribute__ ((packed));
一个硬件可能有多个配置,上面结构体中也有显示了配置的个数,所以也有配置描述符
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces; //接口个数
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
每个配置可能有一个或者多个接口,接口是用来描述逻辑上的设备,比如一个USB声卡,硬件上只有一个,但是逻辑上可以分为录音和播放,所以就要有两个接口来描述
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints; //端点个数
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
前面我们说过,USB实际使用端点来传输数据的,所以也应该有端点描述符
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress; //端点地址
__u8 bmAttributes;
__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;
} __attribute__ ((packed));
下面的图可以清晰的表述上面几种描述符的关系:
下面给出大概的USB设备识别的代码流程:
这里涉及到另外一个重要的总线,USB设备总线,和我们之前讲过的另外一个总线(设备、驱动、总线模型简介)类似:
USB_BUS_TYPE
usb_new_device / \usb_register
/ \
usb_interface usb_driver
Linux系统已经为我们搭好了usb_interface的框架,我们只要编写好usb_driver的代码就好了