本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
//增加主控制器的引用计数
if (!usb_get_hcd(bus_to_hcd(bus))) {
kfree(dev);
return NULL;
}
/* Root hubs aren't true devices, so don't allocate HCD resources */
if (usb_hcd->driver->alloc_dev && parent &&
!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
usb_put_hcd(bus_to_hcd(bus));
kfree(dev);
return NULL;
}
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.groups = usb_device_groups;
//主控器能否进行DMA传输
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
//表示设备已经连接到usb接口上,是hub检测到设备时的初始状态
dev->state = USB_STATE_ATTACHED;
atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
//端点0需要特殊化处理
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
//端点0是双向的,既可以收也可以发.所以对它,我们需要以ep_in[0]和ep_out[0]来记录.
usb_enable_endpoint(dev, &dev->ep0, false);
dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
* string is a path along hub ports, from the root. Each device's
* dev->devpath will be stable until USB is re-cabled, and hubs
* are often labeled with these port numbers. The name isn't
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
//如果是root hub,name设置为usb0
if (unlikely(!parent)) {
dev->devpath[0] = '0';
dev->route = 0;
dev->dev.parent = bus->controller;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
//设备连接的那个hub是直接连到root hub上的,则dev->devpath就等于端口号
if (parent->devpath[0] == '0') {
snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
/* Root ports are not counted in route string */
dev->route = 0;
} else { //dev->devpath就等于在父hub的devpath基础上加一个‘.’再加一个端口号
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
/* Route string assumes hubs have less than 16 ports */
if (port1 < 15)
dev->route = parent->route +
(port1 << ((parent->level - 1)*4));
else
dev->route = parent->route +
(15 << ((parent->level - 1)*4));
}
dev->dev.parent = &parent->dev;
//名字设置,例如为0-2.2
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
/* hub driver sets up TT records */
}
dev->portnum = port1;
dev->bus = bus;
dev->parent = parent;
//usbfs用到
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
//设置延时调用函数usb_autoresume_work
INIT_WORK(&dev->autoresume, usb_autoresume_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
#endif
if (root_hub) /* Root hub always ok [and always wired] */ //root hub的值为1
dev->authorized = 1;
else {
//取决于设备链接的那个hub的authorized_default的值
dev->authorized = usb_hcd->authorized_default;
dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
}
return dev;
}
调用函数register_root_hub,register_root_hub函数如下:
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
struct usb_device *usb_dev = hcd->self.root_hub;
//将root hub的设备号devnum设置为1
const int devnum = 1;
int retval;
usb_dev->devnum = devnum;
usb_dev->bus->devnum_next = devnum + 1;
memset (&usb_dev->bus->devmap.devicemap, 0,
sizeof usb_dev->bus->devmap.devicemap);
set_bit (devnum, usb_dev->bus->devmap.devicemap);
//将root hub的状态设置为USB_STATE_ADDRESS
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
mutex_lock(&usb_bus_list_lock);
//将root hub端口0的最大字符长度设置为64
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
//获取root hub的设备描述符,长度是18个字节
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) {
mutex_unlock(&usb_bus_list_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
retval = usb_new_device (usb_dev);
if (retval) {
dev_err (parent_dev, "can't register root hub for %s, %d\n",
dev_name(&usb_dev->dev), retval);
}
mutex_unlock(&usb_bus_list_lock);
if (retval == 0) {
spin_lock_irq (&hcd_root_hub_lock);
//root hub 已经注册了
hcd->rh_registered = 1;
spin_unlock_irq (&hcd_root_hub_lock);
/* Did the HC die before the root hub was registered? */
if (hcd->state == HC_STATE_HALT)
usb_hc_died (hcd); /* This time clean up */
}
return retval;
}
void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state)
{
unsigned long flags;
spin_lock_irqsave(&device_state_lock, flags);
//设备已经断开了,啥都不做
if (udev->state == USB_STATE_NOTATTACHED)
; /* do nothing */
else if (new_state != USB_STATE_NOTATTACHED) {
/* root hub wakeup capabilities are managed out-of-band
* and may involve silicon errata ... ignore them here.
*/
//如果是root hub 不走这里
if (udev->parent) {
//如果原来的状态是USB_STATE_SUSPENDED,现在设置的状态也是USB_STATE_SUSPENDED,什么都不做
if (udev->state == USB_STATE_SUSPENDED
|| new_state == USB_STATE_SUSPENDED)
; /* No change to wakeup settings */
//如果设置的状态是USB_STATE_CONFIGURED,调用device_init_wakeup函数
//bmAttributes,的D5表明的就是一个USB设备是否具有被唤醒的能力(USB_CONFIG_ATT_WAKEUP = 1<<5)
else if (new_state == USB_STATE_CONFIGURED)
device_init_wakeup(&udev->dev,
(udev->actconfig->desc.bmAttributes
& USB_CONFIG_ATT_WAKEUP));
//先不打开这个设备的wakeup能力
else
device_init_wakeup(&udev->dev, 0);
}
if (udev->state == USB_STATE_SUSPENDED &&
new_state != USB_STATE_SUSPENDED)
udev->active_duration -= jiffies;
else if (new_state == USB_STATE_SUSPENDED &&
udev->state != USB_STATE_SUSPENDED)
udev->active_duration += jiffies;
udev->state = new_state;
} else //原来的状态不是USB_STATE_NOTATTACHED而现在要设置成USB_STATE_NOTATTACHED
recursively_mark_NOTATTACHED(udev); //递归的把各设备都设置成NOTATTACHED状态
spin_unlock_irqrestore(&device_state_lock, flags);
}
将root hub端口0的最大字符长度设置为64
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);cpu_to_le16这个函数是把一个数字转化成小端存放在内存中,因为usb的描述符都是按照小端存储的。
获取root hub的设备描述符,长度是18个字节
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
{
……
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
if (ret >= 0)
memcpy(&dev->descriptor, desc, size);
}
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;
}
上面通过usb_control_msg函数获取设备描述符,循环了三次,以防有的设备一次不能成功。
看一下usb_control_msg函数的原型:
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)
dev:usb设备
pipe:管道
管道有8种类型:
usb_sndctrlpipe(dev,endpoint)=((2 << 30) | (dev->devnum << 8) | (endpoint << 15)
usb_rcvctrlpipe(dev,endpoint) =((2 << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
usb_sndisocpipe(dev,endpoint)=((0 << 30) | (dev->devnum << 8) | (endpoint << 15)
usb_rcvisocpipe(dev,endpoint)=((0 << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
usb_sndbulkpipe(dev,endpoint)=((3 << 30) | (dev->devnum << 8) | (endpoint << 15)
usb_rcvbulkpipe(dev,endpoint)=((3 << 30) |(dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
usb_sndintpipe(dev,endpoint) =((1 << 30) | (dev->devnum << 8) | (endpoint << 15)
usb_rcvintpipe(dev,endpoint)=((1 << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
request:
表示具体是哪个request,如下
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
requesttype:
bit7就表示了控制传输中DATA transaction阶段的方向
#define USB_DIR_OUT 0 /* to device /
#define USB_DIR_IN 0x80 / to host */
bit5~6表示request的类型,是标准的,class-specific的还是vendor-specific的
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
bit0~4表示了这个请求针对的是设备,接口,还是端点
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
value:
这个字段是request的参数,request不同,wValue就不同
index:
bRequestType指明request针对的是设备上的某个接口或端点的时候,wIndex就用来指明是哪个接口或端点
data:
请求buffer
size:
请求buffer的大小
timeout:
请求超时时间
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)
{
struct usb_ctrlrequest *dr;
int ret;
//为一个struct usb_ctrlrequest结构体申请了内存
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
//bit7就表示了控制传输中DATA transaction阶段的方向
//bit5~6表示request的类型,是标准的,class-specific的还是vendor-specific的
//bit0~4表示了这个请求针对的是设备,接口,还是端点
dr->bRequestType = requesttype;
//表示具体是哪个request
//对于刚开始提到的SET_ADDRESS来说,bRequest的值就是USB_REQ_SET_ADDRESS
dr->bRequest = request;
//这个字段是request的参数,request不同,wValue就不同
//对于刚开始提到的SET_ADDRESS,wValue就是之前hub已经你的设备指定好的devnum
dr->wValue = cpu_to_le16(value);
//也是request的参数,bRequestType指明request针对的是设备上的某个接口或端点的时候,wIndex就用来指明是哪个接口或端点
dr->wIndex = cpu_to_le16(index);
//控制传输中DATA transaction阶段的长度,方向已经在bRequestType那儿指明了。如果这个值为0,
//就表示没有DATA transaction阶段,bRequestType的方向位也就无效了
dr->wLength = cpu_to_le16(size);
/* dbg("usb_control_msg"); */
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
上面的函数调用usb_internal_control_msg函数
static int usb_internal_control_msg(struct usb_device *usb_dev,unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
//创建一个urb
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
//初始化一个控制urb,urb被创建之后,使用之前必须要正确的初始化
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
//将urb提交给咱们的usb core,以便分配给特定的主机控制器驱动进行处理,然后默默的等待处理结果,或者超时
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
调用usb_start_wait_urb函数
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
//ctx.completion是内核里一个比较简单的同步机制,一个线程可以通过它来通知另外一个线程某件事情已经做完了
struct api_context ctx;
unsigned long expire;
int retval;
init_completion(&ctx.done);
urb->context = &ctx;
urb->actual_length = 0;
//提交urb,并返回一个值表示是否提交成功了
retval = usb_submit_urb(urb, GFP_NOIO);
if (unlikely(retval))
goto out;
//函数wait_for_completion_timeout里的超时参数是必须以jiffy为单位的
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
//设定一个超时时间,等候usb core和HCD的处理结果。
//urb代表的控制传输完成之后会调用结束处理函数usb_api_blocking_completion,
//从而调用complete来通知usb_start_wait_urb说不用再等了,传输已经完成了
if (!wait_for_completion_timeout(&ctx.done, expire)) {
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%u/%u\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
retval = ctx.status;
out:
if (actual_length)
//用来记录实际传输的数据长度
*actual_length = urb->actual_length;
usb_free_urb(urb);
return retval;
}
调用usb_start_wait_urb函数提交一个urb到hcd,没有阻塞,直接返回。然后wait_for_completion_timeout函数来等待。
usb_fill_control_urb函数中,将usb_api_blocking_completion设置为urb的complete函数。urb代表的控制传输完成之后会调用结束处理函数usb_api_blocking_completion,usb_api_blocking_completion函数中将tx->done++,wait_for_completion_timeout函数满足条件退出等待。
那么urb通过usb_submit_urb函数提交给了hcd处理。
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
……
usb_hcd_submit_urb(urb, mem_flags)
//root hub调用rh_urb_enqueue进行USB通信
if (is_root_hub(urb->dev))
status = rh_urb_enqueue(hcd, urb);
//如果不是root hub,调用对应的控制器的urb_enqueue函数
else
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
}
usb_submit_urb最终调用的是rh_urb_enqueue函数。
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
//如果是中断传输
if (usb_endpoint_xfer_int(&urb->ep->desc))
return rh_queue_status (hcd, urb);
//如果是控制传输
if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
return -EINVAL;
}
rh_urb_enqueue 调用的又是rh_call_control 函数。
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
{
……
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch (wValue & 0xff00) {
case USB_DT_DEVICE << 8:
switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB3:
bufp = usb3_rh_dev_descriptor;
break;
case HCD_USB2:
bufp = usb2_rh_dev_descriptor;
break;
case HCD_USB11:
bufp = usb11_rh_dev_descriptor;
break;
default:
goto error;
}
len = 18;
if (hcd->has_tt)
patch_protocol = 1;
break;
case USB_DT_CONFIG << 8:
switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB3:
bufp = ss_rh_config_descriptor;
len = sizeof ss_rh_config_descriptor;
break;
case HCD_USB2:
bufp = hs_rh_config_descriptor;
len = sizeof hs_rh_config_descriptor;
break;
case HCD_USB11:
bufp = fs_rh_config_descriptor;
len = sizeof fs_rh_config_descriptor;
break;
default:
goto error;
}
if (device_can_wakeup(&hcd->self.root_hub->dev))
patch_wakeup = 1;
break;
case USB_DT_STRING << 8:
if ((wValue & 0xff) < 4)
urb->actual_length = rh_string(wValue & 0xff,
hcd, ubuf, wLength);
else /* unsupported IDs --> "protocol stall" */
goto error;
break;
default:
goto error;
}
break;
}
usb3_rh_dev_descriptor,usb2_rh_dev_descriptor,ss_rh_config_descriptor等都是定义在hcd.c里面的全局变量。因为root hub是集成在主机控制器里面了,所以跟主机控制器通信获取root hub的信息实际上驱动软件里面写死了,而不是获取的硬件上的信息。
/* usb 1.1 root hub device descriptor */
static const u8 usb11_rh_dev_descriptor [18] = {
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x10, 0x01, /* __le16 bcdUSB; v1.1 */
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
0x01, 0x00, /* __le16 idProduct; device 0x0001 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
static const u8 ss_rh_config_descriptor[] = {
/* one configuration */
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, 0x00, /* __le16 wTotalLength; FIXME */
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0xc0, /* __u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
/* one interface */
0x09, /* __u8 if_bLength; */
0x04, /* __u8 if_bDescriptorType; Interface */
0x00, /* __u8 if_bInterfaceNumber; */
0x00, /* __u8 if_bAlternateSetting; */
0x01, /* __u8 if_bNumEndpoints; */
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* __u8 if_bInterfaceSubClass; */
0x00, /* __u8 if_bInterfaceProtocol; */
0x00, /* __u8 if_iInterface; */
/* one endpoint (status change endpoint) */
0x07, /* __u8 ep_bLength; */
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
/* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
* see hub.c:hub_configure() for details. */
(USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
/*
* All 3.0 hubs should have an endpoint companion descriptor,
* but we're ignoring that for now. FIXME?
*/
};
根据上面的描述信息,可以得到:
root hub只有一种配置,一个接口,一种设置,一个端口;
DeviceClass = 0x9;
InterfaceClass = 0x09;
配置描述符的总长度是25;
设备描述符的长度是18;
最终得到的设备描述符信息保存在dev->descriptor结构体中。
int usb_new_device(struct usb_device *udev)
{
int err;
/* Increment the parent's count of unsuspended children */
//如果该设备不是Root Hub,则调用usb_autoresume_device(),唤醒它的父设备
if (udev->parent)
usb_autoresume_device(udev->parent);
//usb_detect_quirks会为在黑名单中找得到的设备的struct usb_device结构体中的quirks赋值
usb_detect_quirks(udev); /* Determine quirks */
//获得配置描述符
err = usb_configure_device(udev); /* detect & probe dev/intfs */
if (err < 0)
goto fail;
//一些打印信息
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* export the usbdev device-node for libusb */
//minor=((dev->bus->busnum-1)*128)+(dev->devnum-1);
//USB_DEVICE_MAJOR = 189
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* Tell the world! */
//打印厂家信息
announce_device(udev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others).
*/
//添加设备
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
usb_stop_pm(udev);
return err;
}
看一下usb_configure_device函数
static int usb_configure_device(struct usb_device *udev)
{
int err;
if (udev->config == NULL) {
//获得各个配置的配置描述符
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
}
if (udev->wusb == 1 && udev->authorized == 0) {
udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
}
else {
/* read the standard strings and cache them if present */
udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
udev->manufacturer = usb_cache_string(udev,
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
}
err = usb_configure_device_otg(udev);
fail:
return err;
}
usb_configure_device函数调用usb_get_configuration获取配置信息。根据设备描述符知道有多少个配置。然后for循环,读取每一个配置描述符。在配置描述符里面有一个成员wTotalLength,它表示配置信息的总长(包括配置,接口,端点和设备类及厂商定义的描述符)。有了这个长度,我们可以把所有的配置信息全部读出来。读出来后,我们可以知道每个配置里面有几个接口,每个接口里面有几个设置,每个设置里面有几个端口,挨个挨个去解析,然后把解析出来的信息保存起来。
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 (dev->authorized == 0) /* Not really an error */
goto out_not_authorized;
result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
if (ncfg < 1) {
dev_err(ddev, "no configurations\n");
return -EINVAL;
}
//申请内存,存放ncfg个配置
length = ncfg * sizeof(struct usb_host_config);
dev->config = kzalloc(length, GFP_KERNEL);
if (!dev->config)
goto err2;
length = ncfg * sizeof(char *);
dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
if (!dev->rawdescriptors)
goto err2;
//因为usb_config_descriptor的长度是9,申请9个字节的buffer存放usb_config_descriptor
buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
if (!buffer)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
result = 0;
//循环读出ncfg个config
for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
//读取config文件,类型是USB_DT_CONFIG,长度是9个字节
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
} else if (result < 4) { //为什么是小于4呢,因为wTotalLength所在的位置刚好是第四个字节,
//把wTotalLength读出来了后面的都可以出来
dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno,
USB_DT_CONFIG_SIZE, result);
result = -EINVAL;
goto err;
}
length = max((int) le16_to_cpu(desc->wTotalLength),
USB_DT_CONFIG_SIZE);
//length是所有描述符的总长度,申请buffer
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
result = -ENOMEM;
goto err;
}
//获取config描述符获取后面所有的描述符数据
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "all");
kfree(bigbuffer);
goto err;
}
if (result < length) {
dev_warn(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, length, result);
length = result;
}
dev->rawdescriptors[cfgno] = bigbuffer;
//解析所有的描述符
result = usb_parse_configuration(&dev->dev, cfgno,
&dev->config[cfgno], bigbuffer, length);
if (result < 0) {
++cfgno;
goto err;
}
}
result = 0;
err:
kfree(buffer);
out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
dev_err(ddev, "out of memory\n");
return result;
}
解析读出来的描述符信息,调用函数usb_parse_configuration
static int usb_parse_configuration(struct device *ddev, int cfgidx, struct usb_host_config *config,
unsigned char *buffer, int size)
{
unsigned char *buffer0 = buffer;
int cfgno;
int nintf, nintf_orig;
int i, j, n;
struct usb_interface_cache *intfc;
unsigned char *buffer2;
int size2;
struct usb_descriptor_header *header;
int len, retval;
u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
unsigned iad_num = 0;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
//做一些参数判断,desc.bDescriptorType = 2, desc.bLength = 9
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
config->desc.bLength < USB_DT_CONFIG_SIZE) {
dev_err(ddev, "invalid descriptor for config index %d: "
"type = 0x%X, length = %d\n", cfgidx,
config->desc.bDescriptorType, config->desc.bLength);
return -EINVAL;
}
//保存当前配置的配置号
cfgno = config->desc.bConfigurationValue;
//usb_config_descriptor解析完了,跳过usb_config_descriptor去解析后面的数据
buffer += config->desc.bLength;
size -= config->desc.bLength;
//获取usb_config_descriptor里面包含几个usb_interface_descriptor,最多可以有32个
nintf = nintf_orig = config->desc.bNumInterfaces;
if (nintf > USB_MAXINTERFACES) {
dev_warn(ddev, "config %d has too many interfaces: %d, "
"using maximum allowed: %d\n",
cfgno, nintf, USB_MAXINTERFACES);
nintf = USB_MAXINTERFACES;
}
/* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */
n = 0;
//统计一下这个配置里每个接口所拥有的设置数目
for ((buffer2 = buffer, size2 = size);
size2 > 0;
(buffer2 += header->bLength, size2 -= header->bLength)) {
if (size2 < sizeof(struct usb_descriptor_header)) {
dev_warn(ddev, "config %d descriptor has %d excess "
"byte%s, ignoring\n",
cfgno, size2, plural(size2));
break;
}
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
break;
}
//某个接口拥有一个设置,是没有设置描述符
if (header->bDescriptorType == USB_DT_INTERFACE) {
struct usb_interface_descriptor *d;
int inum;
//header代表的就是usb_interface_descriptor
d = (struct usb_interface_descriptor *) header;
if (d->bLength < USB_DT_INTERFACE_SIZE) {
dev_warn(ddev, "config %d has an invalid "
"interface descriptor of length %d, "
"skipping\n", cfgno, d->bLength);
continue;
}
//usb_interface_descriptorde的索引值,不是表示个数
inum = d->bInterfaceNumber;
if (inum >= nintf_orig)
dev_warn(ddev, "config %d has an invalid "
"interface number: %d but max is %d\n",
cfgno, inum, nintf_orig - 1);
/* Have we already encountered this interface?
* Count its altsettings */
//把索引值inum保存在inums数组里面
for (i = 0; i < n; ++i) {
if (inums[i] == inum)
break;
}
if (i < n) {
if (nalts[i] < 255)
++nalts[i];
} else if (n < USB_MAXINTERFACES) {
//记录一个接口号
inums[n] = inum;
//记录的是每个接口拥有的设置数目
nalts[n] = 1;
++n;
}
} else if (header->bDescriptorType ==
USB_DT_INTERFACE_ASSOCIATION) {
if (iad_num == USB_MAXIADS) {
dev_warn(ddev, "found more Interface "
"Association Descriptors "
"than allocated for in "
"configuration %d\n", cfgno);
} else {
config->intf_assoc[iad_num] =
(struct usb_interface_assoc_descriptor
*)header;
iad_num++;
}
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
dev_warn(ddev, "config %d contains an unexpected "
"descriptor of type 0x%X, skipping\n",
cfgno, header->bDescriptorType);
} /* for ((buffer2 = buffer, size2 = size); ...) */
//在上面的循环中,过滤掉了错误的数据,得到实际上有效的长度size,desc.wTotalLength
size = buffer2 - buffer;
config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);
//得到的usb_interface_descriptor的个数应该等于usb_config_descriptor.bNumInterfaces,不相等的话是有问题的
if (n != nintf)
dev_warn(ddev, "config %d has %d interface%s, different from "
"the descriptor's value: %d\n",
cfgno, n, plural(n), nintf_orig);
//如果没有找到usb_interface_descriptor,也是有问题的
else if (n == 0)
dev_warn(ddev, "config %d has no interfaces?\n", cfgno);
config->desc.bNumInterfaces = nintf = n;
/* Check for missing interface numbers */
for (i = 0; i < nintf; ++i) {
for (j = 0; j < nintf; ++j) {
if (inums[j] == i)
break;
}
if (j >= nintf)
dev_warn(ddev, "config %d has no interface number "
"%d\n", cfgno, i);
}
/* Allocate the usb_interface_caches and altsetting arrays */
for (i = 0; i < nintf; ++i) {
j = nalts[i];
if (j > USB_MAXALTSETTING) {
dev_warn(ddev, "too many alternate settings for "
"config %d interface %d: %d, "
"using maximum allowed: %d\n",
cfgno, inums[i], j, USB_MAXALTSETTING);
nalts[i] = j = USB_MAXALTSETTING;
}
//为每一个interface申请内存,内存大小为sizeof(*intfc) + n个usb_host_interface,
//intfc.altsetting[0]是第一个usb_host_interface的地址
len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
if (!intfc)
return -ENOMEM;
kref_init(&intfc->ref);
}
/* FIXME: parse the BOS descriptor */
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first interface descriptor */
config->extra = buffer;
//找到第一个usb_interface_descriptor出现的位置,上面的只是为了统计usb_interface_descriptor的个数
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
USB_DT_INTERFACE, &n);
config->extralen = i;
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, plural(n), "configuration");
//buffer指针跳到第一个usb_interface_descriptor出现的位置
buffer += i;
size -= i;
/* Parse all the interface/altsetting descriptors */
//解析所有的 interface/altsetting
while (size > 0) {
retval = usb_parse_interface(ddev, cfgno, config,
buffer, size, inums, nalts);
if (retval < 0)
return retval;
buffer += retval;
size -= retval;
}
/* Check for missing altsettings */
for (i = 0; i < nintf; ++i) {
intfc = config->intf_cache[i];
for (j = 0; j < intfc->num_altsetting; ++j) {
for (n = 0; n < intfc->num_altsetting; ++n) {
if (intfc->altsetting[n].desc.
bAlternateSetting == j)
break;
}
if (n >= intfc->num_altsetting)
dev_warn(ddev, "config %d interface %d has no "
"altsetting %d\n", cfgno, inums[i], j);
}
}
return 0;
}
解析接口描述符函数usb_parse_interface
static int usb_parse_interface(struct device *ddev, int cfgno,
struct usb_host_config *config, unsigned char *buffer, int size,
u8 inums[], u8 nalts[])
{
unsigned char *buffer0 = buffer;
struct usb_interface_descriptor *d;
int inum, asnum;
struct usb_interface_cache *intfc;
struct usb_host_interface *alt;
int i, n;
int len, retval;
int num_ep, num_ep_orig;
d = (struct usb_interface_descriptor *) buffer;
//buffer指针跳过usb_interface_descriptor的长度,usb_interface_descriptor的长度为9
buffer += d->bLength;
size -= d->bLength;
if (d->bLength < USB_DT_INTERFACE_SIZE)
goto skip_to_next_interface_descriptor;
/* Which interface entry is this? */
intfc = NULL;
//有可能inum[0] = 1, inum[1] = 0
inum = d->bInterfaceNumber;
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
if (inums[i] == inum) {
intfc = config->intf_cache[i];
break;
}
}
if (!intfc || intfc->num_altsetting >= nalts[i])
goto skip_to_next_interface_descriptor;
/* Check for duplicate altsetting entries */
asnum = d->bAlternateSetting;
//usb_interface_descriptor接口使用的是哪个可选设置
for ((i = 0, alt = &intfc->altsetting[0]);
i < intfc->num_altsetting;
(++i, ++alt)) {
//说明已经解析过了,就不用解析,跳到下一个
if (alt->desc.bAlternateSetting == asnum) {
dev_warn(ddev, "Duplicate descriptor for config %d "
"interface %d altsetting %d, skipping\n",
cfgno, inum, asnum);
goto skip_to_next_interface_descriptor;
}
}
//设置个数加1
++intfc->num_altsetting;
//把解析出来的usb_interface_descriptor拷贝到intfc->altsetting[i].desc里面去
memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first endpoint or interface descriptor */
alt->extra = buffer;
//这里find_next_descriptor的dt1参数和dt2参数就不再一样了,因为如果一个接口只用到端点0,
//它的接口描述符后边儿是不会跟有端点描述符的
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
alt->extralen = i;
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, plural(n), "interface");
buffer += i;
size -= i;
/* Allocate space for the right(?) number of endpoints */
//获取这个设置的端点数目
num_ep = num_ep_orig = alt->desc.bNumEndpoints;
alt->desc.bNumEndpoints = 0; /* Use as a counter */
if (num_ep > USB_MAXENDPOINTS) {
dev_warn(ddev, "too many endpoints for config %d interface %d "
"altsetting %d: %d, using maximum allowed: %d\n",
cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);
num_ep = USB_MAXENDPOINTS;
}
if (num_ep > 0) {
/* Can't allocate 0 bytes */
//申请内存,申请大小为num_ep个usb_host_endpoint
len = sizeof(struct usb_host_endpoint) * num_ep;
alt->endpoint = kzalloc(len, GFP_KERNEL);
if (!alt->endpoint)
return -ENOMEM;
}
/* Parse all the endpoint descriptors */
n = 0;
while (size > 0) {
//判断find_next_descriptor找到的地址的描述符是不是接口描述符,
//如果是直接退出while循环,否则解析完所有的usb_host_endpoint
if (((struct usb_descriptor_header *) buffer)->bDescriptorType
== USB_DT_INTERFACE)
break;
//解析usb_host_endpoint
retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,
num_ep, buffer, size);
if (retval < 0)
return retval;
++n;
//调整buffer的位置和size大小
buffer += retval;
size -= retval;
}
//判断解析出来的usb_host_endpoint的个数,肯定要是num_ep_orig个
if (n != num_ep_orig)
dev_warn(ddev, "config %d interface %d altsetting %d has %d "
"endpoint descriptor%s, different from the interface "
"descriptor's value: %d\n",
cfgno, inum, asnum, n, plural(n), num_ep_orig);
return buffer - buffer0;
skip_to_next_interface_descriptor:
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
USB_DT_INTERFACE, NULL);
return buffer - buffer0 + i;
}
端口描述符解析函数usb_parse_endpoint
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
int asnum, struct usb_host_interface *ifp, int num_ep,
unsigned char *buffer, int size)
{
unsigned char *buffer0 = buffer;
struct usb_endpoint_descriptor *d;
struct usb_host_endpoint *endpoint;
int n, i, j, retval;
d = (struct usb_endpoint_descriptor *) buffer;
//跳过usb_endpoint_descriptor的大小
buffer += d->bLength;
size -= d->bLength;
//usb_endpoint_descriptor的大小7 or 9,后面多了2个字节,是对音频扩展的
if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)
n = USB_DT_ENDPOINT_AUDIO_SIZE;
else if (d->bLength >= USB_DT_ENDPOINT_SIZE)
n = USB_DT_ENDPOINT_SIZE;
else {
dev_warn(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint descriptor of length %d, skipping\n",
cfgno, inum, asnum, d->bLength);
goto skip_to_next_endpoint_or_interface_descriptor;
}
//得到端口地址
i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
if (i >= 16 || i == 0) {
dev_warn(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
}
/* Only store as many endpoints as we have room for */
//ifp->desc.bNumEndpoints这个值在前面被赋值成0了
if (ifp->desc.bNumEndpoints >= num_ep)
goto skip_to_next_endpoint_or_interface_descriptor;
//ifp->desc.bNumEndpoints这个值在前面被赋值成0了,把发现的usb_endpoint_descriptor一个一个赋值到endpoint->desc里面去
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
++ifp->desc.bNumEndpoints;
//把发现的usb_endpoint_descriptor一个一个赋值到endpoint->desc里面去
memcpy(&endpoint->desc, d, n);
INIT_LIST_HEAD(&endpoint->urb_list);
/* Fix up bInterval values outside the legal range. Use 32 ms if no
* proper value can be guessed. */
i = 0; /* i = min, j = max, n = default */
j = 255;
//如果是中断传输模式
if (usb_endpoint_xfer_int(d)) {
i = 1;
//判断速度
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_HIGH:
/* Many device manufacturers are using full-speed
* bInterval values in high-speed interrupt endpoint
* descriptors. Try to fix those and fall back to a
* 32 ms default value otherwise. */
n = fls(d->bInterval*8);
if (n == 0)
n = 9; /* 32 ms = 2^(9-1) uframes */
j = 16;
break;
default: /* USB_SPEED_FULL or _LOW */
/* For low-speed, 10 ms is the official minimum.
* But some "overclocked" devices might want faster
* polling so we'll allow it. */
n = 32;
break;
} //如果是等时传输
} else if (usb_endpoint_xfer_isoc(d)) {
i = 1;
j = 16;
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_HIGH:
n = 9; /* 32 ms = 2^(9-1) uframes */
break;
default: /* USB_SPEED_FULL */
n = 6; /* 32 ms = 2^(6-1) frames */
break;
}
}
if (d->bInterval < i || d->bInterval > j) {
dev_warn(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X has an invalid bInterval %d, "
"changing to %d\n",
cfgno, inum, asnum,
d->bEndpointAddress, d->bInterval, n);
endpoint->desc.bInterval = n;
}
//下面是根据不同的U盘的读写速度和传输模式给endpoint->desc赋值
/* Some buggy low-speed devices have Bulk endpoints, which is
* explicitly forbidden by the USB spec. In an attempt to make
* them usable, we will try treating them as Interrupt endpoints.
*/
if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
usb_endpoint_xfer_bulk(d)) {
dev_warn(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X is Bulk; changing to Interrupt\n",
cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
endpoint->desc.bInterval = 1;
if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
}
/*
* Some buggy high speed devices have bulk endpoints using
* maxpacket sizes other than 512. High speed HCDs may not
* be able to handle that particular bug, so let's warn...
*/
if (to_usb_device(ddev)->speed == USB_SPEED_HIGH
&& usb_endpoint_xfer_bulk(d)) {
unsigned maxp;
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
if (maxp != 512)
dev_warn(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n",
cfgno, inum, asnum, d->bEndpointAddress,
maxp);
}
/* Allocate room for and parse any SS endpoint companion descriptors */
if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
endpoint->extra = buffer;
i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
endpoint->extralen = i;
buffer += i;
size -= i;
/* Allocate space for the SS endpoint companion descriptor */
endpoint->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
GFP_KERNEL);
if (!endpoint->ss_ep_comp)
return -ENOMEM;
/* Fill in some default values (may be overwritten later) */
endpoint->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
endpoint->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
endpoint->ss_ep_comp->desc.bMaxBurst = 0;
/*
* Leave bmAttributes as zero, which will mean no streams for
* bulk, and isoc won't support multiple bursts of packets.
* With bursts of only one packet, and a Mult of 1, the max
* amount of data moved per endpoint service interval is one
* packet.
*/
if (usb_endpoint_xfer_isoc(&endpoint->desc) ||
usb_endpoint_xfer_int(&endpoint->desc))
endpoint->ss_ep_comp->desc.wBytesPerInterval =
endpoint->desc.wMaxPacketSize;
if (size > 0) {
retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, num_ep, buffer,
size);
if (retval >= 0) {
buffer += retval;
retval = buffer - buffer0;
}
} else {
dev_warn(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X has no "
"SuperSpeed companion descriptor\n",
cfgno, inum, asnum, d->bEndpointAddress);
retval = buffer - buffer0;
}
} else {
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
endpoint->extralen = i;
retval = buffer - buffer0 + i;
}
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, plural(n), "endpoint");
return retval;
skip_to_next_endpoint_or_interface_descriptor:
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, NULL);
return buffer - buffer0 + i;
}
所有解析出来的配置描述符信息保存在usb_device->usb_host_config[config_num].desc结构体里面,i是该配置的编号;
usb_device->usb_host_config[config_num].intf_cache[interface_num].altsetting[setting_num].desc保存每个接口描述符;
usb_device->usb_host_config[config_num].intf_cache[interface_num].altsetting[setting_num].endpoint[point_num].desc保存每个端口的描述符信息;
最后一步就是device_add添加root hub 设备。
文章参考:https://blog.csdn.net/fudan_abc/article/category/325189