通用串行总线(英语:Universal Serial Bus,缩写:USB)是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,并扩展至摄影器材、数字电视(机顶盒)、游戏机等其它相关领域。
在USB总线出现之前,计算机与键盘、鼠标、扫描仪、打印机等的设备连接都使用专用的接口连接,不同的设备的接口不能互用,扩展性很差,每次插拔设备都要关闭计算机,不支持热插拔,且通信速率很低。
为了解决上述问题,USB总线诞生了。USB总线就好像一条管道,管道里流过的东西只要符合USB协议,至于具体流的是什么东西,USB总线并不关心。对应具体的设备上,只要是支持USB协议的设备,都可以连接计算机,如USB键盘、USB鼠标、USB摄像头、USB音箱等。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供电。
注: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是主从模式的总线,主机称为Host,丛机称为Device(设备)。从机与从机之间、主机与主机之间(不包括USB4.0),不能互联。每次通信都是由主机发起,从机不能主动发起通信,只能被动的应答主机的请求。
USB3.0及以后的USB协议,主机也可以和集线器(Hub)通信。为了增加灵活性,又出现了USB OTG(On The Go),USB OTG支持主从切换,同一个设备,在不同场合下,可以在主机和从机之间切换。
USB OTG线中增加了一根USB ID线,当USB ID线上拉时,处于从机模式,当USB ID线接地时,处于主机模式。
在有些场景下,我们期望将一个USB接口扩展为多个USB接口,这时我们就会使用到一个装置,也就是USB Hub,如下图所示:
因此,USB总线可能呈现出树状的拓扑接口吗,USB标准上说USB总线拓扑是一种分层星型结构,如下图所示:
从树结构我们可以看到:
比如我的计算机内部就是1个USB主控制器+Root Hub,从Windows设备管理器可以看到,下图是其中一条USB总线:
下图是USB3.2线缆的示意图,同时兼容USB2.0:
USB使用差分信号传输数据,图中的D+和D-是一对差分线,SSTX+和SSTX-是一对差分线,SSRX+和SSRX-是一对差分线:
USB3.2和USB2.0使用不同的差分线传输数据,两者互不干扰,可同时工作。USB3.2线缆中保留了USB2.0的数据传输通道,实现了对USB2.0的兼容。USB主机可通过Vbus线向设备供电,最大可输出20V/5A,GND是地线。
当一个USB设备插入PC机,PC机怎么知道有设备插入?
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架构包含四种基本类型的数据传输:
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),数据的接收端用它来报告事务成功或失败。对于超高速传输事务,信息包类型和协议有所不同,但却含有相同的地址、错误检查和与数据相配合的数据顺序值。
更多参考详见:USB协议详解
USB的驱动可以分为3类:
通常,对于USB这种标准化的设备,内核已经将USB主机控制器驱动编写好了,设备端Gadget驱动通常只运行固件程序而不是基于Linux, 所以驱动工程师的主要工作就是编写主机端USB设备驱动。
USB驱动框架结构图如下:
USB总线驱动程序包括USB Core和USB HCD两部分,其作用如下:
USB总线上的所有通信都是由主机发起的,所以本质上,USB都是采用轮询的方式进行的:
上面所说的主机具体指的是USB主机控制器。
USB Core这个模块是纯软件部分,并不代表一个设备,是独立于硬件的协议栈,它是所有USB设备赖以生存的模块,即USB子系统的核心。代码位于kernel/driver/usb/core目录下。
USB核心层向上为USB设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口,维护整个系统的USB设备信息,完成设备热插拔控制、总线数据传输控制等。
USB核心层将用户的请求映射到相关的USB HCD,用户不能直接访问USB HCD,USB核心层就是USB HCD和USB设备的桥梁
硬件主机控制器HOST Contrller之上运行的是USB HCD,是对USB主机控制器的一个抽象,实现USB核心层与主机控制器之间的对话接口。代码位于drivers/usb/host目录下,比如ohci-s3c2410.c文件。
USB主机控制器包含多种不同的类型,即OHCI和UHCI,EHCI,和xHCI,不同类型的USB主机控制器的区别和联系如下:
USB设备驱动框架如下图所示:
为了更好地描述USB设备的特征,USB提出了设备架构的概念。从这个角度来看,可以认为USB设备是由一些配置(configuration)、接口(interface)和端点(endpoint)组成,即一个USB设备可以含有一个或多个配置,在每个配置中可含有一个或多个接口,在每个接口中可含有若干个端点。其中:
任何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个如下:
除了端点0,其余的端点在设备配置之前不能与主机通信,只有向主机报告这些端点的特性并确认后才能被激活
USB设备使用各种描述符来说明其设备架构,包括设备描述符、配置描述符、接口描述符、端点描述符。
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; //本端口对应的urb链表,urb:usb请求块
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled; //使能的话urb才能被提交到此端口
int streams;
};
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; //描述符类型, 端点描述符类型值是5;
__u8 bEndpointAddress; //端点地址:位[3:0]表示端点号,第7位是方向:0位输出、1为输入;
__u8 bmAttributes; //端点属性:位[1:0]值00表示控制、01表示等时、10表示批量、11表示中断;
__le16 wMaxPacketSize; //本端点接受或发送的最大信息包的大小;
__u8 bInterval; //轮询数据传输端点的时间间隔,用在中断传输上,比如间隔时间查询鼠标的数据;
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
USB端口被捆绑为接口,USB接口只处理一种USB逻辑,一个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 */
};
其中部分参数含义如下:
其中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 */
};
可以看到该结构成员包含了:
我们重点看一下接口描述符usb_interface_descriptor ,其定义在include/uapi/linux/usb/ch9.h:
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength; //描述符长度;
__u8 bDescriptorType; //描述符类型,接口描述符类型值是4;
__u8 bInterfaceNumber; //接口的编号,相同的编号代表相同的功能接口;
__u8 bAlternateSetting; //接口的设置的编号,同一个接口可以有一个或者多个设置代表该接口下不同的参数;
__u8 bNumEndpoints; //要使用的端点个数(不包括端点0), 表示有多少个端点描述符,比如鼠标就只有一个端点;
__u8 bInterfaceClass; //接口类型;
__u8 bInterfaceSubClass; //接口子类型;
__u8 bInterfaceProtocol; //接口所遵循的协议;
__u8 iInterface; //描述该接口的字符串索引值;
} __attribute__ ((packed));
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;
};
其中部分参数含义如下:
其中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; //描述符类型,配置描述符类型值是2;
__le16 wTotalLength; //配置下面所有描述符的长度,包括这个配置描述符;
__u8 bNumInterfaces; //配置所支持的接口数;
__u8 bConfigurationValue; //配置值,实际上存的就是当前配置在usb_device->config数组中的索引;
__u8 iConfiguration; //描述该配置的字符串的索引值;
__u8 bmAttributes; //供电模式的选择;
__u8 bMaxPower; //设备从总线提取的最大电流;
} __attribute__ ((packed));
一个设备里包含了不同级别的配置,可以有一个或者多个配置。在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; //设备号,是在USB总线的地址;
char devpath[16]; //用于消息的设备ID字符串;
u32 route; //用于 xHCI 的树拓扑十六进制字符串;
enum usb_device_state state; //设备状态:已配置、未连接等等;
enum usb_device_speed speed; //设备速度:高速、全速、低速或错误;
unsigned int rx_lanes; //正在使用的rx lanes数,USB 3.2 增加了dual-lane支持;
unsigned int tx_lanes; //正在使用的tx lanes数,USB 3.2 增加了dual-lane支持;
struct usb_tt *tt; //处理传输者信息;用于低速、全速设备和高速HUB;
int ttport; //位于tt HUB的设备口;
unsigned int toggle[2]; //每个端点的占一位,表明端点的方向([0] = IN, [1] = OUT);
struct usb_device *parent; //上一级HUB指针,除非是根节点
struct usb_bus *bus; //总线指针;
struct usb_host_endpoint ep0; //端点0,需要注意的是端点0是单独存放在usb_device中的;
struct device dev; //一般的设备接口数据结构 ;
struct usb_device_descriptor descriptor; //USB设备描述符,
struct usb_host_bos *bos;
struct usb_host_config *config; //设备的所有配置,配置结构体里包含了配置描述符;
struct usb_host_config *actconfig; //被激活的设备配置;
struct usb_host_endpoint *ep_in[16]; //所有的USB输入端点数组;
struct usb_host_endpoint *ep_out[16]; //所有的USB输出端点数组;
char **rawdescriptors; //每个配置的raw描述符;
unsigned short bus_mA; //可使用的总线电流;
u8 portnum; //父端口号;
u8 level; //USB HUB的层数;
unsigned can_submit:1; /URB可被提交标志;
unsigned persist_enabled:1; //USB_PERSIST使能标志;
unsigned have_langid:1; //string_langid存在标志
unsigned authorized:1; //授权策略;
unsigned authenticated:1; //加密认证通过;
unsigned wusb:1; //无线USB标志;
unsigned lpm_capable:1; //设备支持LPM标志位
unsigned usb2_hw_lpm_capable:1; //device can perform USB2 hardware LPM;
unsigned usb2_hw_lpm_besl_capable:1; //device can perform USB2 hardware BESL LPM;
unsigned usb2_hw_lpm_enabled:1; // USB2 hardware LPM is enabled ;
unsigned usb2_hw_lpm_allowed:1; //Userspace allows USB 2.0 LPM to be enabled;
unsigned usb3_lpm_u1_enabled:1; //USB3 hardware U1 LPM enabled;
unsigned usb3_lpm_u2_enabled:1; // USB3 hardware U2 LPM enabled;
int string_langid; //字符串语言ID;
/* static strings from the device */
char *product; //产品名;
char *manufacturer; //厂商名;
char *serial;//产品串号;
struct list_head filelist; //此设备打开的usbfs文件;
int maxchild; //(若为HUB)接口数;
u32 quirks; //quirks of the whole device;
atomic_t urbnum; //为整个设备提交的URBs数量;
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; //上游端口被挂起(L2 或 U3);
#endif
struct wusb_dev *wusb_dev; //(如果为无线USB)连接到WUSB特定的数据结构;
int slot_id; //xHCI 分配的槽位 ID;
enum usb_device_removable removable; //Device can be physically removed from this port;
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;
};
usb_device_descriptor对应于协议中的设备描述符,其定义在include/uapi/linux/usb/ch9.h:
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength; //描述符的长度;
__u8 bDescriptorType; //描述符的类型,设备描述符类型值为1;
__le16 bcdUSB; //usb版本号,比如usb2.0;
__u8 bDeviceClass; //USB分配的设备类code;
__u8 bDeviceSubClass; //USB分配的设备子类code;
__u8 bDeviceProtocol; //USB分配的协议code;
__u8 bMaxPacketSize0; //端点0最大包大小;
__le16 idVendor; //厂商编号;
__le16 idProduct; //产品编号;
__le16 bcdDevice; //设备出厂编号;
__u8 iManufacturer; //描述厂商字符串的索引;
__u8 iProduct; //描述产品字符串的索引;
__u8 iSerialNumber; //描述设备序列号字符串的索引;
__u8 bNumConfigurations; //配置描述符的个数,表示有多少个配置描述符;
} __attribute__ ((packed));
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 */
};
其中:
usb设备驱动程序创建并初始化一个访问特定usb设备特定端点的urb,并提交给usb core;