linux驱动移植-USB驱动基础
一、USB总线介绍
1.1 简介
我们之前接触过的通信协议有串口、I2C、SPI以及CAN总线,这里我们又去学习USB总线,那USB和之前我们介绍过那些总线有什么区别呢。
通用串行总线(英语:Universal Serial Bus,缩写:USB)是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,并扩展至摄影器材、数字电视(机顶盒)、游戏机等其它相关领域。
在USB总线出现之前,计算机与键盘、鼠标、扫描仪、打印机等的设备连接都使用专用的接口连接,不同的设备的接口不能互用,扩展性很差,每次插拔设备都要关闭计算机,不支持热插拔,且通信速率很低。
为了解决上述问题,USB总线诞生了。USB总线就好像一条管道,管道里流过的东西只要符合USB协议,至于具体流的是什么东西,USB总线并不关心。对应具体的设备上,只要是支持USB协议的设备,都可以连接计算机,如USB键盘、USB鼠标、USB摄像头、USB音箱等。USB的出现简化了计算机与外围设备的连接,增强了扩展性,支持热插拔,且通信速度很快。
1.2 USB协议版本
从USB协议诞生至今,出现了多个USB协议版本,如USB1.0、USB1.1、USB2.0、USB3.0、USB3.1、USB3.2。最新的是USB4.0协议,可直连CPU的PCIe总线,最大速度可达40Gbps,使用Type-C接口,兼容DP视频协议、PD快充协议等,最高支持100W供电。
USB协议版本 | 速率称号 | 最大速率 | 电源 | 类型 | 推出时间 |
---|---|---|---|---|---|
USB1.0 | 低速(Low-Speed) | 1.5Mbps | 5V/500mA | 半双工 | 1996年1月 |
USB1.1 | 全速(Full-Speed) | 12Mbps | 5V/500mA | 半双工 | 1998年9月 |
USB2.0 | 高速(High-Speed) | 480Mbps | 5V/500mA | 半双工 | 2000年4月 |
USB3.0(USB3.2 Gen1) | 超高速(SuperSpeed USB) | 5Gbps | 5V/900mA | 全双工 | 2008年月11月 |
USB3.1(USB3.2 Gen2) | SuperSpeed USB 10Gbps | 10Gbps | 20V/5A | 全双工 | 2013年月7月 |
USB3.2(USB3.2 Gen2×2) | SuperSpeed USB 20Gps | 20Gbps | 20V/5A | dual-lane | 2017年月9月 |
USB4.0(Gen3×2) | ---- | 40Gbps | 100瓦 | single-lane或dual-lane,兼容Thunderbolt3 | 2019年月8月 |
注:USB3.2推出时,USB-IF公布了新的命名规范,将USB3.0改名为USB3.2 Gen1,USB3.1改名为USB3.2 Gen2,而将能够使用两个USB Type-C Rx/Tx针脚的USB3.2改名为USB3.2 Gen2×2。
下图是各个版本USB协议使用的标志及接口,USB3.2以后,只使用Type-C接口,包括图中未画出的USB4.0和Thunderbolt3。
伴随着USB的版本迭代,USB又产生了多种连接器类型规范,比如Type A、Type B、Type-C。
下图是USB3.2协议使用的标志,此标志是USB-IF网站上最新的。
下图是USB4.0协议使用的标志,USB4.0使用Gen3 lane,single-lane可达到20Gps,dual-lane为40Gps。USB4™ 20Gbps使用single-lane,USB4™ 40Gbps使用dual-lane。
二、USB总线特点
2.1 主从模式
USB是主从模式的总线,主机称为Host,丛机称为Device(设备)。从机与从机之间、主机与主机之间(不包括USB4.0),不能互联。每次通信都是由主机发起,从机不能主动发起通信,只能被动的应答主机的请求。
USB3.0及以后的USB协议,主机也可以和集线器(Hub)通信。为了增加灵活性,又出现了USB OTG(On The Go),USB OTG支持主从切换,同一个设备,在不同场合下,可以在主机和从机之间切换。
USB OTG线中增加了一根USB ID线,当USB ID线上拉时,处于从机模式,当USB ID线接地时,处于主机模式。
2.2 总线结构
在有些场景下,我们期望将一个USB接口扩展为多个USB接口,这时我们就会使用到一个装置,也就是USB Hub,如下图所示:
因此,USB总线可能呈现出树状的拓扑接口吗,USB标准上说USB总线拓扑是一种分层星型结构,如下图所示:
从树结构我们可以看到:
- 树的根节点是USB Host控制器(上图没有画出来),连接在USB Host控制器上的是USB根集线器(Root Hub);
- USB集线器(Hub)可以将一个USB接口扩展成多个USB接口,扩展出的USB接口又可以通过USB集线器(Hub)扩展,每个USB接口都可以接USB设备;
- 集线器只能扩展出更多的USB接口,而不能扩展出更多的带宽,所有USB设备共享USB Host控制器的带宽,当有多个USB设备需要较大带宽时,可以考虑将他们接到不同USB Host控制器上的根集线器上,以避免带宽不足;
- 集线器级联最多5层,因此最大为7层星型结构;这个最大7层星形结构,代表的是一条USB总线,一个USB分层星型结构有且仅有一个USB主机控制器,但并不是说一台计算机就只有一个USB总线;
比如我的计算机内部就是1个USB主控制器+Root Hub,从Windows设备管理器可以看到,下图是其中一条USB总线:
2.3 电气特性
下图是USB3.2线缆的示意图,同时兼容USB2.0:
USB使用差分信号传输数据,图中的D+和D-是一对差分线,SSTX+和SSTX-是一对差分线,SSRX+和SSRX-是一对差分线:
- USB2.0只有一对差分线,即下图中的D+、D-,因此USB2.0是半双工的,不能同时收发数据;
- USB3.2拥有两对差分线,即SSTX+和SSTX-及SSRX+和SSRX-,因此USB3.2是全双工的,可同时收发数据;
USB3.2和USB2.0使用不同的差分线传输数据,两者互不干扰,可同时工作。USB3.2线缆中保留了USB2.0的数据传输通道,实现了对USB2.0的兼容。USB主机可通过$V_{BUS}$线向设备供电,最大可输出20V/5A,GND是地线。
2.4 热插拔
当一个USB设备插入PC机,PC机怎么知道有设备插入?
如下图所示,USB2.0接口只有4条线:$V_{BUS}$(5V),GND,D-,D+。
USB低速设备硬件接线图
USB全速(高速)设备硬件接线图
注意:上图中VCC同$V_{BUS}$。
PC机的USB插孔的D-和D+数据线均连接15K欧姆的下拉电阻。而USB设备端的D-或D+数据线连接1.5K欧姆的上拉电阻。当设备插入PC机的时候,会将PC机的D-或D+端的电压拉高,当PC机在D-或D+端检测到高电平时,就知道有设备插入了。
如果是PC机D-端被拉高,接入的则是USB低速设备;如果是PC机D+端被拉高,接入的则是USB全速或高速设备,具体是全速设备还是高速设备,会由PC机和USB设备发包握手确定。
三、USB传输基础
3.1 传输类型
USB架构包含四种基本类型的数据传输:
- 控制传输:控制传输用于配置设备、获取设备信息、发送命令到设备、获取设备的状态。每个USB设备都有端点0的控制端点,当USB设备插入到USB主机拓扑网络中时,USB主机就通过端点0与USB设备通信,对USB设备进行配置,便于后续的数据传输。USB协议保证控制传输有足够的带宽。控制传输可靠,时间有保证,但传输的数据量不大。如USB设备的枚举过程就采用的是控制传输;
- 中断传输:当USB主机请求USB设备传输数据时,中断传输以一个固定的速率传送少量的数据。中断端点的数据传输方式为中断传输,数据传输可靠,实时性高,这里的中断并不是USB设备产生中断,而是USB主机每隔一个固定的时间主动查询USB设备是否有数据要传输,以轮询的方式提高实时性。如USB鼠标采用的是中断传输;
- 批量传输:批量传输用于传输大量数据。USB协议不保证这些数据传输可以在特定的时间内完成,但保证数据的准确性。如果总线上的带宽不足以发送整个批量包,则将数据拆分为多个包传输。批量传输数据可靠,但实时性较低。如USB硬盘、打印机等设备就采用的是批量传输方式;
- 等时传输:等时传输也可以传输大量数据,但数据的可靠性无法保证。采用等时传输的USB设备更加注重保持一个恒定的数据传输速度,对数据的可靠性要求不高。如USB摄像头就使用的是等时传输方式;
下表是这四类传输在不同速度模式下支持的最大包长度:
速度模式 | 低速 | 全速 | 高速 |
控制传输 | 8 | 8/16/32/64 | 64 |
同步传输 | 不支持 | 1023 | 1024 |
中断传输 | 0~8 | 0~64 | 0~1024 |
批量传输 | 不支持 | 8/16/32/64 | 512 |
3.2 传输要素
USB2.0主机控制器通过把时间在低速、全速模式下分成1毫秒宽的帧(frame),在高速模式下分成125微妙宽的微帧(microfranme),以此来管理传输。主机控制器将每个帧或微帧的一部分分配给各个传输。每个帧(或微帧)以带有时序参考的帧(Start-of-Frame,SOF)开始。超高速总线不使用SOF,但主机控制器仍可以在125微妙的总线时间内安排超高速传输。
USB传输可以安排在1个或多个帧或微帧中,每个传输包含多个事务,每个事务又进一步含有多个信息包(packets)。信息包必须在一个帧或微帧中传输完毕,不能跨帧或微帧。信息包分为4类,令牌类信息包确认事务类型,数据类信息包携带数据和状态代码,握手类信息包携带状态代码,最后一种是特殊类信息包。
USB传输由一个或多个事务(transaction)组成,这些事务可将数据载入端点或从端点取出。USB2.0事务开始于主机在总线上发送的令牌信息包(token packet)。令牌信息包含有目标端点号和方向。IN令牌信息包表示向端点请求数据信息包。OUT令牌信息包则是主机派发数据信息包的先行信息。除了数据,每个数据包还含有错误检查位和一个带有数据顺序值的信息包ID(PID)。许多事务还拥有握手信息包(handshake packet),数据的接收端用它来报告事务成功或失败。对于超高速传输事务,信息包类型和协议有所不同,但却含有相同的地址、错误检查和与数据相配合的数据顺序值。
信息包类型 | PID名字 | 取值(二进制) | 传输类型 | 来源 | 说明 |
---|---|---|---|---|---|
令牌 | OUT | 0001 | 全部 | 主机 | IN事务中需要的设备和端点地址 |
令牌 | IN | 1001 | 全部 | 主机 | IN事务中需要的设备和端点地址 |
令牌 | SOF | 0101 | 帧开始 | 主机 | SOF标识符和帧号 |
令牌 | SETUP | 1101 | 控制 | 主机 | 用于Setup事务的设备和端点地址 |
数据 | DATA0 | 0011 | 全部 | 主机、设备 | 数据交替或数据PID序列 |
数据 | DATA1 | 1011 | 全部 | 主机、设备 | 数据交替或数据PID序列 |
数据 | DATA2 | 0111 | 等时 | 主机、设备 | 数据PID序列 |
数据 | MDATA | 1111 | 等时、分割事务 | 主机、设备 | 数据PID序列 |
握手 | ACK | 0010 | 控制、批量、中断 | 主机、设备 | 接收端接收到正确的数据信息包 |
握手 | NAK | 1010 | 控制、批量、中断 | 设备 | 接收端不能接收数据,或者发送端无法发送数据或无数据要发送 |
握手 | STALL | 1110 | 控制、批量、中断 | 设备 | 控制请求不被支持或端点被停止 |
握手 | NYET | 0110 | 控制写、批量、OUT、分割事务 | 设备 | 正确的接收了数据信息包,但还没准备好接收下一个,或集线器还没有将数据信息包分割完成 |
特殊 | PRE | 1100 | 控制、中断 | 主机 | 主机发出的先行信号 |
特殊 | ERR | 1100 | 全部 | 集线器 | 由集线器返回的错误 |
特殊 | SPLIT | 1000 | 全部 | 主机 | 分割事务 |
特殊 | PING | 0100 | 控制写、批量、OUT | 主机 | PING测试 |
特殊 | EXT | 0000 | 无 | 主机 | 扩展,未使用 |
更多细节参考:USB协议详解。
四、USB驱动分析
4.1 驱动分类
USB的驱动可以分为3类:
- USB主机控制器驱动,主要包括:
- usb主机控制器驱动的创建;
- 根hub设备的创建和注册;
- 主机端USB设备驱动(更准确的说是usb接口驱动);
- 设备端USB Gadget驱动(专业术语,用于描述连接到计算机的USB的设备的驱动);
通常,对于USB这种标准化的设备,内核已经将USB主机控制器驱动编写好了,设备端Gadget驱动通常只运行固件程序而不是基于Linux, 所以驱动工程师的主要工作就是编写主机端USB设备驱动。
4.2 USB驱动框架
USB驱动框架结构图如下:
USB总线驱动程序包括USB Core和USB HCD两部分,其作用如下:
- 识别USB设备:
- 分配地址;
- 并告诉USB设备;
- 发出命令获取描述符;
- 查找并安装对应的USB设备驱动程序(更准确的说是usb接口驱动);;
- 提供USB读写函数;
USB总线上的所有通信都是由主机发起的,所以本质上,USB都是采用轮询的方式进行的:
- 主机会使用轮询的方式不断检测总线上是否有设备接入,如果有设备接入相应的D+、D-就会有电平变化;
- 然后USB总线就会按照USB规定的协议与设备进行通信,设备将存储在自身的设备信息依次交给主机;
- 主机将这些信息组织起来,上报到内核,内核中的USB子系统再去匹配相应的设备驱动;
上面所说的主机具体指的是USB主机控制器。
4.3 USB Core
USB Core这个模块是纯软件部分,并不代表一个设备,是独立于硬件的协议栈,它是所有USB设备赖以生存的模块,即USB子系统的核心。代码位于kernel/driver/usb/core目录下。
USB核心层向上为USB设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口,维护整个系统的USB设备信息,完成设备热插拔控制、总线数据传输控制等。
USB核心层将用户的请求映射到相关的USB HCD,用户不能直接访问USB HCD,USB核心层就是USB HCD和USB设备的桥梁。
4.4 USB HCD(Host Controller Driver)
硬件主机控制器HOST Contrller之上运行的是USB HCD,是对USB主机控制器的一个抽象,实现USB核心层与主机控制器之间的对话接口。代码位于drivers/usb/host目录下,比如ohci-s3c2410.c文件。
USB主机控制器包含多种不同的类型,即OHCI和UHCI,EHCI,和xHCI,不同类型的USB主机控制器的区别和联系如下:
4.5 USB Devices Driver
USB设备驱动框架如下图所示:
为了更好地描述USB设备的特征,USB提出了设备架构的概念。从这个角度来看,可以认为USB设备是由一些配置(configuration)、接口(interface)和端点(endpoint)组成,即一个USB设备可以含有一个或多个配置,在每个配置中可含有一个或多个接口,在每个接口中可含有若干个端点。其中:
- 配置和接口是对USB设备功能的抽象;
- 实际的数据传输由端点来完成;
- 每个USB设备,都可能有多个接口,每个接口都实现了一个功能。在linux,每个USB设备都是一个device(具体是struct usb_device)、每一个接口也是一个device(具体是struct usb_interface,代表一个逻辑上的设备)。不管是USB设备还是USB接口,都会被注册到同一个总线上,也就是usb_bus_type,其之间的区别会在match函数中区分,之后再去绑定不同的driver。
- 所有的USB设备都会和usb_generic_driver设备驱动匹配,当一个USB设备被插入的时候,USB设备驱动,也就是usb_generic_driver会跟USB设备交互,得到其所有的各种描述符,并为每个接口都定义成为一个device,之后再加载到usb_bus上,让其去匹配其对应的接口驱动程序。
任何USB设备都包含设备描述符,主要用与说明设备树形(设备描述符,配置描述符,接口描述符,端点描述符之间的关系),通常都被固话在设备内部,当主机检测到有设备插入的时候,就会通过控制传输模式将设备描述信息读出来,这个步骤一般是在设备接入主机时设备进行枚举时完成的。
4.6 USB设备地址和端点
每个USB设备都有唯一的设备地址,比如root hub的设备地址为1,设备地址是usb设备连接上主机时由usb主机控制器分配的,usb主机控制器主要依靠这个设备地址对usb设备进行访问。
但是在usb设备内部地址会被分的更细,设备会分出一些端点来,每个端点在设备都会有一个端点号,这个端点号是设备生产时给设定的。如端点0、端点1等,一个usb设备最多可以包含16个端点,每个端点的地址为0~15。
其中每个端点地址对应一个方向。例如端点3-IN,端点3-OUT,这另个含义不同。但是需要注意的是有一个特殊端点-端点0,每个usb必须要有一个端点0,其作用为对设备枚举和对设备进行一些基本的控制功能,端点0也被称作控制端点,并且它与其他的端点还有一个不同之处在于端点0的数据传输方向是双向的,即端点0既可以给主机发送数据,也可以接收主机发送过来的数据,而其他端点都是单向的。
虽然有16个端点,单通常我们只用到3个如下:
- EP0:传输配置和控制信息;
- EP1:数据输入IN_EP;
- EP2:数据输出OUT_EP;
除了端点0,其余的端点在设备配置之前不能与主机通信,只有向主机报告这些端点的特性并确认后才能被激活。
五、USB设备驱动架构中的描述符
USB设备使用各种描述符来说明其设备架构,包括设备描述符、配置描述符、接口描述符、端点描述符。
5.1 端点
USB通信最基本的形式是通过端点的东西。USB端点只能往一个方向传送数据,从主机到设备(称为输出端点out)或者从设备到主机(称为输入端点in),端点可以看作是单向的管道。
USB端点有四种不同的类型,分别具有不同的传送数据的方式:对应着我们之前介绍的四种基本类型的数据传输:控制、中断、批量、等时。
内核中使用struct usb_host_endpoint结构体来描述USB端点,其定义在include/linux/usb.h:
/** * struct usb_host_endpoint - host-side endpoint descriptor and queue * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder * @ss_ep_comp: SuperSpeed companion descriptor for this endpoint * @ssp_isoc_ep_comp: SuperSpeedPlus isoc companion descriptor for this endpoint * @urb_list: urbs queued to this endpoint; maintained by usbcore * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH) * with one or more transfer descriptors (TDs) per urb * @ep_dev: ep_device for sysfs info * @extra: descriptors following this endpoint in the configuration * @extralen: how many bytes of "extra" are valid * @enabled: URBs may be submitted to this endpoint * @streams: number of USB-3 streams allocated on the endpoint * * USB requests are always queued to a given endpoint, identified by a * descriptor within an active interface in a given USB configuration. */ struct usb_host_endpoint { struct usb_endpoint_descriptor desc; struct usb_ss_ep_comp_descriptor ss_ep_comp; struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp; struct list_head urb_list; void *hcpriv; struct ep_device *ep_dev; /* For sysfs info */ unsigned char *extra; /* Extra descriptors */ int extralen; int enabled; int streams; };
其中部分参数含义如下:
- desc:端点描述符;
- ss_ep_comp:超快速端点描述符;
- urb_list:本端口对应的urb链表;
- enabled:使能的话urb才能被提交到此端口;
usb_host_endpoint 结构体在另一个名为struct usb_endpoint_descriptor的结构体中包含真正的端点信息,其定义在include/uapi/linux/usb/ch9.h:
/* USB_DT_ENDPOINT: Endpoint descriptor */ 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));
其中部分参数含义如下:
- bLength:描述符长度;
- bDescriptorType:描述符类型, 端点描述符类型值是5;
- bEndpointAddress:端点地址:位[3:0]表示端点号,第7位是方向:0位输出、1为输入;
- bmAttributes:端点属性:位[1:0]值00表示控制、01表示等时、10表示批量、11表示中断;
- wMaxPacketSize:本端点接受或发送的最大信息包的大小;
- bInterval:轮询数据传输端点的时间间隔,用在中断传输上,比如间隔时间查询鼠标的数据;
5.2 接口
USB端口被捆绑为接口,USB接口只处理一种USB逻辑,一个USB接口代表一个逻辑上的设备,比如声卡驱动,就有两个接口:录音接口和播放接口。
内核使用struct usb_interface结构体来描述USB接口。USB核心把该结构体传递给USB设备驱动程序,之后由USB设备驱动程序来负责控制该结构体,该结构定义在include/linux/usb.h:
/** * struct usb_interface - what usb device drivers talk to * @altsetting: array of interface structures, one for each alternate * setting that may be selected. Each one includes a set of * endpoint configurations. They will be in no particular order. * @cur_altsetting: the current altsetting. * @num_altsetting: number of altsettings defined. * @intf_assoc: interface association descriptor * @minor: the minor number assigned to this interface, if this * interface is bound to a driver that uses the USB major number. * If this interface does not use the USB major, this field should * be unused. The driver should set this value in the probe() * function of the driver, after it has been assigned a minor * number from the USB core by calling usb_register_dev(). * @condition: binding state of the interface: not bound, binding * (in probe()), bound to a driver, or unbinding (in disconnect()) * @sysfs_files_created: sysfs attributes exist * @ep_devs_created: endpoint child pseudo-devices exist * @unregistering: flag set when the interface is being unregistered * @needs_remote_wakeup: flag set when the driver requires remote-wakeup * capability during autosuspend. * @needs_altsetting0: flag set when a set-interface request for altsetting 0 * has been deferred. * @needs_binding: flag set when the driver should be re-probed or unbound * following a reset or suspend operation it doesn't support. * @authorized: This allows to (de)authorize individual interfaces instead * a whole device in contrast to the device authorization. * @dev: driver model's view of this device * @usb_dev: if an interface is bound to the USB major, this will point * to the sysfs representation for that device. * @reset_ws: Used for scheduling resets from atomic context. * @resetting_device: USB core reset the device, so use alt setting 0 as * current; needs bandwidth alloc after reset. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding * an audio stream to a speaker or reporting a change in a volume control. * Many USB devices only have one interface. The protocol used to talk to * an interface's endpoints can be defined in a usb "class" specification, * or by a product's vendor. The (default) control endpoint is part of * every interface, but is never listed among the interface's descriptors. * * The driver that is bound to the interface can use standard driver model * calls such as dev_get_drvdata() on the dev member of this structure. * * Each interface may have alternate settings. The initial configuration * of a device sets altsetting 0, but the device driver can change * that setting using usb_set_interface(). Alternate settings are often * used to control the use of periodic endpoints, such as by having * different endpoints use different amounts of reserved USB bandwidth. * All standards-conformant USB devices that use isochronous endpoints * will use them in non-default settings. * * The USB specification says that alternate setting numbers must run from * 0 to one less than the total number of alternate settings. But some * devices manage to mess this up, and the structures aren't necessarily * stored in numerical order anyhow. Use usb_altnum_to_altsetting() to * look up an alternate setting in the altsetting array based on its number. */ struct usb_interface { /* array of alternate settings for this interface, * stored in no particular order */ struct usb_host_interface *altsetting; struct usb_host_interface *cur_altsetting; /* the currently * active alternate setting */ unsigned num_altsetting; /* number of alternate settings */ /* If there is an interface association descriptor then it will list * the associated interfaces */ struct usb_interface_assoc_descriptor *intf_assoc; int minor; /* minor number this interface is * bound to */ enum usb_interface_condition condition; /* state of binding */ unsigned sysfs_files_created:1; /* the sysfs attributes exist */ unsigned ep_devs_created:1; /* endpoint "devices" exist */ unsigned unregistering:1; /* unregistration is in progress */ unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ unsigned needs_binding:1; /* needs delayed unbind/rebind */ unsigned resetting_device:1; /* true: bandwidth alloc after reset */ unsigned authorized:1; /* used for interface authorization */ struct device dev; /* interface specific device info */ struct device *usb_dev; struct work_struct reset_ws; /* for resets in atomic context */ };
其中部分参数含义如下:
- altsetting:包含所有可用于该接口的可选设置的接口结构数组。每个 struct usb_host_interface 包含一套端点配置,即struct usb_host_endpoint结构所定义的端点配置。这些接口结构没有特别的顺序;
- cur_altsetting: 指向altsetting内部的指针,表示当前激活的接口配置;
- num_altsetting:可选设置的数量;
- minor:如果绑定到这个接口的 USB 驱动使用USB主设备号, 这个变量包含由USB核心分配给接口的次设备号. 这只在一个成功的调用 usb_register_dev后才有效;
其中usb_host_interface 结构定义如下:
/* host-side wrapper for one interface setting's parsed descriptors */ struct usb_host_interface { struct usb_interface_descriptor desc; int extralen; unsigned char *extra; /* Extra descriptors */ /* array of desc.bNumEndpoints endpoints associated with this * interface setting. these will be in no particular order. */ struct usb_host_endpoint *endpoint; char *string; /* iInterface string, if present */ };
可以看到该结构成员包含了:
- desc:接口描述符;
- endpoint:这个接口包含的所有端点;
- extra:额外的描述符;
我们重点看一下接口描述符usb_interface_descriptor ,其定义在include/uapi/linux/usb/ch9.h:
/* USB_DT_INTERFACE: Interface descriptor */ struct usb_interface_descriptor { __u8 bLength; __u8 bDescriptorType; __u8 bInterfaceNumber; __u8 bAlternateSetting; __u8 bNumEndpoints; __u8 bInterfaceClass; __u8 bInterfaceSubClass; __u8 bInterfaceProtocol; __u8 iInterface; } __attribute__ ((packed));
其中部分参数含义如下:
- bLength:描述符长度;
- bDescriptorType:描述符类型,接口描述符类型值是4;
- bInterfaceNumber:接口的编号,相同的编号代表相同的功能接口;
- bAlternateSetting:接口的设置的编号,同一个接口可以有一个或者多个设置代表该接口下不同的参数;
- bNumEndpoints:要使用的端点个数(不包括端点0), 表示有多少个端点描述符,比如鼠标就只有一个端点;
- bInterfaceClass:接口类型;
- bInterfaceSubClass:接口子类型;
- bInterfaceProtocol:接口所遵循的协议;
- iInterface:描述该接口的字符串索引值;
5.3 配置
USB接口被捆绑为配置。一个USB设备可以有多个配置,而且可以在配置之间切换以改变设备的状态。例如,一些允许下载固件到其上的设备包含多个配置以完成这个工作,而一个时刻只能激活一个配置。
内核使用usb_host_config来描述USB设备的配置,定义在include/linux/usb.h:
/** * struct usb_host_config - representation of a device's configuration * @desc: the device's configuration descriptor. * @string: pointer to the cached version of the iConfiguration string, if * present for this configuration. * @intf_assoc: list of any interface association descriptors in this config * @interface: array of pointers to usb_interface structures, one for each * interface in the configuration. The number of interfaces is stored * in desc.bNumInterfaces. These pointers are valid only while the * the configuration is active. * @intf_cache: array of pointers to usb_interface_cache structures, one * for each interface in the configuration. These structures exist * for the entire life of the device. * @extra: pointer to buffer containing all extra descriptors associated * with this configuration (those preceding the first interface * descriptor). * @extralen: length of the extra descriptors buffer. * * USB devices may have multiple configurations, but only one can be active * at any time. Each encapsulates a different operational environment; * for example, a dual-speed device would have separate configurations for * full-speed and high-speed operation. The number of configurations * available is stored in the device descriptor as bNumConfigurations. * * A configuration can contain multiple interfaces. Each corresponds to * a different function of the USB device, and all are available whenever * the configuration is active. The USB standard says that interfaces * are supposed to be numbered from 0 to desc.bNumInterfaces-1, but a lot * of devices get this wrong. In addition, the interface array is not * guaranteed to be sorted in numerical order. Use usb_ifnum_to_if() to * look up an interface entry based on its number. * * Device drivers should not attempt to activate configurations. The choice * of which configuration to install is a policy decision based on such * considerations as available power, functionality provided, and the user's * desires (expressed through userspace tools). However, drivers can call * usb_reset_configuration() to reinitialize the current configuration and * all its interfaces. */ struct usb_host_config { struct usb_config_descriptor desc; char *string; /* iConfiguration string, if present */ /* List of any Interface Association Descriptors in this * configuration. */ struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS]; /* the interfaces associated with this configuration, * stored in no particular order */ struct usb_interface *interface[USB_MAXINTERFACES]; /* Interface information available even when this is not the * active configuration */ struct usb_interface_cache *intf_cache[USB_MAXINTERFACES]; unsigned char *extra; /* Extra descriptors */ int extralen; };
其中部分参数含义如下:
- desc:配置描述符;
- interface:这个配置包含的所有接口;
- extra:额外的描述符;
其中struct usb_config_descriptor 结构体定义在include/uapi/linux/usb/ch9.h:
/* USB_DT_CONFIG: Configuration descriptor information. * * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the * descriptor type is different. Highspeed-capable devices can look * different depending on what speed they're currently running. Only * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG * descriptors. */ struct usb_config_descriptor { __u8 bLength; __u8 bDescriptorType; __le16 wTotalLength; __u8 bNumInterfaces; __u8 bConfigurationValue; __u8 iConfiguration; __u8 bmAttributes; __u8 bMaxPower; } __attribute__ ((packed));
其中部分参数含义如下:
- bLength:描述符长度;
- bDescriptorType:描述符类型,配置描述符类型值是2;
- wTotalLength:配置下面所有描述符的长度,包括这个配置描述符;
- bNumInterfaces:配置所支持的接口数;
- bConfigurationValue:配置值,实际上存的就是当前配置在usb_device->config数组中的索引;
- iConfiguration:描述该配置的字符串的索引值;
- bmAttributes:供电模式的选择;
- bMaxPower:设备从总线提取的最大电流;
5.4 设备
一个设备里包含了不同级别的配置,可以有一个或者多个配置。在linux中,结构体usb_device 对应着USB设备,定义在include/linux/usb.h:
/** * struct usb_device - kernel's representation of a USB device * @devnum: device number; address on a USB bus * @devpath: device ID string for use in messages (e.g., /port/...) * @route: tree topology hex string for use with xHCI * @state: device state: configured, not attached, etc. * @speed: device speed: high/full/low (or error) * @rx_lanes: number of rx lanes in use, USB 3.2 adds dual-lane support * @tx_lanes: number of tx lanes in use, USB 3.2 adds dual-lane support * @tt: Transaction Translator info; used with low/full speed dev, highspeed hub * @ttport: device port on that tt hub * @toggle: one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints * @parent: our hub, unless we're the root * @bus: bus we're part of * @ep0: endpoint 0 data (default control pipe) * @dev: generic device interface * @descriptor: USB device descriptor * @bos: USB device BOS descriptor set * @config: all of the device's configs * @actconfig: the active configuration * @ep_in: array of IN endpoints * @ep_out: array of OUT endpoints * @rawdescriptors: raw descriptors for each config * @bus_mA: Current available from the bus * @portnum: parent port number (origin 1) * @level: number of USB hub ancestors * @can_submit: URBs may be submitted * @persist_enabled: USB_PERSIST enabled for this device * @have_langid: whether string_langid is valid * @authorized: policy has said we can use it; * (user space) policy determines if we authorize this device to be * used or not. By default, wired USB devices are authorized. * WUSB devices are not, until we authorize them from user space. * FIXME -- complete doc * @authenticated: Crypto authentication passed * @wusb: device is Wireless USB * @lpm_capable: device supports LPM * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM * @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled * @usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled * @usb3_lpm_u1_enabled: USB3 hardware U1 LPM enabled * @usb3_lpm_u2_enabled: USB3 hardware U2 LPM enabled * @string_langid: language ID for strings * @product: iProduct string, if present (static) * @manufacturer: iManufacturer string, if present (static) * @serial: iSerialNumber string, if present (static) * @filelist: usbfs files that are open to this device * @maxchild: number of ports if hub * @quirks: quirks of the whole device * @urbnum: number of URBs submitted for the whole device * @active_duration: total time device is not suspended * @connect_time: time device was first connected * @do_remote_wakeup: remote wakeup should be enabled * @reset_resume: needs reset instead of resume * @port_is_suspended: the upstream port is suspended (L2 or U3) * @wusb_dev: if this is a Wireless USB device, link to the WUSB * specific data for the device. * @slot_id: Slot ID assigned by xHCI * @removable: Device can be physically removed from this port * @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout. * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout. * @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout. * @lpm_disable_count: Ref count used by usb_disable_lpm() and usb_enable_lpm() * to keep track of the number of functions that require USB 3.0 Link Power * Management to be disabled for this usb_device. This count should only * be manipulated by those functions, with the bandwidth_mutex is held. * @hub_delay: cached value consisting of: * parent->hub_delay + wHubDelay + tTPTransmissionDelay (40ns) * * Will be used as wValue for SetIsochDelay requests. * * Notes: * Usbcore drivers should not set usbdev->state directly. Instead use * usb_set_device_state(). */ struct usb_device { int devnum; char devpath[16]; u32 route; enum usb_device_state state; enum usb_device_speed speed; unsigned int rx_lanes; unsigned int tx_lanes; struct usb_tt *tt; int ttport; unsigned int toggle[2]; struct usb_device *parent; struct usb_bus *bus; struct usb_host_endpoint ep0; struct device dev; struct usb_device_descriptor descriptor; struct usb_host_bos *bos; struct usb_host_config *config; struct usb_host_config *actconfig; struct usb_host_endpoint *ep_in[16]; struct usb_host_endpoint *ep_out[16]; char **rawdescriptors; unsigned short bus_mA; u8 portnum; u8 level; unsigned can_submit:1; unsigned persist_enabled:1; unsigned have_langid:1; unsigned authorized:1; unsigned authenticated:1; unsigned wusb:1; unsigned lpm_capable:1; unsigned usb2_hw_lpm_capable:1; unsigned usb2_hw_lpm_besl_capable:1; unsigned usb2_hw_lpm_enabled:1; unsigned usb2_hw_lpm_allowed:1; unsigned usb3_lpm_u1_enabled:1; unsigned usb3_lpm_u2_enabled:1; int string_langid; /* static strings from the device */ char *product; char *manufacturer; char *serial; struct list_head filelist; int maxchild; u32 quirks; atomic_t urbnum; unsigned long active_duration; #ifdef CONFIG_PM unsigned long connect_time; unsigned do_remote_wakeup:1; unsigned reset_resume:1; unsigned port_is_suspended:1; #endif struct wusb_dev *wusb_dev; int slot_id; enum usb_device_removable removable; struct usb2_lpm_parameters l1_params; struct usb3_lpm_parameters u1_params; struct usb3_lpm_parameters u2_params; unsigned lpm_disable_count; u16 hub_delay; };
其中部分参数含义如下:
- devnum; 设备号,是在USB总线的地址;
- devpath :用于消息的设备ID字符串;
- route:用于 xHCI 的树拓扑十六进制字符串;
- state:设备状态:已配置、未连接等等;
- speed:设备速度:高速、全速、低速或错误;
- rx_lanes:正在使用的rx lanes数,USB 3.2 增加了dual-lane支持;
- tx_lanes:正在使用的tx lanes数,USB 3.2 增加了dual-lane支持;
- tt:处理传输者信息;用于低速、全速设备和高速HUB;
- ttport:位于tt HUB的设备口;
- toggle:每个端点的占一位,表明端点的方向([0] = IN, [1] = OUT);
- parent:上一级HUB指针,除非是根节点;
- bus:总线指针;
- ep0:端点0,需要注意的是端点0是单独存放在usb_device中的;
- dev:一般的设备接口数据结构 ;
- descriptor:USB设备描述符,
- config:设备的所有配置,配置结构体里包含了配置描述符;
- actconfig:被激活的设备配置;
- ep_in:所有的USB输入端点数组;
- ep_ou:所有的USB输出端点数组;
- rawdescriptors:每个配置的raw描述符;
- bus_mA:可使用的总线电流;
- portnum:父端口号;
- level:USB HUB的层数;
- can_submit:URB可被提交标志;
- persist_enabled:USB_PERSIST使能标志;
- have_langid:string_langid存在标志;
- authorized:授权策略;
- authenticated:加密认证通过;
- discon_suspended:暂停时断开标志;
- wusb:无线USB标志;
- lpm_capable:设备支持LPM标志位;
- usb2_hw_lpm_capable:device can perform USB2 hardware LPM;
- usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM;
- usb2_hw_lpm_enabled: USB2 hardware LPM is enabled ;
- usb2_hw_lpm_allowed: Userspace allows USB 2.0 LPM to be enabled;
- usb3_lpm_u1_enabled: USB3 hardware U1 LPM enabled;
- usb3_lpm_u2_enabled: USB3 hardware U2 LPM enabled;
- string_langid:字符串语言ID;
- product:产品名;
- manufacturer:厂商名;
- serial:产品串号;
- filelist:此设备打开的usbfs文件;
- maxchild; (若为HUB)接口数;
- quirks: quirks of the whole device;
- urbnum: 为整个设备提交的URBs数量;
- active_duration:设备未挂起的总时间;
- connect_time:设备首次连接的时间;
- do_remote_wakeup:远程唤醒 ;
- reset_resume:使用复位替代唤醒;
- port_is_suspended:上游端口被挂起(L2 或 U3);
- wusb_dev:(如果为无线USB)连接到WUSB特定的数据结构;
- slot_id:xHCI 分配的槽位 ID;
- removable: Device can be physically removed from this port;
- ......
usb_device_descriptor对应于协议中的设备描述符,其定义在include/uapi/linux/usb/ch9.h:
/* 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));
其中部分参数含义如下:
- bLength:描述符的长度;
- bDescriptorType:描述符的类型,设备描述符类型值为1;
- bcdUSB:usb版本号,比如usb2.0;
- bDeviceClass:USB分配的设备类code;
- bDeviceSubClass:USB分配的设备子类code;
- bDeviceProtocol:USB分配的协议code;
- bMaxPacketSize0:端点0最大包大小;
- idVendor:厂商编号;
- idProduct:产品编号;
- bcdDevice:设备出厂编号;
- iManufacturer:描述厂商字符串的索引;
- iProduct:描述产品字符串的索引;
- iSerialNumber:描述设备序列号字符串的索引;
- bNumConfigurations:配置描述符的个数,表示有多少个配置描述符;
5.5 URB(USB Request Block)
linux内核通过一个称为urb(usb请求块)的东西和所有的USB设备通信,urb是USB设备驱动中用来描述与USB设备通信所用的基本载体和核心数据结构,这个请求块使用struct urb结构体来形容,定义在include/linux/usb.h:
/** * struct urb - USB Request Block * @urb_list: For use by current owner of the URB. * @anchor_list: membership in the list of an anchor * @anchor: to anchor URBs to a common mooring * @ep: Points to the endpoint's data structure. Will eventually * replace @pipe. * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl" * (control), "bulk", "int" (interrupt), or "iso" (isochronous). * For example usb_sndbulkpipe() or usb_rcvintpipe(). Endpoint * numbers range from zero to fifteen. Note that "in" endpoint two * is a different endpoint (and pipe) from "out" endpoint two. * The current configuration controls the existence, type, and * maximum packet size of any given endpoint. * @stream_id: the endpoint's stream ID for bulk streams * @dev: Identifies the USB device to perform the request. * @status: This is read in non-iso completion functions to get the * status of the particular request. ISO requests only use it * to tell whether the URB was unlinked; detailed status for * each frame is in the fields of the iso_frame-desc. * @transfer_flags: A variety of flags may be used to affect how URB * submission, unlinking, or operation are handled. Different * kinds of URB can use different flags. * @transfer_buffer: This identifies the buffer to (or from) which the I/O * request will be performed unless URB_NO_TRANSFER_DMA_MAP is set * (however, do not leave garbage in transfer_buffer even then). * This buffer must be suitable for DMA; allocate it with * kmalloc() or equivalent. For transfers to "in" endpoints, contents * of this buffer will be modified. This buffer is used for the data * stage of control transfers. * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, * the device driver is saying that it provided this DMA address, * which the host controller driver should use in preference to the * transfer_buffer. * @sg: scatter gather buffer list, the buffer size of each element in * the list (except the last) must be divisible by the endpoint's * max packet size if no_sg_constraint isn't set in 'struct usb_bus' * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer. The transfer may * be broken up into chunks according to the current maximum packet * size for the endpoint, which is a function of the configuration * and is encoded in the pipe. When the length is zero, neither * transfer_buffer nor transfer_dma is used. * @actual_length: This is read in non-iso completion functions, and * it tells how many bytes (out of transfer_buffer_length) were * transferred. It will normally be the same as requested, unless * either an error was reported or a short read was performed. * The URB_SHORT_NOT_OK transfer flag may be used to make such * short reads be reported as errors. * @setup_packet: Only used for control transfers, this points to eight bytes * of setup data. Control transfers always start by sending this data * to the device. Then transfer_buffer is read or written, if needed. * @setup_dma: DMA pointer for the setup packet. The caller must not use * this field; setup_packet must point to a valid buffer. * @start_frame: Returns the initial frame for isochronous transfers. * @number_of_packets: Lists the number of ISO transfer buffers. * @interval: Specifies the polling interval for interrupt or isochronous * transfers. The units are frames (milliseconds) for full and low * speed devices, and microframes (1/8 millisecond) for highspeed * and SuperSpeed devices. * @error_count: Returns the number of ISO transfers that reported errors. * @context: For use in completion functions. This normally points to * request-specific driver context. * @complete: Completion handler. This URB is passed as the parameter to the * completion function. The completion function may then do what * it likes with the URB, including resubmitting or freeing it. * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to collect the transfer status for each buffer. * * This structure identifies USB transfer requests. URBs must be allocated by * calling usb_alloc_urb() and freed with a call to usb_free_urb(). * Initialization may be done using various usb_fill_*_urb() functions. URBs * are submitted using usb_submit_urb(), and pending requests may be canceled * using usb_unlink_urb() or usb_kill_urb(). * * Data Transfer Buffers: * * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise * taken from the general page pool. That is provided by transfer_buffer * (control requests also use setup_packet), and host controller drivers * perform a dma mapping (and unmapping) for each buffer transferred. Those * mapping operations can be expensive on some platforms (perhaps using a dma * bounce buffer or talking to an IOMMU), * although they're cheap on commodity x86 and ppc hardware. * * Alternatively, drivers may pass the URB_NO_TRANSFER_DMA_MAP transfer flag, * which tells the host controller driver that no such mapping is needed for * the transfer_buffer since * the device driver is DMA-aware. For example, a device driver might * allocate a DMA buffer with usb_alloc_coherent() or call usb_buffer_map(). * When this transfer flag is provided, host controller drivers will * attempt to use the dma address found in the transfer_dma * field rather than determining a dma address themselves. * * Note that transfer_buffer must still be set if the controller * does not support DMA (as indicated by bus.uses_dma) and when talking * to root hub. If you have to trasfer between highmem zone and the device * on such controller, create a bounce buffer or bail out with an error. * If transfer_buffer cannot be set (is in highmem) and the controller is DMA * capable, assign NULL to it, so that usbmon knows not to use the value. * The setup_packet must always be set, so it cannot be located in highmem. * * Initialization: * * All URBs submitted must initialize the dev, pipe, transfer_flags (may be * zero), and complete fields. All URBs must also initialize * transfer_buffer and transfer_buffer_length. They may provide the * URB_SHORT_NOT_OK transfer flag, indicating that short reads are * to be treated as errors; that flag is invalid for write requests. * * Bulk URBs may * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers * should always terminate with a short packet, even if it means adding an * extra zero length packet. * * Control URBs must provide a valid pointer in the setup_packet field. * Unlike the transfer_buffer, the setup_packet may not be mapped for DMA * beforehand. * * Interrupt URBs must provide an interval, saying how often (in milliseconds * or, for highspeed devices, 125 microsecond units) * to poll for transfers. After the URB has been submitted, the interval * field reflects how the transfer was actually scheduled. * The polling interval may be more frequent than requested. * For example, some controllers have a maximum interval of 32 milliseconds, * while others support intervals of up to 1024 milliseconds. * Isochronous URBs also have transfer intervals. (Note that for isochronous * endpoints, as well as high speed interrupt endpoints, the encoding of * the transfer interval in the endpoint descriptor is logarithmic. * Device drivers must convert that value to linear units themselves.) * * If an isochronous endpoint queue isn't already running, the host * controller will schedule a new URB to start as soon as bandwidth * utilization allows. If the queue is running then a new URB will be * scheduled to start in the first transfer slot following the end of the * preceding URB, if that slot has not already expired. If the slot has * expired (which can happen when IRQ delivery is delayed for a long time), * the scheduling behavior depends on the URB_ISO_ASAP flag. If the flag * is clear then the URB will be scheduled to start in the expired slot, * implying that some of its packets will not be transferred; if the flag * is set then the URB will be scheduled in the first unexpired slot, * breaking the queue's synchronization. Upon URB completion, the * start_frame field will be set to the (micro)frame number in which the * transfer was scheduled. Ranges for frame counter values are HC-specific * and can go from as low as 256 to as high as 65536 frames. * * Isochronous URBs have a different data transfer model, in part because * the quality of service is only "best effort". Callers provide specially * allocated URBs, with number_of_packets worth of iso_frame_desc structures * at the end. Each such packet is an individual ISO transfer. Isochronous * URBs are normally queued, submitted by drivers to arrange that * transfers are at least double buffered, and then explicitly resubmitted * in completion handlers, so * that data (such as audio or video) streams at as constant a rate as the * host controller scheduler can support. * * Completion Callbacks: * * The completion callback is made in_interrupt(), and one of the first * things that a completion handler should do is check the status field. * The status field is provided for all URBs. It is used to report * unlinked URBs, and status for all non-ISO transfers. It should not * be examined before the URB is returned to the completion handler. * * The context field is normally used to link URBs back to the relevant * driver or request state. * * When the completion callback is invoked for non-isochronous URBs, the * actual_length field tells how many bytes were transferred. This field * is updated even when the URB terminated with an error or was unlinked. * * ISO transfer status is reported in the status and actual_length fields * of the iso_frame_desc array, and the number of errors is reported in * error_count. Completion callbacks for ISO transfers will normally * (re)submit URBs to ensure a constant transfer rate. * * Note that even fields marked "public" should not be touched by the driver * when the urb is owned by the hcd, that is, since the call to * usb_submit_urb() till the entry into the completion routine. */ struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ int unlinked; /* unlink error code */ void *hcpriv; /* private data for host controller */ atomic_t use_count; /* concurrent submissions counter */ atomic_t reject; /* submissions will fail */ /* public: documented fields in the urb that can be used by drivers */ struct list_head urb_list; /* list head for use by the urb's * current owner */ struct list_head anchor_list; /* the URB may be anchored */ struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */ unsigned int pipe; /* (in) pipe information */ unsigned int stream_id; /* (in) stream ID */ int status; /* (return) non-ISO status */ unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/ void *transfer_buffer; /* (in) associated data buffer */ dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ struct scatterlist *sg; /* (in) scatter gather buffer list */ int num_mapped_sgs; /* (internal) mapped sg entries */ int num_sgs; /* (in) number of entries in the sg list */ u32 transfer_buffer_length; /* (in) data buffer length */ u32 actual_length; /* (return) actual transfer length */ unsigned char *setup_packet; /* (in) setup packet (control only) */ dma_addr_t setup_dma; /* (in) dma addr for setup_packet */ int start_frame; /* (modify) start frame (ISO) */ int number_of_packets; /* (in) number of ISO packets */ int interval; /* (modify) transfer interval * (INT/ISO) */ int error_count; /* (return) number of ISO errors */ void *context; /* (in) context for completion */ usb_complete_t complete; /* (in) completion routine */ struct usb_iso_packet_descriptor iso_frame_desc[0]; /* (in) ISO ONLY */ };
其中:
- kref:urb引用计数;
- hcpriv:主机控制器私有数据;
- use_count:并发传输计数;
- reject:传输将失效;
- urb_list:链表头;
- dev:关联的usb设备;
- ep:指向端点的数据结构;
- pipe:指向端点管道;
- status:urb的当前状态;当status=0时,表示数据被成功的收到/发送;
- transfer_buffer:发送到设备或从设备接收数据的缓冲区;
- transfer_dma:用来以DMA方式向设备传输数据的缓冲区;
- actual_length:urb结束后,发送或接收数据的实际长度;
- setup_package:指向控制urb设置数据包的指针;
- setup_dma:控制urb的设置数据包的DMA缓冲区;
- start_frame:等待传输中用于设置或返回初始帧;
- number_of_package:等时传输找那个等时缓冲区数量;
- interval:urb被轮询到的事件间隔(对中断和等时urb有效);
- error_count:等时传输错误数量:
- context:complete函数上下文;
- complete:当urb被完全传输或发生错误时,被调用;
- iso_frame_desc:单个urb一次可定义多个等时传输时,描述各个等时传输。
urb典型的生命周期如下:
- usb设备驱动程序创建并初始化一个访问特定usb设备特定端点的urb,并提交给usb core;
- usb core 提交该urb到usb主控制器驱动程序;
- usb主控制器驱动程序根据 urb 描述的信息,来访问usb设备;
- 当设备访问结束后,usb主控制器驱动程序通知 usb core(调用这个函数usb_complete_t complete;)然后其再通知usb设备驱动程序。
六、开发板启动
由于内核自带了USB驱动,所以我们在开发板上接一个USB鼠标,然后启动开发板,串口就会输出如下信息:
usb 1-1: new low-speed USB device number 2 using s3c2410-ohci
可以看到linux内核已经识别到我们的USB鼠标设备了,那linux内核是如何设备到我们的USB设备的呢,这将在后面章节介绍。
参考文章
[4]常见硬件通信(SPI、I2C、CAN、USB、UART)协议介绍
[5]USART(RS232/422/485)、I2C、SPI、CAN、USB总线
[6]USB总线-USB协议简介(一)(转载)
[7]图解USB标准之架构概览
[8]USB驱动框架
[9]USB_4大描述符