标签:
大家常说,一个设备通常有多个配置,配置通常有多个接口,接口通常有多个端点。接口代表逻辑上的设备,比如声卡分为 录音和播放。访问设备时,访问的是某个接口(逻辑设备)。除了端点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_devicestatic 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