USB驱动——描述符、URB、管道
来源:互联网 发布:算法的时间复杂度分析 编辑:程序博客网 时间:2024/06/07 09:17
大家常说,一个设备通常有多个配置,配置通常有多个接口,接口通常有多个端点。接口代表逻辑上的设备,比如声卡分为 录音和播放。访问设备时,访问的是某个接口(逻辑设备)。除了端点0之外,每个端点只支持一个传输方向,一种性质的传输传输数据时,读写某个端点,端点是数据通道。
本文首先分析设备、配置、接口、设置、端点之间的关系,然后根据 2440-ochi 驱动程序,分析一个设备注册到内核时,它的这些描述符的获取过程。
一、设备、配置、接口、设置、端点之间的关系
在内核中,一个 USB 设备,无论是 hub 还是普通的USB鼠标等等,它们都使用一个 usb_device 结构体来描述,在 usb_device 结构体中,包含了一个设备描述符和这个设备支持的多个配置。
struct usb_device {...struct device dev;struct usb_device_descriptor descriptor;// 设备描述符struct usb_host_config *config;// 支持的配置struct usb_host_config *actconfig;// 当前的配置...};设备描述符
struct usb_device_descriptor {__u8 bLength;// 描述符长度__u8 bDescriptorType;//描述符类型__le16 bcdUSB;//USB版本号__u8 bDeviceClass;//USB分配的设备类__u8 bDeviceSubClass;//USB分配的子类__u8 bDeviceProtocol;//USB分配的协议__u8 bMaxPacketSize0;//endpoint0最大包大小__le16 idVendor;//厂商编号__le16 idProduct;//产品编号__le16 bcdDevice;//设备出厂编号__u8 iManufacturer;//描述厂商字符串的索引__u8 iProduct;//描述产品字符串的索引__u8 iSerialNumber;//描述设备序列号字符串的索引__u8 bNumConfigurations;//可能的配置数量} __attribute__ ((packed));设备所包含的配置,配置里包含一个配置描述符,以及该配置所拥有的接口。
struct usb_host_config {struct usb_config_descriptordesc;// 配置描述符char *string;struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];struct usb_interface *interface[USB_MAXINTERFACES];// 接口struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];unsigned char *extra; int extralen;};配置描述符,注意它的 wTotalLength ,我们通常将一个配置以及它所包含的接口,接口所包含的端点所有的描述符一次性都获取到,wTotalLength 就是它们全部的长度。
struct usb_config_descriptor {__u8 bLength;//描述符长度__u8 bDescriptorType;//描述符类型编号__le16 wTotalLength;//请求配置所返回的所有数据的大小,当前配置的所有描述符包括所包含的接口、端点描述符__u8 bNumInterfaces;//配置所支持的接口数__u8 bConfigurationValue;//Set_Configuration 命令需要的参数值__u8 iConfiguration;//描述该配置的字符串的索引值__u8 bmAttributes;//供电模式选择__u8 bMaxPower;//设备从总线提取的最大电流} __attribute__ ((packed));配置所包含的接口
struct usb_interface {struct usb_host_interface *altsetting;// 一个接口可能有多个设置(一个接口多种功能),也就是这些接口所包含的端点凑起来可能有多种功能struct usb_host_interface *cur_altsetting;// 当前的设置unsigned num_altsetting;/* number of alternate settings */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 is_active:1;/* the interface is not suspended */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;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 */};接口当前的设置,里边包含了接口描述符和该接口所拥有的端点
struct usb_host_interface {struct usb_interface_descriptordesc;// 接口描述符struct usb_host_endpoint *endpoint;char *string;/* iInterface string, if present */unsigned char *extra; /* Extra descriptors */int extralen;};接口描述符
struct usb_interface_descriptor {__u8 bLength;//描述符长度__u8 bDescriptorType;//描述符类型__u8 bInterfaceNumber;//接口的编号__u8 bAlternateSetting;//备用的接口描述符编号__u8 bNumEndpoints;//该接口使用的端点数,不包括端点0__u8 bInterfaceClass;//接口类型__u8 bInterfaceSubClass;//接口子类型__u8 bInterfaceProtocol;//接口所遵循的协议__u8 iInterface;//描述该接口的字符串的索引值} __attribute__ ((packed));端点
struct usb_host_endpoint {struct usb_endpoint_descriptordesc;// 端点描述符struct list_headurb_list;// 该端点的 urb 队列void*hcpriv;struct ep_device *ep_dev;/* For sysfs info */struct usb_host_ss_ep_comp*ss_ep_comp;/* For SS devices */unsigned char *extra; /* Extra descriptors */int extralen;int enabled;};端点描述符
struct usb_endpoint_descriptor {__u8 bLength;//描述符长度__u8 bDescriptorType;//描述符类型__u8 bEndpointAddress;//端点地址:0~3位为端点号,第7位为传输方向__u8 bmAttributes;// 端点属性 bit 0-1 00控制 01 同步 02批量 03 中断__le16 wMaxPacketSize;//本端点接收或发送的最大信息包的大小__u8 bInterval;//轮询数据断端点的时间间隔//批量传送的端点,以及控制传送的端点,此域忽略//对于中断传输的端点,此域的范围为1~255/* NOTE: these two are _only_ in audio endpoints. *//* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */__u8 bRefresh;__u8 bSynchAddress;} __attribute__ ((packed));
1、usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size){struct usb_device_descriptor *desc;int ret;if (size > sizeof(*desc))return -EINVAL;desc = kmalloc(sizeof(*desc), GFP_NOIO);if (!desc)return -ENOMEM;ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);if (ret >= 0)memcpy(&dev->descriptor, desc, size);kfree(desc);return ret;}
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size){int i;int result;memset(buf, 0, size);/* Make sure we parse really received data */for (i = 0; i < 3; ++i) {/* retry on length 0 or error; some devices are flakey */result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,(type << 8) + index, 0, buf, size,USB_CTRL_GET_TIMEOUT);if (result <= 0 && result != -ETIMEDOUT)continue;if (result > 1 && ((u8 *)buf)[1] != type) {result = -ENODATA;continue;}break;}return result;}2、usb_configure_device
static int usb_configure_device(struct usb_device *udev){usb_get_configuration(udev);}
int usb_get_configuration(struct usb_device *dev){struct device *ddev = &dev->dev;int ncfg = dev->descriptor.bNumConfigurations;int result = 0;unsigned int cfgno, length;unsigned char *buffer;unsigned char *bigbuffer;struct usb_config_descriptor *desc;cfgno = 0;if (ncfg > USB_MAXCONFIG) {dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;}length = ncfg * sizeof(struct usb_host_config);dev->config = kzalloc(length, GFP_KERNEL);length = ncfg * sizeof(char *);dev->rawdescriptors = kzalloc(length, GFP_KERNEL);buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);desc = (struct usb_config_descriptor *)buffer;result = 0;for (; cfgno < ncfg; cfgno++) {/* We grab just the first descriptor so we know how long the whole configuration is */result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE);/* 长度为当前配置所有描述符的长度 */length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE);/* Now that we know the length, get the whole thing */bigbuffer = kmalloc(length, GFP_KERNEL);<span style="white-space:pre"></span>/* 获取描述符 */result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);dev->rawdescriptors[cfgno] = bigbuffer;/* 解析配置描述符 */result = usb_parse_configuration(&dev->dev, cfgno, &dev->config[cfgno], bigbuffer, length);}result = 0;return result;}至此,所有的描述符获取完毕。
三、URB
URB(USB Request Block,USB请求块)是USB数据传机制使用的核心数据结构。URB供USB协议栈使用。URB在include/linux/usb.h 文件中定义。
struct urb {struct kref kref;/* reference count of the URB */...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 */...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 */};URB 使用分三步,分配内存,初始化,提交。URB的内存分配是调用 usb_alloc_urb()方法来分配,该函数分配内存并将其至零,之后初始化URB相关的kobject和用于保护的URB自旋锁。USB核心提供下列辅助函数来完成URB的初始化工作。
usb_fill_[int|control|bulk]_urb(struct urb * urb, // URB pointerstruct usb_device * dev, // USB device structureunsigned int pipe, // pipe encodingvoid * transfer_buffer, // Buffer for I/Oint buffer_length, // I/O Buffer lengthusb_complete_t complete_fn, // Callback routinevoid * context, // For usb by completion_fnint interval// For int URBS only)complete_fn 是回调函数,回调函数在URB提交过程后被调用,负责检查提交状态、释放传输输出缓冲区等。为了提交URB以便进行数据传输,需要调用 usb_submit_urb()函数。该函数异步提交URB。
USB 核心也提供了公布提交 URB 的接口函数:
usb_[interrupt|control|bulk]_msg(struct usb_device * usb_dev, unsigned int pipe, void * data, int len, int * actual_length, int timeout)创建一个URB 之后提交,如果没有成功则会一直等待。该函数不需要传递回调函数地址,一个通用的完成回调函数将会实现此功能。也不需要另外创建和初始化,因为这个函数在没有增加任何开销的情况下连这些都已经做了。
URB 的任务完成以后,usb_free_urb()函数释放该实例。usb_unlink_urb()取消一个等待处理的URB.
四、管道
管道包含以下几部分:
断点地址;
数据传输方向;
数据传输模式:控制模式、中断模式、批量模式、实时模式;
管道是URB的重要成员,为USB数据传输提供地址信息。USB核心提供现成的宏来创建管道。
usb_[rcv|snd][ctrl|int|bulk|isoc]pipe(struct usb_device *usb_dev,_u8 endpointAddress)
五、传输模式
控制传输模式:用来传送外设和主机之间的控制、状态、配置等信息
批量传输模式:传输大量延时要求不高的数据
中断传输模式:传输数据量小,但是对传输延时要求较高的的情况,比如键盘
实时传输模式:传输实时数据,传输速率要预先可知
- USB驱动——描述符、URB、管道
- USB驱动程序(二)————USB描述符、URB、管道
- USB驱动——描述符
- Linux USB驱动中URB的使用
- linux usb驱动中的urb详解
- USB驱动之描述符
- USB请求块(URB)——框架及机制
- USB URB
- USB URB
- USB URB
- USB urb
- USB设备驱动6:usb HID 报告描述符
- USB请求块(URB)
- USB 的 Urb
- /Documentation/usb/URB.txt
- usb子系统浅析--urb
- usb urb接口
- usb设计中的管道pipe描述
- 使用PreparedStatement操作数据库
- MySQL高级
- gnl总结(#,%,$)
- CentOS 7 使用阿里云的yum源
- 网页背景图不够大而重复显示的解决方案
- USB驱动——描述符、URB、管道
- 安卓的字体设置
- 编程的那些锯齿
- 11
- C/C++笔记(C语言重要问题,指针与数组篇)
- 70. Climbing Stairs
- hdu 5172 GTY's gay friends(线段树+前缀和)
- struts2拦截器interceptor的三种配置方法
- jvm类加载过程