Linux USB Subsystem
Linux 包括了一个 USB Core 的子系统。其包含了一组特定的API函数来支持USB设备和主机控制器。
USB Core 中包含了通用于所有 USB 设备和主机控制器驱动程序的函数。这些函数可以划分成上层和底层API。
从下图可以看出,一类API是为USB设备驱动程序服务,另一类为主机控制器驱动程序服务。
![]() |
USB Device Driver Framework
USB设备驱动通过USB子系统框架进行注册/注销。每个USB设备驱动应该注册两个入口点和入口名字,并且注册一组文件操作指针和一个minor number。
所有USB设备的 major number 都是 180。
Framework Data Structures
所有USB相关函数或数据结构都遵从相同的命名规则,且以usb_ 为前缀。
下图列出了注册usb驱动到USB子系统的数据结构。
![]() |
- name: 模块名
- probe: 侦测函数入口
- disconnect: 断开函数入口
- driver_list: 子系统内部使用
- fops: 驱动程序通用文件操作列表
- minor: 被分配给该驱动的 minor number 基值(该值应该是16的倍数)。
- serialize: 串行化
- ioctl: I/O接口控制
- id_table:
Framewor Entry Point
USB驱动框架针对常规设备驱动增加了两个入口函数。
- void *probe(struct usb_device *dev, unsigned int interface, const struct usb_device_id *id_table);
当新设备被连接上总线时,该入口函数被调用。驱动将为新设备创建其内部数据结构的实例。
dev 参数指定了设备上下文, 包含了所有 USB 描述符的指针。
interface 参数指定了接口值。 如果usb驱动希望去绑定一个特定的设备和接口,它将返回一个指针;该指针指向了驱动程序的上下文数据结构。
probe 函数通常检查 usb 供应商和产品信息,或者usb class 和 subclass 定义。如果和驱动支持的接口数值进行比较后其相等,将继续解析更多的 USB 描述符。
一个简单的 probe 函数示例如下:
- void disconnect(struct usb_device *dev, void *drv_context);
当USB驱动服务的设备被拔出时, disconnect() 函数被调用。
dev 参数指定了设备上下文。
drv_context 参数返回一个指向先前由 probe() 函数注册的 drv_context 指针。
一旦 disconnect() 函数返回, USB 框架将释放所有关联该设备的数据结构。 usb_driver 数据结构不能再被驱动使用。
一个简单的 disconnect() 函数示例如下:
Framework Functions
- int usb_register(struct usb_driver *drv);
usb_register() 函数注册一个新的usb 驱动到子系统中。
drv 参数指向一个已被初始化的 usb_driver 数据结构。 - void usb_deregister(struct usb_driver *drv);
usb_deregister() 从子系统中注销一个已注册的USB设备驱动。
- void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *drv_context);
如果usb 设备驱动需要声明多于一个的接口, usb_driver_claim_interface() 函数被调用。
- int usb_interface_claimed(struct usb_interface *iface);
usb_interface_claimed() 函数检查是否驱动程序已经声明了该接口。
- void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
usb_driver_relese_interface() 函数释放先前声明的接口。
disconnect() 函数不需要释放先前被 probe() 函数声明的接口。
- const struct usb_device_id *usb_match_id( struct usb_device *dev, struct usb_interface *interface, const struct usb_device_id *id);
Configuring USB Devices
USB子系统框架提供了一系列的可以选择/查询设备描述符、配置和可选设定的 API 函数。
所有标准操作都是通过对设备的控制传输来完成。
Descriptor Data Structures
Linux USB 子系统通过扩展或内嵌的方式,在设备描述符结构中包含了标准USB描述符。
描述符数据结构存储了指向被选定的配置和接口的指针。
struct usb_device{ ... struct usb_config_descriptor *actconfig;/* the active configuration */ ... struct usb_device_descriptor descriptor;/* Descriptor */ struct usb_config_descriptor *config; /* All of the configs */ }
usb_device 结构是所有 USB特定描述符之根本。有时,为了配置设备或设置传输请求,USB驱动有必要解析该结构。- 访问所有有效的配置描述符
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { struct usb_config_descriptor *cfg = &dev->config[i]; ... }
- 访问一个特定配置的所有有效接口描述符
for (j = 0; j < cfg->bNumInterfaces; j++) { struct usb_interface *ifp = &cfg->interface[j]; ... }
为启动活动配置的解析,使用 dev->actconfig 指针。
- 访问一个特定接口的所有可选设定
for (k = 0; k < ifp->num_altsetting; k++) { struct usb_interface_descriptor *as = &ifp->altsetting[k]; ... }
活动可选设定可以通过如下方式访问:
*as = &ifp->altsetting[ifp->act_altsetting]
- 访问一个特定可选设定的所有端点
for(l = 0; l < as->bNumEndpoints; l++) { struct usb_endpoint_descriptor *ep=&as->endpoint[k]; ... }
Standard Device Requests - int usb_set_configuration(struct usb_device *dev, int configuration);
To activate a particular configuration use this function.
The argument is of
0 <= configuration < dev->descriptor.bNumConfigurations.
Configuration 0 is selected by default after the device is attached to the bus. - int usb_set_interface(struct usb_device *dev, int interface, int alternate);
This function activates an alternate setting of a specified interface.
The argument interface is of
0 <= interface < dev->actconfig->bNumInterfaces.
The argument alternate is of
0 <= alternate < dev->actconfig->interface[interface].num_altsetting - int usb_get_device_descriptor(struct usb_device *dev);
This function rereads the complete descriptor tree from a particular device.
It is called automatically whenever a device is attached to the bus or it may be called whenever a USB descriptor has changed.
- int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size);
Single USB descriptors can be read as raw data from a device. This function can be used to parse extended or vendor specific descriptors.
- int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);
If a device, configuration or interface descriptor references a string index value, this function can be used to retrieve the string descriptor.
According to the specification USB strings are coded as Unicode. If successful the function returns 0 otherwise an error code is returned.
- int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
This function simplifies usb_get_string by converting Unicode strings into ASCII strings.
- int usb_get_status(struct usb_device *dev, int type, int target, void *data);
- int usb_clear_halt(struct usb_device *dev, int pipe);
If an endpoint is stalled , call this function to clear the STALL condition.
STALL indicates that a function is unable to transmit or receive data, or that a control pipe request is not supported.
The argument endpoint defines a pipe handle.
- int usb_get_protocol(struct usb_device *dev, int ifnum);
- int usb_set_protocol(struct usb_device *dev, int protocol, int ifnum);
- int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, int ifnum, void *buf, int size);
- int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id);
USB Transfer
包括了所有数据结构,宏和与总线数据传输相关的函数。以及如何设置,提交和处理传输请求。
Transfer Data Structures & Macros
Linux USB子系统使用唯一的数据传输结构URB ( USB Request Block)。该数据结构包含了设置任何usb传输类型所需的全部参数。
所有数据传输请求以异步方式发送给 USB Core, 传输请求完成则通过回调函数通知。
上图中,
- C 标记表示所有传输类型都通用的元素。
- > 表示输入参数
- < 表示返回值
- M 表示强制参数
- O 表示可选参数
- T 表示双向参数 ( 可输入,可输出)
- 所有非通用元素,标记有三列。分别代表控制,中断,实时传输。如果对应列有一个 X 标记,表示该元素被用于该传输类型。
URB 结构参数介绍如下:
- dev (强制输入参数) : 指向 usb_device 结构体的指针
- pipe (强制输入参数): pipe 用来编码端点值和属性
- pipe=usb_sndctrlpipe(dev,endpoint)
pipe=usb_rcvctrlpipe(dev,endpoint)
- pipe=usb_sndctrlpipe(dev,endpoint)
创建下行 (snd ) 和上行 ( rcv)控制传输到到指定的端点。
- pipe=usb_sndbulkpipe(dev,endpoint)
pipe=usb_rcvbulkpipe(dev, endpoint)
- pipe=usb_sndbulkpipe(dev,endpoint)
创建下行 (snd ) 和上行 ( rcv)块传输到到指定的端点。
- pipe=usb_sndintpipe(dev,endpoint)
pipe=usb_rcvintopipe(dev,endpoint
创建下行 (snd ) 和上行 ( rcv)中断传输到到指定的端点。
- pipe=usb_sndisopipe(dev,endpoint)
pipe=usb_rcvisopipe(dev, endpoint)创建下行 (snd ) 和上行 ( rcv)实时传输到到指定的端点。
- pipe=usb_sndintpipe(dev,endpoint)
- transfer_buffer (强制输入参数)
- transfer_buffer_length (强制输入参数)
- complete (可选输入参数): 提供给调用者的函数指针。当传输请求完成后,该函数被调用。通过此回调方式,调用者可以在传输完成后进行特定的操作。
- context (可选输入参数)
- transfer_flags (可选输入参数和返回值)
- USB_DISABLE_SPD
- USB_NO_FSBR
- USB_ISO_ASAP
- USB_ASYNC_UNLINK
- USB_TIMEOUT_KILLED
- USB_QUEUE_BULK
- next (可选输入参数)
- status (返回值)
- actual_length (返回值)
URB FunctionsUSB Core 一共有四个函数处理 URB数据结构。
- purb_t usb_alloc_urb(int iso_packets);
usb_alloc_urb() 用于创建一个新的 URB 数据结构实例。
iso_packets 参数: 表示 iso_frame_desc 结构的数目。用于实时传输类型。
- void usb_free_urb (purb_t purb);
usb_free_urb() 释放由 usb_alloc_urb() 分配的 URB 结构。
- int usb_submit_urb(purb_t purb);
usb_submit_urb() 以异步方式提交传输请求到 USB Core 中去。
- int usb_unlink_urb(purb_t purb);
usb_unlink_urb() 取消一个已提交但未完成的传输请求。
usb_unlink_urb() 也被用来停止中断传输类型的URB。
URB Macros
2.x 内核中有如下 URB 宏用于填充 URB 结构体。
至少3.4.x 内核中,已经转化成对应的函数形式填充 URB 结构体。
- FILL_CONTROL_URB(purb, dev, pipe, setup_packet, transfer_buffer, transfer_buffer_length, complete, context);
- FILL_BULK_URB(purb, dev, pipe, transfer_buffer, transfer_buffer_length, complete, context);
- FILL_INT_URB(purb, dev, pipe, transfer_buffer, transfer_buffer_length, complete, context, interval);
- FILL_CONTROL_URB_TO();
- FILL_BULK_URB_TO();
Compatibility Wrappers
The USB core contains a number of higher level functions which were introduced as compatibility wrappers for the older APIs. Some of these functions can still be used to issue blocking control or bulk transfers.
- int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
Issues a blocking standard control request.
- int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *actual_length, int timeout);
Issues a blocking bulk transfer.
在 3.4.5 内核中,对应有
- int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout)
usb_control_msg() 创建一个简单的控制传输urb结构, 发送它到一个指定的端点并且等待该消息完成。
- dev: 指向此消息将要发送到的usb设备指针
- pipe: 指向次消息将要发送到的端点
- request: USB消息请求值
- requesttype: USB消息类型
- value USB消息值
- index USB消息索引值
- data 被发送的数据的指针
- size 被发送的数据字节长度
- timeout 消息完成之前超时等待的时间 (毫秒数)
usb_control_msg() 不可用于中断上下文,例如中断底半部。
如果需要一个异步消息,或者需要在中断上下文使用,使用 usb_submit_urb()。
如果usb驱动程序线程中调用了 usb_control_msg(), 请确保等待其完成后再调用 disconnect() 函数。
因为没有 URB 的句柄,该请求不能被撤消。
- int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
usb_interrupt_msg() 创建一个简单的中断传输urb结构, 发送它到一个指定的端点并且等待该消息完成。
usb_interrupt_msg() 不可用于中断上下文,例如中断底半部。
- int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
usb_bulk_msg() 创建一个简单的中断传输urb结构, 发送它到一个指定的端点并且等待该消息完成。
usb_bulk_msg() 不可用于中断上下文,例如中断底半部。