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.5Mbps5V/500mA半双工1996年1月
USB1.1全速(Full-Speed)12Mbps5V/500mA半双工1998年9月
USB2.0高速(High-Speed)480Mbps5V/500mA半双工2000年4月
USB3.0(USB3.2 Gen1)超高速(SuperSpeed USB)5Gbps5V/900mA全双工2008年月11月
USB3.1(USB3.2 Gen2)SuperSpeed USB 10Gbps10Gbps20V/5A全双工2013年月7月
USB3.2(USB3.2 Gen2×2)SuperSpeed USB 20Gps20Gbps20V/5Adual-lane2017年月9月
USB4.0(Gen3×2)----40Gbps100瓦single-lane或dual-lane,兼容Thunderbolt32019年月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摄像头就使用的是等时传输方式;

下表是这四类传输在不同速度模式下支持的最大包长度:

速度模式低速全速高速
控制传输88/16/32/6464
同步传输不支持10231024
中断传输0~80~640~1024
批量传输不支持8/16/32/64512
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名字取值(二进制)传输类型来源说明
令牌OUT0001全部主机IN事务中需要的设备和端点地址
令牌IN1001全部主机IN事务中需要的设备和端点地址
令牌SOF0101帧开始主机SOF标识符和帧号
令牌SETUP1101控制主机用于Setup事务的设备和端点地址
数据DATA00011全部主机、设备数据交替或数据PID序列
数据DATA11011全部主机、设备数据交替或数据PID序列
数据DATA20111等时主机、设备数据PID序列
数据MDATA1111等时、分割事务主机、设备数据PID序列
握手ACK0010控制、批量、中断主机、设备接收端接收到正确的数据信息包
握手NAK1010控制、批量、中断设备接收端不能接收数据,或者发送端无法发送数据或无数据要发送
握手STALL1110控制、批量、中断设备控制请求不被支持或端点被停止
握手NYET0110控制写、批量、OUT、分割事务设备正确的接收了数据信息包,但还没准备好接收下一个,或集线器还没有将数据信息包分割完成
特殊PRE1100控制、中断主机主机发出的先行信号
特殊ERR1100全部集线器由集线器返回的错误
特殊SPLIT1000全部主机分割事务
特殊PING0100控制写、批量、OUT主机PING测试
特殊EXT0000主机扩展,未使用

更多细节参考: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设备的呢,这将在后面章节介绍。

参考文章

[1]十四、Linux驱动之USB驱动分析

[2]19.Linux-USB总线驱动分析

[3]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大描述符

[10]Linux USB 3.0驱动分析(一)—— USB设备基础概念

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值