标签:
大家常说,一个设备通常有多个配置,配置通常有多个接口,接口通常有多个端点。接口代表逻辑上的设备,比如声卡分为 录音和播放。访问设备时,访问的是某个接口(逻辑设备)。除了端点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_descriptor desc; // 配置描述符 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_descriptor desc; // 接口描述符 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_descriptor desc; // 端点描述符 struct list_head urb_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; }至此,所有的描述符获取完毕。
USB驱动——设备、配置、接口、设置、端点之前的关系以及它们的获取过程分析
标签:
原文地址:http://blog.csdn.net/lizuobin2/article/details/51953702