1. 端点 (endpoint)
USB端点只能单向传送数据,从主机到设备(输出端点)或从设备到主机(输入端点)。
依据传输数据方式的不同,可以分为4种端点:
a. 控制端点(control endpoint):通常用于配置设备,获取设备信息,发送命令到设备,或获取设备的状态。
b. 中断端点(interrupt endpoint):当USB host要求设备传输数据时,中断端点就以一个固定的速率来传送少量的数据。USB键盘和鼠标就是这种方式。
c. 批量端点(bulk endpoint):传输大批量数据。打印机,存储设备和网络设备多用这采用传输方式。
d. 等时端点(也交同步端点,isochronous endpoint):可以传输大批量数据,等待功能使得可以确保数据不丢失。可以保持一个恒定的数据流,如实时的数据收集(音频和视频设备)都使用这种方式。
控制和批量端点用于异步传输数据。
内核中使用struct usb_host_endpoint结构体描述USB端点:
/**
* 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
* @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
*
* 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 list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */
unsigned char *extra; /* Extra descriptors */
int extralen;
int enabled;
};
struct usb_endpoint_descriptor 结构体包含了所有USB特定的数据,这些数据的格式是由设备自己定义的:
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress; //特定端点的USB地址,这8位值中还包括了端点的方向。
//该字段可以结合掩码 USB_DIR_OUT 和 USB_DIR_IN 来使用,
//以确定该端点的数据时传向设备还是主机。
__u8 bmAttributes; //这里描述端点的类型,
//该值可以结合位掩码 USB_ENDPOINT_XFERTYPE_MASK
//来确定此端点的类型是 USB_ENDPOINT_XFER_ISOC(等时),
//USB_ENDPOINT_XFER_BULK(批量)
//还是USB_ENDPOINT_XFER_INT(中断)
__le16 wMaxPacketSize; //该端点一次可以处理的最大字节数。
//驱动可以发送数量大于此值的数据到端点,
//但实际传输中,数据会被分割成 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));
2. 接口 (interface):
一个USB接口可以包含多个USB端点,一个USB接口处理一种USB逻辑连接(如 鼠标,键盘 或者 音频流)。
一些USB设备具有多个接口,如USB扬声器可以包括两个接口:一个USB键盘用于按键 和 一个音频流。
每个USB驱动控制一个接口,因此一扬声器为例,Linux需要两个不同的驱动程序来处理一个硬件设备。
内核使用struct usb_interface 来描述 USB 接口:
/**
* 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.
* @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.
* @pm_usage_cnt: PM usage counter for this interface
* @reset_ws: Used for scheduling resets from atomic context.
* @reset_running: set to 1 if the interface is currently running a
* queued reset so that usb_cancel_queued_reset() doesn't try to
* remove from the workqueue when running inside the worker
* thread. See __usb_queue_reset_device().
*
* 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; //包含了可能用于该接口的可选设置
/* the currently active alternate setting */
struct usb_host_interface *cur_altsetting; //指向altsetting数组内部的指针,
//表示该接口当前的接口设置
/* number of alternate settings */
unsigned num_altsetting; //altsetting 指针所指的可选设置数量
/* If there is an interface association descriptor then it will list
* the associated interfaces */
struct usb_interface_assoc_descriptor *intf_assoc;
/* minor number this interface is bound to */
int minor; //USB核心分配给该接口的次设备号
//这个仅在usb_register_dev()调用成功后有效
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 reset_running:1;
unsigned resetting_device:1; /* true: bandwidth alloc after reset */
struct device dev; /* interface specific device info */
struct device *usb_dev;
atomic_t pm_usage_cnt; /* usage counter for autosuspend */
struct work_struct reset_ws; /* for resets in atomic context */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
3. 配置 (config):
一个USB 配置 可以包含多个 USB 接口。
一个USB 设备可以有多个配置,可以在配置之间切换以改变设备的状态,如手机插上USB会弹出,debug状态还是数据存储状态。这就是不同的配置。
同一时刻只能激活一种配置。
linux内核使用 struct usb_host_config 来描述 USB 配置:
/**
* 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;
};
总结:USB设备非常复杂,它由许多不同的逻辑单元组成,这些逻辑单元之间可以简单描述如下:
a. USB 设备通常具有一个或多个USB 配置
b. USB 配置通常具有一个或多个USB 接口
c. USB 接口通常具有一个或多个USB 设置
d. USB 接口没有或者具有一个以上USB 端点