Linux驱动开发: USB驱动开发
Posted DS小龙哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux驱动开发: USB驱动开发相关的知识,希望对你有一定的参考价值。
一、USB简介
1.1 什么是USB?
USB是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,USB就是简写,中文叫通用串行总线。最早出现在1995年,伴随着奔腾机发展而来。自微软在Windows 98中加入对USB接口的支持后,USB接口才推广开来,USB设备也日渐增多,如数码相机、摄像头、扫描仪、游戏杆、打印机、键盘、鼠标等等,其中应用最广的就是摄像头和U盘了。
USB包括老旧的USB 1.1标准和时下正流行的USB 2.0标准。传统的USB 1.1最高传输速率为12Mbps,一般厂商将其符合USB 1.1标准的产品称为“全速USB”。而高速USB 2.0最初推出时最高传输速率仅为240Mbps,后来USB2.0推广组(USB Promoter Group)在1999年10月将该速率提高到480Mbps,比传统的USB 1.1快40倍。
USB2.0向下兼容USB 1.1,当然USB1.1设备也“向上兼容”USB 2.0,但是无法实现USB2.0的传输能力,并自动以低速传输。USB 2.0连接线的最大长度为5米,但如果用五个USB适配器,则最大长度可达30米。
最新一代是USB 3.1,传输速度为10Gbit/s,三段式电压5V/12V/20V,最大供电100W ,新型Type C插型不再分正反。
USB采用四线电缆,其中两根是用来传送数据的串行通道,另两根为下游(Downstream)设备提供电源,对于高速且需要高带宽的外设,USB以全速12Mbps的传输数据;对于低速外设,USB则以1.5Mbps的传输速率来传输数据。USB总线会根据外设情况在两种传输模式中自动地动态转换。USB是基于令牌的总线。类似于令牌环网络或FDDI基于令牌的总线。USB主控制器广播令牌,总线上设备检测令牌中的地址是否与自身相符,通过接收或发送数据给主机来响应。USB通过支持悬挂/恢复操作来管理USB总线电源。USB系统采用级联星型拓扑,该拓扑由三个基本部分组成:主机(Host),集线器(Hub)和功能设备。
主机,也称为根,根结或根Hub,它做在主板上或作为适配卡安装在计算机上,主机包含有主控制器和根集线器(Root Hub),控制着USB总线上的数据和控制信息的流动,每个USB系统只能有一个根集线器,它连接在主控制器上。
集线器是USB结构中的特定成分,它提供叫做端口(Port)的点将设备连接到USB总线上,同时检测连接在总线上的设备,并为这些设备提供电源管理,负责总线的故障检测和恢复。集线可为总线提供能源,亦可为自身提供能源(从外部得到电源),自身提供能源的设备可插入总线提供能源的集线器中,但总线提供能源的设备不能插入自身提供能源的集线器或支持超过四个的下游端口中,如总线提供能源设备的需要超过100mA电源时,不能同总线提供电源的集线器连接。
USB介绍: http://www.usb.org/home
1.2 USB设备主要优点总结
1. 可以热插拔
用户在使用外接设备时,不需要关机再开机等动作,而是在电脑工作时,直接将USB插上使用。
2. 携带方便
USB设备大多以“小、轻、薄”见长,对用户来说,随身携带大量数据时,很方便。当然USB硬盘是首要之选了。
3. 标准统一
大家常见的是IDE接口的硬盘,串口的鼠标键盘,并口的打印机扫描仪,可是有了USB之后,这些应用外设统统可以用同样的标准与个人电脑连接,这时就有了USB硬盘、USB鼠标、USB打印机等等。
4. 可以连接多个设备
USB在个人电脑上往往具有多个接口,可以同时连接几个设备,如果接上一个有四个端口的USB HUB时,就可以再连上四个USB设备,以此类推 (注:最高可连接至127个设备,扩展到一定数量时需要外加电源)
1.3 USB电器接口定义
一般的排列方式是:红白绿黑从左到右
定义:
- 红色-USB电源: 标有-VCC、Power、5V、5VSB字样
- 白色-USB数据线:(负)-DATA-、USBD-、PD-、USBDT-
- 绿色-USB数据线:(正)-DATA+、USBD+、PD+、USBDT+
- 黑色-地线: GND、Ground
1. 4 USB的插入检测机制
USB端口的D+和D-均用一个15k的电阻接地,当无设备接入时,均处于低电平;在设备端在D+(表示高速设备或者全速设备)或者D-(表示低速设备)接了一个1.5k的上拉电阻到+3.3v,一旦将设备接入,USB端口的D+或者D-其中一个被拉高为3v,系统识别到外部设备接入。
注意:高速设备首先会被识别为全速设备,然后再通过集线器和设备二者的确认最后切换到高速模式下。
在高速模式下,采用的是电流传输模式,这个时候上拉电阻需要从D+上断开。
usb主机检测到USB设备插入后,就要对设备进行枚举了。枚举的作用就是从设备是那个读取一些信息,知道设备是什么样的设备,如果通信,这样主机就可以根据这些信息选择合适的驱动程序。调试USB设备,很重要的一点就是USB枚举过程,只要枚举成功了,那就成功一大半了。
当设备没有枚举成功时(可以通过一个10K的电阻将USB的电源端和D+或者D-连接起来,电脑会发现一个无法识别的设备,这个设备的PID和VID都是0,根据每个特性可以简单的判定设备的枚举是否成功。
二、 USB标准描述符
USB协议为USB设备定义了一套描述设备功能和属性的有固定结构的描述符,包括标准的描述符即设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符。USB设备通过这些描述符向USB主机汇报设备的各种各样属性,主机通过对这些描述符的访问对设备进行类型识别、配置并为其提供相应的客户端驱动程序。
USB设备通过描述符反映自己的设备特性。USB描述符是由特定格式排列的一组数据结构组成。
在USB设备枚举过程中,主机端的协义软件需要解析从USB设备读取的所有描述符信息。在USB主向设备发送读取描述符的请求后,USB设备将所有的描述符以连续的数据流方式传输给USB主机。主机从第一个读到的字符开始,根据双方规定好的数据格式,顺序地解析读到的数据流。
USB描述符包含标准描述符、类描述符和厂商特定描述3种形式。任何一种设备必须遵循USB标准描述符(除了字符串描述符可选外)。
在USB1.X中,规定了5种标准描述符:设备描述符(Device Descriptor)、配置描述符(Configuration Descriptor)、接口描述符(Interface Descriptor)、端点描述符(Endpoint Descriptor)和字符串描述符(String Descriptor)。
每个USB设备只有一个设备描述符,而一个设备中可包含一个或多个配置描述符,即USB设备可以有多种配置。设备的每一个配置中又可以包含一个或多个接口描述符,即USB设备可以支持多种功能(接口),接口的特性通过描述符提供。
在USB主机访问USB设备的描述符时,USB设备依照设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符顺序将所有描述符传给主机。一设备至少要包含设备描述符、配置描述符和接口描述符,如果USB设备没有端点描述符,则它仅仅用默认管道与主机进行数据传输。
2. 1 设备描述符
30.2.1 设备描述符
/* USB_DT_DEVICE: Device descriptor */
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));
//USB设备信息与驱动端匹配成功的时候调用。
static int test_probe(struct usb_interface *intf,const struct usb_device_id *id) //资源探索函数
{
printk("识别到USB光谱仪设备,正在进行设备初始化.\\n");
printk("该设备的厂商ID=%#x,设备ID:%#x\\n",id->idVendor,id->idProduct);
/*通过接口获取设备信息*/
struct usb_device *dev = interface_to_usbdev(intf);
printk("bcdUSB = %#x\\n",dev->descriptor.bcdUSB); //从USB设备描述符中获取USB版本
printk("vidUSB = %#x\\n",dev->descriptor.idVendor); //从USB设备描述符中获取厂商ID
printk("pidUSB = %#x\\n",dev->descriptor.idProduct);//从USB设备描述符中获取产品ID
/*-------------------------------*/
}
设备描述符给出了USB设备的一般信息,包括对设备及在设备配置中起全程作用的信息,包括制造商标识号ID、产品序列号、所属设备类号、默认端点的最大包长度和配置描述符的个数等。一个USB设备必须有且仅有一个设备描述符。设备描述符是设备连接到总线上时USB主机所读取的第一个描述符,它包含了14个字段,结构如下:
USB设备描述符的结构 | ||||
偏移量 | 域 | 大小 | 值 | 描述 |
0 | bLength | 1 | 数字 | 此描述表的字节数 |
1 | bDecriptorType | 1 | 常量 | 描述符的类型(此处应为0x01,即设备描述符) |
2 | bcdUSB | 2 | BCD码 | 此设备与描述表兼容的USB设备说明版本号(BCD 码) |
4 | bDeviceClass | 1 | 类 | 设备类码: 如果此域的值为0则一个设置下每个接口指出它自己的类,各个接口各自独立工作。 |
5 | bDeviceSubClass | 1 | 子类 | 子类码 这些码值的具体含义根据bDeviceClass 域来看。 |
6 | bDevicePortocol | 1 | 协议 | 协议码 这些码的值视bDeviceClass 和 bDeviceSubClass 的值而定。 如果设备支持设备类相关的协议,此码标志了设备类的值。如果此域的值为零,则此设备不支持设备类相关的协议,然而,可能它的接口支持设备类相关的协议。如果此域的值为FFH,此设备使用厂商定义的协议。 |
7 | bMaxPacketSize0 | 1 | 数字 | 端点0的最大包大小(仅8,16,32,64为合法值) |
8 | idVendor | 2 | ID | 厂商标志(由USB-IF组织赋值) |
10 | idProduct | 2 | ID | 产品标志(由厂商赋值) |
12 | bcdDevice | 2 | BCD码 | 设备发行号(BCD 码) |
14 | iManufacturer | 1 | 索引 | 描述厂商信息的字符串描述符的索引值。 |
15 | iProduct | 1 | 索引 | 描述产品信息的字串描述符的索引值。 |
16 | iSerialNumber | 1 | 索引 | 描述设备序列号信息的字串描述符的索引值。 |
17 | bNumConfigurations | 1 | 数字 | 可能的配置描述符数目 |
其中bDescriptorType为描述符的类型,其含义可查下表(此表也适用于标准命令Get_Descriptor中wValue域高字节的取值含义):
USB描述符的类型值 | ||
类型 | 描述符 | 描述符值 |
标准描述符 | 设备描述符(Device Descriptor) | 0x01 |
配置描述符(Configuration Descriptor) | 0x02 | |
字符串描述符(String Descriptor) | 0x03 | |
接口描述符(Interface Descriptor) | 0x04 | |
端点描述符(EndPont Descriptor) | 0x05 | |
类描述符 | 集线器类描述符(Hub Descriptor) | 0x29 |
人机接口类描述符(HID) | 0x21 | |
厂商定义的描述符 | 0xFF |
设备类代码bDeviceClass可查下表:
设备的类别(bDeviceClass) | ||
值(十进制) | 值(十六进制) | 说明 |
0 | 0x00 | 接口描述符中提供类的值 |
2 | 0x02 | 通信类 |
9 | 0x09 | 集线器类 |
220 | 0xDC | 用于诊断用途的设备类 |
224 | 0xE0 | 无线通信设备类 |
255 | 0xFF | 厂商定义的设备类 |
下表列出了一个USB鼠标的设备描述符的例子,供大家分析一下:
一种鼠标的设备描述符示例 | |
字段 | 描述符值(十六制) |
bLength | 0x12 |
bDecriptorType | 0x01 |
bcdUSB | 0x110 |
bDeviceClass | 0x00 |
bDeviceSubClass | 0x00 |
bDevicePortocol | 0x00 |
bMaxPacketSize0 | 0x08 |
idVendor | 0x045E(Microsoft Corporation) |
idProduct | 0x0047 |
bcdDevice | 0x300 |
iManufacturer | 0x01 |
iProduct | 0x03 |
iSerialNumber | 0x00 |
bNumConfigurations | 0x01 |
Linux内核中定义的设备描述符结构:
struct usb_device_descriptor
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型编号
_ _le16 bcdUSB; //USB版本号
_ _u8 bDeviceClass; //USB分配的设备类code
_ _u8 bDeviceSubClass;// USB分配的子类code
_ _u8 bDeviceProtocol; //USB分配的协议code
_ _u8 bMaxPacketSize0; //endpoint0最大包大小
_ _le16 idVendor; //厂商编号
_ _le16 idProduct; //产品编号
_ _le16 bcdDevice; //设备出厂编号
_ _u8 iManufacturer; //描述厂商字符串的索引
_ _u8 iProduct; //描述产品字符串的索引
_ _u8 iSerialNumber; //描述设备序列号字符串的索引
_ _u8 bNumConfigurations; //可能的配置数量
} _ _attribute_ _ ((packed));
2.2 配置描述符
配置描述符中包括了描述符的长度(属于此描述符的所有接口描述符和端点描述符的长度的和)、供电方式(自供电/总线供电)、最大耗电量等。主果主机发出USB标准命令Get_Descriptor要求得到设备的某个配置描述符,那么除了此配置描述符以外,此配置包含的所有接口描述符与端点描述符都将提供给USB主机。
USB配置描述符的结构 | ||||
偏移量 | 域 | 大小 | 值 | 描述 |
0 | bLength | 1 | 数字 | 此描述表的字节数长度。 |
1 | bDescriptorType | 1 | 常量 | 配置描述表类型(此处为0x02) |
2 | wTotalLength | 2 | 数字 | 此配置信息的总长(包括配置,接口,端点和设备类及厂商定义的描述符) |
4 | bNumInterfaces | 1 | 数字 | 此配置所支持的接口个数 |
5 | bCongfigurationValue | 1 | 数字 | 在SetConfiguration()请求中用作参数来选定此配置。 |
6 | iConfiguration | 1 | 索引 | 描述此配置的字串描述表索引 |
7 | bmAttributes | 1 | 位图 | 配置特性: D7: 保留(设为一) |
8 | MaxPower | 1 | mA | 在此配置下的总线电源耗费量。以 2mA 为一个单位。 |
下面是一种硬盘的配置描述符示例:
一种硬盘的配置描述符示例 | |
字段 | 描述符值(十六进制) |
bLength | 0x09 |
bDescriptorType | 0x02 |
wTotalLength | 0x01F |
bNumInterfaces | 0x01 |
bCongfigurationValue | 0x01 |
iConfiguration | 0x00 |
bmAttributes | 0x0C |
MaxPower | 0x32 |
Linux内核中定义的配置描述符结构
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型编号
_ _le16 wTotalLength; //配置所返回的所有数据的大小
_ _u8 bNumInterfaces; // 配置所支持的接口数
_ _u8 bConfigurationValue; //Set_Configuration命令需要的参数值
_ _u8 iConfiguration; //描述该配置的字符串的索引值
_ _u8 bmAttributes; //供电模式的选择
_ _u8 bMaxPower; //设备从总线提取的最大电流
} _ _attribute_ _ ((packed));
2.3 接口描述符
配置描述符中包含了一个或多个接口描述符,这里的“接口”并不是指物理存在的接口,在这里把它称之为“功能”更易理解些,例如一个设备既有录音的功能又有扬声器的功能,则这个设备至少就有两个“接口”。
如果一个配置描述符不止支持一个接口描述符,并且每个接口描述符都有一个或多个端点描述符,那么在响应USB主机的配置描述符命令时,USB设备的端点描述符总是紧跟着相关的接口描述符后面,作为配置描述符的一部分被返回。接口描述符不可直接用Set_Descriptor和Get_Descriptor来存取。
如果一个接口仅使用端点0,则接口描述符以后就不再返回端点描述符,并且此接口表现的是一个控制接口的特性,它使用与端点0相关联的默认管道进行数据传输。在这种情况下bNumberEndpoints域应被设置成0。接口描述符在说明端点个数并不把端点0计算在内。
USB接口描述符的结构 | ||||
偏移量 | 域 | 大小 | 值 | 说明 |
0 | bLength | 1 | 数字 | 此表的字节数 |
1 | bDescriptorType | 1 | 常量 | 接口描述表类(此处应为0x04) |
2 | bInterfaceNumber | 1 | 数字 | 接口号,当前配置支持的接口数组索引(从零开始)。 |
3 | bAlternateSetting | 1 | 数字 | 可选设置的索引值。 |
4 | bNumEndpoints | 1 | 数字 | 此接口用的端点数量,如果是零则说明此接口只用缺省控制管道。 |
5 | bInterfaceClass | 1 | 类 | 接口所属的类值: 零值为将来的标准保留。 如果此域的值设为FFH,则此接口类由厂商说明。 所有其它的值由USB 说明保留。 |
6 | bInterfaceSubClass | 1 | 子类 | 子类:这些值的定义视bInterfaceClass域而定。 如果bInterfaceClass域的值为零则此域的值必须为零。 bInterfaceClass域不为FFH则所有值由USB 所保留。 |
7 | bInterfaceProtocol | 1 | 协议 | 协议码:bInterfaceClass 和bInterfaceSubClass 域的值而定.如果一个接口支持设备类相关的请求此域的值指出了设备类说明中所定义的协议. |
8 | iInterface | 1 | 索引 | 描述此接口的字串描述表的索引值。 |
对于bInterfaceClass字段,表示接口所属的类别,USB协议根据功能将不同的接口划分成不的类,其具体含义如下表所示:
USB协议定义的接口类别(bInterfaceClass) | |
值(十六进制) | 类别 |
0x01 | 音频类 |
0x02 | CDC控制类 |
0x03 | 人机接口类(HID) |
0x05 | 物理类 |
0x06 | 图像类 |
0x07 | 打印机类 |
0x08 | 大数据存储类 |
0x09 | 集线器类 |
0x0A | CDC数据类 |
0x0B | 智能卡类 |
0x0D | 安全类 |
0xDC | 诊断设备类 |
0xE0 | 无线控制器类 |
0xFE | 特定应用类(包括红外的桥接器等) |
0xFF | 厂商定义的设备 |
Linux内核中定义的接口描述符结构
struct usb_interface_descriptor
{
_ _u8 bLength; //描述符长度
_ _u8 bDescriptorType; //描述符类型
_ _u8 bInterfaceNumber; // 接口的编号
_ _u8 bAlternateSetting; //备用的接口描述符编号
_ _u8 bNumEndpoints; //该接口使用的端点数,不包括端点0
_ _u8 bInterfaceClass; //接口类型
_ _u8 bInterfaceSubClass; //接口子类型
_ _u8 bInterfaceProtocol; //接口所遵循的协议
_ _u8 iInterface; //描述该接口的字符串索引值
} _ _attribute_ _ ((packed));
2.4 端点描述符
端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点0(控制端点,一般一个设备只有一个控制端点)为双向端口外,其它均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小和端点号(也可称为端点地址)等。
以上是关于Linux驱动开发: USB驱动开发的主要内容,如果未能解决你的问题,请参考以下文章
Linux 下wifi 驱动开发—— USB接口WiFi驱动浅析