标签:
本文以 2440-ohci 驱动为例,简单分析 USB 主机控制器驱动 根 Hub 的注册过程,以及 USB设备的枚举过程,并不涉及USB协议,单纯分析驱动框架流程。无论是hub还是普通的usb设备,它们注册到 usb_bus_type 都会经历两次 Match ,因为第一次注册进来时,是将整个设备作为一个 device 注册,然后在通用的 devices 驱动程序 usb_generic_driver 的 generic_probe 函数中,将该设备的所有接口进行设置并将这些接口注册到 usb_bus_type 。如果是Hub设备的接口,则会调用 hub_probe,如果是其他设备则调用 xx_probe 函数。如果是 Hub 的话,usb主机会监测hub端口变化,如果有变化会分配一个usb_devices 注册到 usb_bus_type 重复前边的步骤。
首先,整个驱动框架的开始,是基于 platform 平台总线的。
struct platform_device s3c_device_usb = { .name = "s3c2410-ohci", .id = -1, .num_resources = ARRAY_SIZE(s3c_usb_resource), .resource = s3c_usb_resource, .dev = { .dma_mask = &s3c_device_usb_dmamask, .coherent_dma_mask = 0xffffffffUL } };
static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ /*.resume = ohci_hcd_s3c2410_drv_resume, */ .driver = { .owner = THIS_MODULE, .name = "s3c2410-ohci", }, };platform 平台总线模型,这里定义了 platform_device 和 platform_driver ,后面将这俩注册到 platform_bus_type 时,就会根据它们的名字来匹配,显然,它们的名字都是 “s3c2410-ohci” ,匹配成功后,便会调用到 ohci_hcd_s3c2410_drv_probe 函数。在看 probe 函数之前,我们先看看设备侧提供的信息。
static struct resource s3c_usb_resource[] = { [0] = { .start = S3C_PA_USBHOST, .end = S3C_PA_USBHOST + 0x100 - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_USBH, .end = IRQ_USBH, .flags = IORESOURCE_IRQ, } };resource 中指定了 2440 主机控制器的寄存器范围,以及中断。
int usb_simtec_init(void) { s3c_device_usb.dev.platform_data = &usb_simtec_info; } static struct s3c2410_hcd_info usb_simtec_info = { .port[0] = { .flags = S3C_HCDFLG_USED }, .port[1] = { .flags = S3C_HCDFLG_USED }, .power_control = usb_simtec_powercontrol, .enable_oc = usb_simtec_enableoc, };这里,指定了一些额外的信息,保存在 dev.platform_data 中,后边我们再来看他们是干什么用的。下面来看 probe 函数。
static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev) { return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev); }
static int usb_hcd_s3c2410_probe (const struct hc_driver *driver, struct platform_device *dev) { struct usb_hcd *hcd = NULL; int retval; /* 设置GPG4输出1 mini2440 jz2440好像均不需要 */ s3c2410_usb_set_power(dev->dev.platform_data, 1, 1); s3c2410_usb_set_power(dev->dev.platform_data, 2, 1); /* 创建usb_hcd 绑定 usb_driver等 */ hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx"); /* 主机控制寄存器 起始地址 结束地址 */ hcd->rsrc_start = dev->resource[0].start; hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; /* 申请IO空间 */ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { ... } /* 获得usb-host 时钟 */ clk = clk_get(&dev->dev, "usb-host"); /* 获得 usb-bus-host 时钟 */ usb_clk = clk_get(&dev->dev, "usb-bus-host"); /* 使能时钟 使能过流检查 */ s3c2410_start_hc(dev, hcd); /* Ioremap */ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED); return 0; }前边第一个 probe 函数仅仅是一个中转,usb_hcd_s3c2410_probe 它才是真正的 probe 函数,主要工作就是分配一个 usb_hcd 结构、设置然后 usb_add_hcd 。
struct usb_hcd { /* * housekeeping */ struct usb_bus self; /* hcd is-a bus */ struct kref kref; /* reference counter */ const char *product_desc; /* product/vendor string */ char irq_descr[24]; /* driver + bus # */ struct timer_list rh_timer; /* drives root-hub polling */ struct urb *status_urb; /* the current status urb */ #ifdef CONFIG_PM struct work_struct wakeup_work; /* for remote wakeup */ #endif /* * hardware info/state */ const struct hc_driver *driver; /* hw-specific hooks */ /* Flags that need to be manipulated atomically */ unsigned long flags; #define HCD_FLAG_HW_ACCESSIBLE 0x00000001 #define HCD_FLAG_SAW_IRQ 0x00000002 unsigned rh_registered:1;/* is root hub registered? */ /* The next flag is a stopgap, to be removed when all the HCDs * support the new root-hub polling mechanism. */ unsigned uses_new_polling:1; unsigned poll_rh:1; /* poll for rh status? */ unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ unsigned authorized_default:1; unsigned has_tt:1; /* Integrated TT in root hub */ int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ u64 rsrc_start; /* memory/io resource start */ u64 rsrc_len; /* memory/io resource length */ unsigned power_budget; /* in mA, 0 = no limit */ #define HCD_BUFFER_POOLS 4 struct dma_pool *pool [HCD_BUFFER_POOLS]; int state; # define __ACTIVE 0x01 # define __SUSPEND 0x04 # define __TRANSIENT 0x80 # define HC_STATE_HALT 0 # define HC_STATE_RUNNING (__ACTIVE) # define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE) # define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT) # define HC_STATE_SUSPENDED (__SUSPEND) #define HC_IS_RUNNING(state) ((state) & __ACTIVE) #define HC_IS_SUSPENDED(state) ((state) & __SUSPEND) /* more shared queuing code would be good; it should support * smarter scheduling, handle transaction translators, etc; * input size of periodic table to an interrupt scheduler. * (ohci 32, uhci 1024, ehci 256/512/1024). */ /* The HC driver's private data is stored at the end of * this structure. */ unsigned long hcd_priv[0] __attribute__ ((aligned(sizeof(unsigned long)))); };usb_hcd —— USB Host Controller Driver,同时,一个主机控制器驱动对应一条 usb_bus 。
struct usb_bus { struct device *controller; /* host/master side hardware */ int busnum; /* Bus number (in order of reg) */ const char *bus_name; /* stable id (PCI slot_name etc) */ u8 uses_dma; /* Does the host controller use DMA? */ u8 otg_port; /* 0, or number of OTG/HNP port */ unsigned is_b_host:1; /* true during some HNP roleswitches */ unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ int devnum_next; /* Next open device number in * round-robin allocation */ struct usb_devmap devmap; /* device address allocation map */ struct usb_device *root_hub; /* Root hub */ struct list_head bus_list; /* list of busses */ int bandwidth_allocated; /* on this bus: how much of the time * reserved for periodic (intr/iso) * requests is used, on average? * Units: microseconds/frame. * Limits: Full/low speed reserve 90%, * while high speed reserves 80%. */ int bandwidth_int_reqs; /* number of Interrupt requests */ int bandwidth_isoc_reqs; /* number of Isoc. requests */ #ifdef CONFIG_USB_DEVICEFS struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ #endif #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ #endif };
hcd的分配过程
struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, const char *bus_name) { struct usb_hcd *hcd; /* 分配一个 usb_hcd + driver->hcd_priv_size 空间 */ hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); /* dev->p->driver_data = hcd; */ dev_set_drvdata(dev, hcd); kref_init(&hcd->kref); /* 初始化 usb_bus ,一个主机控制器对应一个 usb_bus */ usb_bus_init(&hcd->self); /* 设置 usb_bus */ hcd->self.controller = dev; hcd->self.bus_name = bus_name; hcd->self.uses_dma = (dev->dma_mask != NULL); /* 初始化 根Hub poll定时器 */ init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; #ifdef CONFIG_PM INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif /* 绑定 hc_driver */ hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; return hcd; }
static void usb_bus_init (struct usb_bus *bus) { memset (&bus->devmap, 0, sizeof(struct usb_devmap)); bus->devnum_next = 1; bus->root_hub = NULL; bus->busnum = -1; bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD (&bus->bus_list); }
整个Probe函数里干了那些事:
1、创建一个 usb_hcd
2、usb_bus_init ,初始化 usb_hcd 对应的 usb_bus ,bus->devmap 清零,根 Hub 指向 NULL等3、设置 usb_hcd.usb_bus
3.1 hcd.usb_bus.controller = s3c_device_usb.dev (最开始创建的平台device)
3.2 hcd.usb_bus.name = “s3c24xx”
4、设置 usb_hcd.rh_timer
5、设置 usb_hcd.driver = ohci_s3c2410_hc_driver
6、根据 resource 资源,设置usb_hcd.rsrc_start、usb_hcd.rsrc_len
7、使能时钟
8、ioremap 、申请 io 空间
9、usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED)
int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { int retval; struct usb_device *rhdev; /* 无线USB? */ hcd->authorized_default = hcd->wireless? 0 : 1; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); /* hcd->pool[i] = dma_pool_create(name, hcd->self.controller,size, size, 0); */ if ((retval = hcd_buffer_create(hcd)) != 0) { ... } /* * busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); * bus->busnum = busnum; * list_add (&bus->bus_list, &usb_bus_list); */ if ((retval = usb_register_bus(&hcd->self)) < 0) goto err_register_bus; /* 根 Hub */ if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { ... } rhdev->speed = USB_SPEED_FULL; hcd->self.root_hub = rhdev; /* dev->power.can_wakeup = dev->power.should_wakeup = 1 */ device_init_wakeup(&rhdev->dev, 1); if (hcd->driver->irq) { snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", hcd->driver->description, hcd->self.busnum); if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd)) != 0) { ... } hcd->irq = irqnum; } hcd->driver->start(hcd)); /* starting here, usbcore will pay attention to this root hub */ rhdev->bus_mA = min(500u, hcd->power_budget); if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; }
usb_hcd_add 干了哪些事:
1、hcd_buffer_create(hcd)
2、usb_register_bus(&hcd->self) ,将 usb_hcd.usb_bus 注册到全局链表 usb_bus_list
3、为根 hub 分配一个 usb_device 结构(内核中,所有的真实的usb设备(Hub,鼠标...)都用usb_device结构来描述)
4、注册根 Hub 的 usb_device 结构到 usb_bus_type
弄了半天,神神秘秘的USB主机控制器也只不过是分配了一个 usb_hcd 结构体,为它的 根hub 分配了一个usb_device 结构体,注册到 usb_bus_type 罢了,后边是 根Hub 的注册和设备枚举过程了。
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; /* 分配一个 usb_device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); device_initialize(&dev->dev); /* usb_bus_type */ dev->dev.bus = &usb_bus_type; /* 属性文件 */ dev->dev.type = &usb_device_type; dev->dev.groups = usb_device_groups; dev->dev.dma_mask = bus->controller->dma_mask; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; atomic_set(&dev->urbnum, 0); INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */ usb_enable_endpoint(dev, &dev->ep0, false); dev->can_submit = 1; /* 如果是根Hub */ if (unlikely(!parent)) { ... } else { ... } <span style="white-space:pre"> </span>... } return dev; }注意一下几点:
1、dev->dev.bus = &usb_bus_type 这里出现了一条“总线模型”中的总线,注意和 usb_bus 完全没关系。相当于hub 、鼠标等 usb 设备是注册到 usb_bus_type 的,前面我们说的控制器的驱动是注册到 platform_bus_type 的。
2、dev->dev.type = &usb_device_type ;后边Match函数中会用到
3、dev->state = USB_STATE_ATTACHED; 根Hub是和控制器连在一起的,必然已经连接上了
ATTACHED :表示设备已经连接到 hub 接口上了。
Powered :表示加电状态
Default :表示默认状态,在powered状态之后,设备必须受到一个复位信号并成功复位后,才能使用默认地址回应主机发过来的设备描述符的请求。
Address :表示主机分配了一个唯一的地址给设备。
Configured :表示设备已经被主机配置过了,此时,主机可以使用设备提供的所有功能。
Supended :表示挂起状态,设备在指定的时间内没有传输,就要进入挂起状态。
4、dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT ,我们说一个 usb 设备有多个配置,每个配置又有多个接口,每个接口有多个 端点。但是端点 0 比较特殊,它是整个 usb 设备共享的,因此它的表述符直接在 usb_device中。
5、dev->bus = bus ,根 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; 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); usb_set_device_state(usb_dev, USB_STATE_ADDRESS); mutex_lock(&usb_bus_list_lock); usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); /* 获得设备描述符 */ retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); /* 进一步设置,然后 add_device */ retval = usb_new_device (usb_dev); return retval; }1、usb_dev->devnum = 1 ;根 Hub 的地址为1 ,usb_dev->bus->devmap.devicemap ,表示哪些设备地址被占用了,以及这个 hub 一共支持多少设备。
2、usb_set_device_state(usb_dev, USB_STATE_ADDRESS); 变更状态
3、usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); 获得设备描述符,保存在usb_dev.descriptor 中。
4、usb_new_device 进一步设置(获得配置、端点描述符等),将 usb_device 注册到 usb_bus_type 。
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; }注意,这里是将整个根Hub作为一个 device 注册到 usb_bus_type ,后边还会将Hub的接口注册进去
int usb_new_device(struct usb_device *udev) { int err; /* Increment the parent's count of unsuspended children */ if (udev->parent) usb_autoresume_device(udev->parent); usb_detect_quirks(udev); /* Determine quirks */ err = usb_configure_device(udev); /* detect & probe dev/intfs */ /* export the usbdev device-node for libusb */ 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); (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); return err; }
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); 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_device 注册到 usb_bus_type 时,它所有的描述符信息都已经获取到了。
整个控制器驱动一路走下来,最后 注册了一个根 Hub 的 usb_device 到 usb_bus_type 。有必要看一下usb_bus_type ,它的 match 函数,将注册进来的 device 和 接口分开处理。第一次注册的我们说是 device ,那么看看对应的 driver 是啥。struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .uevent = usb_uevent, };
static int usb_device_match(struct device *dev, struct device_driver *drv) { /* return dev->type == &usb_device_type; */ if (is_usb_device(dev)) { /* return container_of(drv, struct usbdrv_wrap, driver)->for_devices; */ if (!is_usb_device_driver(drv)) return 0; /* TODO: Add real matching code */ return 1; } else if (is_usb_interface(dev)) { .... } return 0; }
如果设备的 dev->type == &usb_device_type ,且 driver.for_devices == 1 ,直接匹配成功。匹配成功之后便会调用driver侧的 probe 函数了。
struct usb_device_driver usb_generic_driver = { .name = "usb", .probe = generic_probe, .disconnect = generic_disconnect, #ifdef CONFIG_PM .suspend = generic_suspend, .resume = generic_resume, #endif .supports_autosuspend = 1, };
static int generic_probe(struct usb_device *udev) { int err, c; c = usb_choose_configuration(udev); err = usb_set_configuration(udev, c); /* USB device state == configured ... usable */ usb_notify_add_device(udev); return 0; }
int usb_set_configuration(struct usb_device *dev, int configuration) { int i, ret; struct usb_host_config *cp = NULL; struct usb_interface **new_interfaces = NULL; int n, nintf; if (dev->authorized == 0 || configuration == -1) configuration = 0; else { for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (dev->config[i].desc.bConfigurationValue == configuration) { cp = &dev->config[i]; break; } } } n = nintf = 0; if (cp) { /* new_interfaces 是个指针数组,首先为它分配空间 */ nintf = cp->desc.bNumInterfaces; new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_KERNEL); /* 为它指向的接口分配空间 */ for (; n < nintf; ++n) { new_interfaces[n] = kzalloc(sizeof(struct usb_interface), GFP_KERNEL); } i = dev->bus_mA - cp->desc.bMaxPower * 2; } /* Wake up the device so we can send it the Set-Config request */ ret = usb_autoresume_device(dev); if (cp) ret = usb_hcd_check_bandwidth(dev, cp, NULL); else ret = usb_hcd_check_bandwidth(dev, NULL, NULL); /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ if (dev->state != USB_STATE_ADDRESS) usb_disable_device(dev, 1); /* Skip ep0 */ /* Get rid of pending async Set-Config requests for this device */ cancel_async_set_config(dev); /* 设置配置 */ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); dev->actconfig = cp; /* 变更状态 */ usb_set_device_state(dev, USB_STATE_CONFIGURED); /* 设置这个配置的所有接口 */ for (i = 0; i < nintf; ++i) { struct usb_interface_cache *intfc; struct usb_interface *intf; struct usb_host_interface *alt; cp->interface[i] = intf = new_interfaces[i]; intfc = cp->intf_cache[i]; intf->altsetting = intfc->altsetting; intf->num_altsetting = intfc->num_altsetting; intf->intf_assoc = find_iad(dev, cp, i); kref_get(&intfc->ref); alt = usb_altnum_to_altsetting(intf, 0); if (!alt) alt = &intf->altsetting[0]; intf->cur_altsetting = alt; usb_enable_interface(dev, intf, true); intf->dev.parent = &dev->dev; intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; /* 注意这个,match时会区分 device 和 接口 */ intf->dev.type = &usb_if_device_type; intf->dev.groups = usb_interface_groups; intf->dev.dma_mask = dev->dev.dma_mask; INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); device_initialize(&intf->dev); mark_quiesced(intf); dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, alt->desc.bInterfaceNumber); } kfree(new_interfaces); if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; /* 注册到 usb_bus_type */ ret = device_add(&intf->dev); create_intf_ep_devs(intf); } usb_autosuspend_device(dev); return 0; }
static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { <span style="white-space:pre"> </span>... } else if (is_usb_interface(dev)) { struct usb_interface *intf; struct usb_driver *usb_drv; const struct usb_device_id *id; /* device drivers never match interfaces */ if (is_usb_device_driver(drv)) return 0; intf = to_usb_interface(dev); usb_drv = to_usb_driver(drv); id = usb_match_id(intf, usb_drv->id_table); if (id) return 1; id = usb_match_dynamic_id(intf, usb_drv); if (id) return 1; } return 0; }第一次注册进来的是 devies,在通用的driver 的 probe 函数,将该设备的所有接口信息都读取出来并设置再注册到 usb_bus_type 中,也就是说在match函数中,会走下边这个分支,根据 dirver 的 id_table 来匹配,根 Hub 的接口自然是与 hub_driver 进行匹配。
static struct usb_driver hub_driver = { .name = "hub", .probe = hub_probe, .disconnect = hub_disconnect, .suspend = hub_suspend, .resume = hub_resume, .reset_resume = hub_reset_resume, .pre_reset = hub_pre_reset, .post_reset = hub_post_reset, .ioctl = hub_ioctl, .id_table = hub_id_table, .supports_autosuspend = 1, };
int usb_hub_init(void) { if (usb_register(&hub_driver) < 0) { ... } /* 创建内核线程,子进程将从 hub_thread 开始,名字叫 khubd */ khubd_task = kthread_run(hub_thread, NULL, "khubd"); }分析过设备模型的都知道,匹配成功后调用的是usb_driver.driver.probe函数,然而这里并没有,而且usb_bus_type中也没有 probe 函数,那么有可能是在driver的注册过程中动了哪些手脚。
static inline int usb_register(struct usb_driver *driver) { return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME); }
int usb_register_driver(struct usb_driver *new_driver, struct module *owner, const char *mod_name) { int retval = 0; if (usb_disabled()) return -ENODEV; new_driver->drvwrap.for_devices = 0; new_driver->drvwrap.driver.name = (char *) new_driver->name; new_driver->drvwrap.driver.bus = &usb_bus_type; new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; new_driver->drvwrap.driver.owner = owner; new_driver->drvwrap.driver.mod_name = mod_name; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); retval = driver_register(&new_driver->drvwrap.driver); if (!retval) { pr_info("%s: registered new interface driver %s\n", usbcore_name, new_driver->name); usbfs_update_special(); usb_create_newid_file(new_driver); } else { printk(KERN_ERR "%s: error %d registering interface " " driver %s\n", usbcore_name, retval, new_driver->name); } return retval; }这里注册到 usb_bus_type 的是 usb_driver.drvwrap.driver ,那么匹配成功后调用的自然是 usb_probe_interface
static int usb_probe_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; dev_dbg(dev, "%s\n", __func__); intf->needs_binding = 0; id = usb_match_id(intf, driver->id_table); if (!id) id = usb_match_dynamic_id(intf, driver); if (id) { dev_dbg(dev, "%s - got id\n", __func__); error = usb_autoresume_device(udev); mark_active(intf); intf->condition = USB_INTERFACE_BINDING; atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend); if (intf->needs_altsetting0) { error = usb_set_interface(udev, intf->altsetting[0]. desc.bInterfaceNumber, 0); intf->needs_altsetting0 = 0; } <span style="white-space:pre"> </span>/* 看这里 */ error = driver->probe(intf, id); intf->condition = USB_INTERFACE_BOUND; usb_autosuspend_device(udev); } return error; }获取到 usb_device 的接口 usb_interface 以及 usb_device_id ,然后 driver->probe(intf, id) 调用到 usb_driver.probe 函数。传递进来的参数非常重要~,尤其是第一个 ---接口。再看 probe 函数之前,还有一点需要先看一下。
int usb_hub_init(void) { if (usb_register(&hub_driver) < 0) { ... } /* 创建内核线程,子进程将从 hub_thread 开始,名字叫 khubd */ khubd_task = kthread_run(hub_thread, NULL, "khubd"); }
static int hub_thread(void *__unused) { /* khubd needs to be freezable to avoid intefering with USB-PERSIST * port handover. Otherwise it might see that a full-speed device * was gone before the EHCI controller had handed its port over to * the companion full-speed controller. */ set_freezable(); do { hub_events(); /* wait_event_interruptible(khubd_wait, ... */ wait_event_freezable(khubd_wait, !list_empty(&hub_event_list) || kthread_should_stop()); } while (!kthread_should_stop() || !list_empty(&hub_event_list)); pr_debug("%s: khubd exiting\n", usbcore_name); return 0; }这个内核线程里干两件事,第一,hub_events(),第二休眠,等待唤醒。
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_host_interface *desc; struct usb_endpoint_descriptor *endpoint; struct usb_device *hdev; struct usb_hub *hub; desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); /* Hub 的子类就是0,即desc->desc 这个interface 描述符里边的bInterfaceSubClass就应该是0 */ if ((desc->desc.bInterfaceSubClass != 0) && (desc->desc.bInterfaceSubClass != 1)) { ... } /* spec 规定了Hub 只有一个端点(除去端点0)也就是中断端点 */ if (desc->desc.bNumEndpoints != 1) goto descriptor_error; endpoint = &desc->endpoint[0].desc; /* 判断这个端点是否是中断端点 */ if (!usb_endpoint_is_int_in(endpoint)) goto descriptor_error; /* 分配一个usb_hub */ hub = kzalloc(sizeof(*hub), GFP_KERNEL); kref_init(&hub->kref); INIT_LIST_HEAD(&hub->event_list); hub->intfdev = &intf->dev; //hub device hub->hdev = hdev; //hub usb_device INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); usb_get_intf(intf); /* intf->dev = hub */ usb_set_intfdata (intf, hub); intf->needs_remote_wakeup = 1; if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs++; if (hub_configure(hub, endpoint) >= 0) return 0; }
static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { struct usb_hcd *hcd; struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; u16 hubstatus, hubchange; u16 wHubCharacteristics; unsigned int pipe; int maxp, ret; char *message = "out of memory"; /* 内存分配 */ hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL, &hub->buffer_dma); hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); mutex_init(&hub->status_mutex); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); /* 获得 hub 描述符 */ ret = get_hub_descriptor(hdev, hub->descriptor, sizeof(*hub->descriptor)); } /* hub 支持的最大下行端口 */ hdev->maxchild = hub->descriptor->bNbrPorts; hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL); wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); if (wHubCharacteristics & HUB_CHAR_COMPOUND) { /* 复合设备 */ } else dev_dbg(hub_dev, "standalone hub\n"); switch (wHubCharacteristics & HUB_CHAR_LPSM) { /* 电源切换方式 */ } switch (wHubCharacteristics & HUB_CHAR_OCPM) { /* 过流保护模式 */ } spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { /* 低速全速设备掠过 */ } /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ switch (wHubCharacteristics & HUB_CHAR_TTTT) { /* 指定 hub->tt.think_time = 666 * n; n根据设备速度不同而不同*/ } /* 是否支持 hub 上的指示灯 */ if (wHubCharacteristics & HUB_CHAR_PORTIND) { hub->has_indicators = 1; dev_dbg(hub_dev, "Port indicators are supported\n"); } /* 请求设备状态 */ ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus); le16_to_cpus(&hubstatus); /* hub 的端口电流 */ if (hdev == hdev->bus->root_hub) { //根Hub ... } /* Update the HCD's internal representation of this hub before khubd * starts getting port status changes for devices under the hub. */ hcd = bus_to_hcd(hdev->bus); if (hcd->driver->update_hub_device) { ret = hcd->driver->update_hub_device(hcd, hdev, &hub->tt, GFP_KERNEL); } ret = hub_hub_status(hub, &hubstatus, &hubchange); /* 获得主机和 Hub 端点的管道 */ pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); if (maxp > sizeof(*hub->buffer)) maxp = sizeof(*hub->buffer); /* 分配一个urb */ hub->urb = usb_alloc_urb(0, GFP_KERNEL); /* 填充Urb */ usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); hub->urb->transfer_dma = hub->buffer_dma; hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* maybe cycle the hub leds */ if (hub->has_indicators && blinkenlights) hub->indicator [0] = INDICATOR_CYCLE; //tatus = usb_submit_urb(hub->urb, GFP_NOIO); //kick_khubd(hub) -> wake_up(&khubd_wait); hub_activate(hub, HUB_INIT); return 0; }
填充一个 urb ,检测 hub 端口状态,如果有状态发生改变,则会调用 hub_irq
static void hub_irq(struct urb *urb) { struct usb_hub *hub = urb->context; int status = urb->status; unsigned i; unsigned long bits; switch (status) { .... /* let khubd handle things */ case 0: /* we got data: port status changed */ bits = 0; for (i = 0; i < urb->actual_length; ++i) bits |= ((unsigned long) ((*hub->buffer)[i])) << (i*8); hub->event_bits[0] = bits; break; } hub->nerrors = 0; /* Something happened, let khubd figure it out */ kick_khubd(hub); resubmit: if (hub->quiescing) return; if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) dev_err (hub->intfdev, "resubmit --> %d\n", status); }
如果哪一位端口发生了变化,标记在 Hub->event_bits[0]中,然后唤醒线程,hub_event 被调用。再次提交 urb
static void hub_events(void) { struct list_head *tmp; struct usb_device *hdev; struct usb_interface *intf; struct usb_hub *hub; struct device *hub_dev; u16 hubstatus; u16 hubchange; u16 portstatus; u16 portchange; int i, ret; int connect_change; while (1) { /* Grab the first entry at the beginning of the list */ spin_lock_irq(&hub_event_lock); tmp = hub_event_list.next; list_del_init(tmp); hub = list_entry(tmp, struct usb_hub, event_list); kref_get(&hub->kref); spin_unlock_irq(&hub_event_lock); hdev = hub->hdev; hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ usb_lock_device(hdev); /* Autoresume */ ret = usb_autopm_get_interface(intf); /* deal with port status changes */ for (i = 1; i <= hub->descriptor->bNbrPorts; i++) { if (test_bit(i, hub->busy_bits)) continue; connect_change = test_bit(i, hub->change_bits); /* 第i位为0返回0 否则返回1,如果端口发生变化,返回1 */ if (!test_and_clear_bit(i, hub->event_bits) && !connect_change) continue; /* 程序运行到这,说明第i个端口发生了变化 */ ret = hub_port_status(hub, i, &portstatus, &portchange); if (portchange & USB_PORT_STAT_C_CONNECTION) { clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION); connect_change = 1; } if (portchange & USB_PORT_STAT_C_ENABLE) { ... } if (portchange & USB_PORT_STAT_C_SUSPEND) { ... } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { ... } if (portchange & USB_PORT_STAT_C_RESET) { ... } if (connect_change) hub_port_connect_change(hub, i, portstatus, portchange); } /* end for i */ ... }
static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) { struct usb_device *hdev = hub->hdev; struct device *hub_dev = hub->intfdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); unsigned wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); struct usb_device *udev; int status, i; for (i = 0; i < SET_CONFIG_TRIES; i++) { /* 分配一个 usb_device */ udev = usb_alloc_dev(hdev, hdev->bus, port1); /* 设置它的状态为 加电的 */ usb_set_device_state(udev, USB_STATE_POWERED); udev->bus_mA = hub->mA_per_port; udev->level = hdev->level + 1; udev->wusb = hub_is_wusb(hub); udev->speed = USB_SPEED_UNKNOWN; /* 分配一个地址 devnum = find_next_zero_bit(bus->devmap.devicemap, 128, bus->devnum_next); */ choose_address(udev); /* 复位 获取描述符 */ status = hub_port_init(hub, udev, port1, i); status = 0; /* Run it through the hoops (find a driver, etc) */ if (!status) { status = usb_new_device(udev); } status = hub_power_remaining(hub); return; }
static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { static DEFINE_MUTEX(usb_address0_mutex); struct usb_device *hdev = hub->hdev; struct usb_hcd *hcd = bus_to_hcd(hdev->bus); int i, j, retval; unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; int devnum = udev->devnum; mutex_lock(&usb_address0_mutex); retval = hub_port_reset(hub, port1, udev, delay); oldspeed = udev->speed; /* 根据传输速度设置端点0的最大包大小 */ switch (udev->speed) { case USB_SPEED_SUPER: case USB_SPEED_VARIABLE: /* fixed at 512 */ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); break; case USB_SPEED_HIGH: /* fixed at 64 */ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); break; case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); break; case USB_SPEED_LOW: /* fixed at 8 */ udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8); break; default: goto fail; } type = ""; switch (udev->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; case USB_SPEED_SUPER: speed = "super"; break; case USB_SPEED_VARIABLE: speed = "variable"; type = "Wireless "; break; default: speed = "?"; break; } for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { ... } if (udev->wusb == 0) { for (j = 0; j < SET_ADDRESS_TRIES; ++j) { /* 将分配的地址告诉设备 ,并设置设备状态为 USB_STATE_ADDRESS */ retval = hub_set_address(udev, devnum); msleep(200); } if (udev->speed == USB_SPEED_SUPER) { devnum = udev->devnum; } msleep(10); if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) break; } /* 不知道一次能获取多少,但至少能获取8 */ retval = usb_get_device_descriptor(udev, 8); if (retval < 8) { ... } else { retval = 0; break; } } if (udev->descriptor.bMaxPacketSize0 == 0xff || udev->speed == USB_SPEED_SUPER) i = 512; else i = udev->descriptor.bMaxPacketSize0; if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); usb_ep0_reinit(udev); } /* 重新获取全部描述符 */ retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); retval = 0; mutex_unlock(&usb_address0_mutex); return retval; }在 Hub_event 中,会调用 对于状态变化的端口调用 hub_port_status 来检测Hub端口的具体状态,然后调用 hub_port_connect_change
hub_port_connect_change
udev = usb_alloc_dev(hdev, hdev->bus, port1);
dev->dev.bus = &usb_bus_type;
choose_address(udev); // 给新设备分配编号(地址)
hub_port_init // usb 1-1: new full speed USB device using s3c2410-ohci and address 3
hub_set_address // 把编号(地址)告诉USB设备
usb_get_device_descriptor(udev, 8); // 获取设备描述符
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
usb_new_device(udev)
err = usb_get_configuration(udev); // 把所有的描述符都读出来,并解析
usb_parse_configuration
device_add // 把device放入usb_bus_type的dev链表,
// 从usb_bus_type的driver链表里取出usb_driver,
// 把usb_interface和usb_driver的id_table比较
// 如果能匹配,调用usb_driver的probe
显然,从 usb_alloc_dev 开始,重复了如同根 Hub 作为一个 device 注册进内核时的流程。如此循环下去,就能枚举注册所有的 usb 设备。
标签:
原文地址:http://blog.csdn.net/lizuobin2/article/details/51931161