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 端点