赞
踩
device_add()上图和下图的连接!
关于hub_probe()内部的具体实现,详见:点击打开链接
- static struct platform_device *nuc970_public_dev[] __initdata = {
- &&nuc970_device_ehci,
- };
- static u64 nuc970_device_usb_ehci_dmamask = 0xffffffffUL;
-
- static struct platform_device nuc970_device_ehci = {
- .name = "nuc970-ehci", //平台设备名,用来与设备驱动匹配的
- .id = -1,
- .num_resources = ARRAY_SIZE(nuc970_ehci_resource),
- .resource = nuc970_ehci_resource,
- .dev = {
- .dma_mask = &nuc970_device_usb_ehci_dmamask,
- .coherent_dma_mask = 0xffffffffUL
- }
- };
- static struct resource nuc970_ehci_resource[] = {
- [0] = { //寄存器地址
- .start = NUC970_PA_EHCI,
- .end = NUC970_PA_EHCI + NUC970_SZ_EHCI - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = { //中断
- .start = IRQ_EHCI,
- .end = IRQ_EHCI,
- .flags = IORESOURCE_IRQ,
- }
- };
ehci设备注册:
platform_add_devices(nuc970_public_dev, ARRAY_SIZE(nuc970_public_dev));
- static int __init ehci_nuc970_init(void)
- {
-
- return platform_driver_register(&ehci_hcd_nuc970_driver); //echi平台设备驱动注册
- }
-
- static void __exit ehci_nuc970_cleanup(void)
- {
- platform_driver_unregister(&ehci_hcd_nuc970_driver); //echi平台设备驱动注销
-
- }
- static struct platform_driver ehci_hcd_nuc970_driver = { //平台设备驱动
-
- .probe = ehci_nuc970_probe,
- .remove = ehci_nuc970_remove,
- .driver = {
- .name = "nuc970-ehci", //平台设备驱动名称,用来与2.中的平台设备匹配
- .owner= THIS_MODULE,
- },
- };
当platform_device平台设备和platform_driver平台驱动注册到platform总线上时,通过设备名和设备驱动名“nuc970-echi”相匹配,最终调用ehci_nuc970_probe()探测函数,接下来我们将重点分析该函数。
- static int ehci_nuc970_probe(struct platform_device *pdev)
- {
- //printk("ehci_nuc970_probe()\n");
- if (usb_disabled())
- return -ENODEV;
-
- return usb_nuc970_probe(&ehci_nuc970_hc_driver, pdev); //见下
- }
usb_nuc970_probe()的函数参数为平台设备和ehci主机控制器驱动ehci_nuc970_hc_driver,对应结构体如下:
- static const struct hc_driver ehci_nuc970_hc_driver = {
- .description = hcd_name, //hcd主机控制器名称“ehci-platform”
- .product_desc = "Nuvoton NUC970 EHCI Host Controller", //产品描述
- .hcd_priv_size = sizeof(struct ehci_hcd), //echi主机控制器大小
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq, //echi硬件中断
- .flags = HCD_USB2|HCD_MEMORY, //usb2.0 | hcd使用内存(其它就是I/O)
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_init, //复位主机控制器
- .start = ehci_run, //启动主机控制器
-
- .stop = ehci_stop, //停止主机控制器
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue, //urq请求队列
- .urb_dequeue = ehci_urb_dequeue, //urb释放队列
- .endpoint_disable = ehci_endpoint_disable, //端点禁止
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data, //获取hub状态
- .hub_control = ehci_hub_control, //hub控制操作
- #ifdef CONFIG_PM
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- #endif
- };
usb_nuc970_probe()函数:
return usb_nuc970_probe(&ehci_nuc970_hc_driver, pdev);
- static int usb_nuc970_probe(const struct hc_driver *driver,
- struct platform_device *pdev)
- {
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- u32 physical_map_ehci;
- struct pinctrl *p;
- int retval;
-
- if (IS_ERR(clk_get(NULL, "usbh_hclk"))) {
- printk("clk_get error!!\n");
- return -1;
- }
-
- /* multi-function pin select */
- #if defined (CONFIG_NUC970_USBH_PWR_PE)
- /* set over-current active low */
- __raw_writel(__raw_readl(NUC970_VA_OHCI+0x204) | 0x8, NUC970_VA_OHCI+0x204);
-
- /* initial USBH_PPWR0 & USBH_PPWR1 pin -> PE.14 & PE.15 */
- p = devm_pinctrl_get_select(&pdev->dev, "usbh-ppwr-pe");
- if (IS_ERR(p))
- {
- dev_err(&pdev->dev, "unable to reserve pin\n");
- retval = PTR_ERR(p);
- }
- #elif defined (CONFIG_NUC970_USBH_PWR_PF)
- /* set over-current active low */
- __raw_writel(__raw_readl(NUC970_VA_OHCI+0x204) | 0x8, NUC970_VA_OHCI+0x204);
-
- /* initial USBH_PPWR pin -> PF.10 */
- p = devm_pinctrl_get_select(&pdev->dev, "usbh-ppwr-pf");
- if (IS_ERR(p))
- {
- dev_err(&pdev->dev, "unable to reserve pin\n");
- retval = PTR_ERR(p);
- }
- #elif defined (CONFIG_NUC970_USBH_OC_ONLY)
- /* set over-current active low */
- __raw_writel(__raw_readl(NUC970_VA_OHCI+0x204) | 0x8, NUC970_VA_OHCI+0x204);
-
- p = devm_pinctrl_get_select(&pdev->dev, "usbh-ppwr-oc");
- if (IS_ERR(p))
- {
- dev_err(&pdev->dev, "unable to reserve pin\n");
- retval = PTR_ERR(p);
- }
- #else // CONFIG_NUC970_USBH_NONE
- /* set over-current active high */
- __raw_writel(__raw_readl(NUC970_VA_OHCI+0x204) &~0x8, NUC970_VA_OHCI+0x204);
- #endif
- /* Enable USB Host clock */
- clk_prepare(clk_get(NULL, "usb_eclk"));
- clk_enable(clk_get(NULL, "usb_eclk"));
-
- clk_prepare(clk_get(NULL, "usbh_hclk"));
- clk_enable(clk_get(NULL, "usbh_hclk"));
-
- if (pdev->resource[1].flags != IORESOURCE_IRQ) { //判定是否是中断
- pr_debug("resource[1] is not IORESOURCE_IRQ");
- retval = -ENOMEM;
- }
-
- hcd = usb_create_hcd(driver, &pdev->dev, "nuc970-ehci"); //创建一个usb hcd主机控制器(struct usb_hcd)
- if (!hcd) {
- retval = -ENOMEM;
- goto err1;
- }
-
-
- //赋值ehci寄存器地址
- hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
-
- //申请内存
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- pr_debug("ehci probe request_mem_region failed");
- retval = -EBUSY;
- goto err2;
- }
-
- //映射内存
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (hcd->regs == NULL) {
- pr_debug("ehci error mapping memory\n");
- retval = -EFAULT;
- goto err3;
- }
-
- ehci = hcd_to_ehci(hcd);
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + 0x20;
-
- /* enable PHY 0/1 */
- physical_map_ehci = (u32)ehci->caps;
- __raw_writel(0x160, physical_map_ehci+0xC4);
- __raw_writel(0x520, physical_map_ehci+0xC8);
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params); //echi结构体参数寄存器
- ehci->sbrn = 0x20;
-
- retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); //增加主机控制器
-
- if (retval != 0)
- goto err4;
-
- return retval;
-
- err4:
- iounmap(hcd->regs);
- err3:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- err2:
- usb_put_hcd(hcd);
- err1:
-
- return retval;
- }
这个函数内部主要时完成一些资源的分配和初始化,我们只关注usb hcd主机控制器的创建和增加,对应的接口函数如下:
- hcd = usb_create_hcd(driver, &pdev->dev, "nuc970-ehci"); //创建一个usb hcd主机控制器(struct usb_hcd)
-
- retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); //增加主机控制器
这里我们将逐个分析。
- struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
- struct device *dev, const char *bus_name)
- {
- return usb_create_shared_hcd(driver, dev, bus_name, NULL); //创建一个共享的USB hcd控制器
- }
- EXPORT_SYMBOL_GPL(usb_create_hcd);
- struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
- struct device *dev, const char *bus_name,
- struct usb_hcd *primary_hcd)
- {
- struct usb_hcd *hcd;
-
- hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); //分配一个usb hcd主机控制器
- if (!hcd) {
- dev_dbg (dev, "hcd alloc failed\n");
- return NULL;
- }
-
- //分配"带宽"互斥锁,干啥用的,忘了!!!
- if (primary_hcd == NULL) { //=NULL,为真
- hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
- GFP_KERNEL);
- if (!hcd->bandwidth_mutex) {
- kfree(hcd);
- dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
- return NULL;
- }
- mutex_init(hcd->bandwidth_mutex);
- dev_set_drvdata(dev, hcd); //将usb hcd绑定为设备的私有数据
- } else {
- hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
- hcd->primary_hcd = primary_hcd;
- primary_hcd->primary_hcd = primary_hcd;
- hcd->shared_hcd = primary_hcd;
- primary_hcd->shared_hcd = hcd;
- }
-
- kref_init(&hcd->kref);
-
- usb_bus_init(&hcd->self); //usb-hcd 作为一个总线初始化
- hcd->self.controller = dev; //绑定设备,对应platform_device
- hcd->self.bus_name = bus_name; //usb-hcd总线名称“nuc970-ehci”
- hcd->self.uses_dma = (dev->dma_mask != NULL); //主机控制器是否使用DMA,通过platfrom_device知道dev->dma_mask=0xffff
-
- init_timer(&hcd->rh_timer); //初始化一个root-hub定时器
- hcd->rh_timer.function = rh_timer_func; //绑定定时器超时的回调函数
- hcd->rh_timer.data = (unsigned long) hcd; //回调函数的参数为usb-hcd主机控制器
- #ifdef CONFIG_PM_RUNTIME
- INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
- #endif
-
- hcd->driver = driver; //usb-hcd主机控制器绑定主机控制器驱动driver
- hcd->speed = driver->flags & HCD_MASK; //获取主机控制器速率
- hcd->product_desc = (driver->product_desc) ? driver->product_desc : //初始化主机控制器的产品描述符
- "USB Host Controller";
- return hcd;
- }
该函数内部主要分配了一个usb-hcd主机控制器,初始化主机控制器root-hub的一个定时器回调函数,最后将主机控制器驱动hcd_driver绑定到usb-hcd主机控制器上,这里要区分他们的关系:
a> struct usb_hcd usb主机控制器
b> struct hc_driver 主机控制器驱动
c> struct usb_bus self 总线
d> struct usb_device *rhdev 设备
retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); //增加主机控制器
- int usb_add_hcd(struct usb_hcd *hcd,
- unsigned int irqnum, unsigned long irqflags)
- {
- int retval;
- struct usb_device *rhdev;
-
- dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
-
- /* Keep old behaviour if authorized_default is not in [0, 1]. */
- /*authorized_default
- 的三种设备状态
- -1 表示认证无线之外的所有设备
- 0 表示不认证任何设备
- 1 表示认证所有设备
- */
- if (authorized_default < 0 || authorized_default > 1)
- hcd->authorized_default = hcd->wireless? 0 : 1;
- else
- hcd->authorized_default = authorized_default;
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); //设置usb-hcd的状态标识为“上电”
-
- /* HC is in reset state, but accessible. Now do the one-time init,
- * bottom up so that hcds can customize the root hubs before khubd
- * starts talking to them. (Note, bus id is assigned early too.)
- */
- if ((retval = hcd_buffer_create(hcd)) != 0) { //创建一个DMA缓冲池
- dev_dbg(hcd->self.controller, "pool alloc failed\n");
- return retval;
- }
-
- if ((retval = usb_register_bus(&hcd->self)) < 0) //注册一个usb-bus
- goto err_register_bus;
-
- if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { //分配一个usb设备,作为root_hub
- dev_err(hcd->self.controller, "unable to allocate root hub\n");
- retval = -ENOMEM;
- goto err_allocate_root_hub;
- }
- hcd->self.root_hub = rhdev;
-
- switch (hcd->speed) {
- case HCD_USB11:
- rhdev->speed = USB_SPEED_FULL;
- break;
- case HCD_USB2:
- rhdev->speed = USB_SPEED_HIGH;
- break;
- case HCD_USB3:
- rhdev->speed = USB_SPEED_SUPER;
- break;
- default:
- retval = -EINVAL;
- goto err_set_rh_speed;
- }
-
- /* wakeup flag init defaults to "everything works" for root hubs,
- * but drivers can override it in reset() if needed, along with
- * recording the overall controller's system wakeup capability.
- */
- device_set_wakeup_capable(&rhdev->dev, 1);
-
- /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
- * registered. But since the controller can die at any time,
- * let's initialize the flag before touching the hardware.
- */
- set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
-
- /* "reset" is misnamed; its role is now one-time init. the controller
- * should already have been reset (and boot firmware kicked off etc).
- */
- if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
- dev_err(hcd->self.controller, "can't setup\n");
- goto err_hcd_driver_setup;
- }
- hcd->rh_pollable = 1;
-
- /* NOTE: root hub and controller capabilities may not be the same */
- if (device_can_wakeup(hcd->self.controller)
- && device_can_wakeup(&hcd->self.root_hub->dev))
- dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
-
- /* enable irqs just before we start the controller,
- * if the BIOS provides legacy PCI irqs.
- */
- if (usb_hcd_is_primary_hcd(hcd) && irqnum) {
- retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); //申请中断
- if (retval)
- goto err_request_irq;
- }
-
- hcd->state = HC_STATE_RUNNING;
- retval = hcd->driver->start(hcd); //.start = ehci_run
- if (retval < 0) {
- dev_err(hcd->self.controller, "startup error %d\n", retval);
- goto err_hcd_driver_start;
- }
-
- /* starting here, usbcore will pay attention to this root hub */
- if ((retval = register_root_hub(hcd)) != 0)
- goto err_register_root_hub;
-
- retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
- if (retval < 0) {
- printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
- retval);
- goto error_create_attr_group;
- }
- if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
- usb_hcd_poll_rh_status(hcd);
-
- /*
- * Host controllers don't generate their own wakeup requests;
- * they only forward requests from the root hub. Therefore
- * controllers should always be enabled for remote wakeup.
- */
- device_wakeup_enable(hcd->self.controller);
- return retval;
-
- error_create_attr_group:
- clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
- if (HC_IS_RUNNING(hcd->state))
- hcd->state = HC_STATE_QUIESCING;
- spin_lock_irq(&hcd_root_hub_lock);
- hcd->rh_registered = 0;
- spin_unlock_irq(&hcd_root_hub_lock);
-
- #ifdef CONFIG_PM_RUNTIME
- cancel_work_sync(&hcd->wakeup_work);
- #endif
- mutex_lock(&usb_bus_list_lock);
- usb_disconnect(&rhdev); /* Sets rhdev to NULL */
- mutex_unlock(&usb_bus_list_lock);
- err_register_root_hub:
- hcd->rh_pollable = 0;
- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
- del_timer_sync(&hcd->rh_timer);
- hcd->driver->stop(hcd);
- hcd->state = HC_STATE_HALT;
- clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
- del_timer_sync(&hcd->rh_timer);
- err_hcd_driver_start:
- if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
- free_irq(irqnum, hcd);
- err_request_irq:
- err_hcd_driver_setup:
- err_set_rh_speed:
- usb_put_dev(hcd->self.root_hub);
- err_allocate_root_hub:
- usb_deregister_bus(&hcd->self);
- err_register_bus:
- hcd_buffer_destroy(hcd);
- return retval;
- }
- EXPORT_SYMBOL_GPL(usb_add_hcd);
usb-hcd主机控制器添加,主要完成以下几点:
1> hcd_buffer_create(hcd) 创建一个hcd DMA池;
2> usb_register_bus(&hcd->self) 注册一个usb总线;
3> usb_alloc_dev(NULL, &hcd->self, 0) 分配一个usb-device设备;
4> usb_hcd_request_irqs(hcd, irqnum, irqflags)申请一个hcd中断定时器;
5> register_root_hub(hcd)注册一个root-hub。
这里将逐个分析:
创建DMA池:
hcd_buffer_create()--> dma_pool_create()-->device_create_file(dev, &dev_attr_pools)
static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
- static ssize_t
- show_pools(struct device *dev, struct device_attribute *attr, char *buf)
- {
- unsigned temp;
- unsigned size;
- char *next;
- struct dma_page *page;
- struct dma_pool *pool;
-
- next = buf;
- size = PAGE_SIZE;
-
- temp = scnprintf(next, size, "poolinfo - 0.1\n");
- size -= temp;
- next += temp;
-
- mutex_lock(&pools_lock);
- list_for_each_entry(pool, &dev->dma_pools, pools) {
- unsigned pages = 0;
- unsigned blocks = 0;
-
- spin_lock_irq(&pool->lock);
- list_for_each_entry(page, &pool->page_list, page_list) {
- pages++;
- blocks += page->in_use;
- }
- spin_unlock_irq(&pool->lock);
-
- /* per-pool info, no real statistics yet */
- temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
- pool->name, blocks,
- pages * (pool->allocation / pool->size),
- pool->size, pages);
- size -= temp;
- next += temp;
- }
- mutex_unlock(&pools_lock);
-
- return PAGE_SIZE - size;
- }
在终端上执行: cat pools命令调用上面的show_pools(),打印如下信息:
- [root@szclou /sys/devices/platform/nuc970-ehci]#cat pools
- poolinfo - 0.1
- ehci_sitd 0 0 96 0
- ehci_itd 0 0 160 0
- ehci_qh 1 42 96 1
- ehci_qtd 1 42 96 1
- buffer-2048 0 0 2048 0
- buffer-512 0 0 512 0
- buffer-128 0 0 128 0
- buffer-32 0 0 32 0
至此,属性文件的操作就是用来显示这些信息的,再看一个usb-root信息
dev->dev.groups = usb_device_groups;
其中dev->dev.groups类型为
const struct attribute_group **groups
- const struct attribute_group *usb_device_groups[] = {
- &dev_attr_grp, //属性组信息
- &dev_string_attr_grp, //属性字符串组
- NULL
- };
- static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
- };
- static struct attribute *dev_attrs[] = {
- /* current configuration's attributes */
- &dev_attr_configuration.attr,
- &dev_attr_bNumInterfaces.attr,
- &dev_attr_bConfigurationValue.attr,
- &dev_attr_bmAttributes.attr,
- &dev_attr_bMaxPower.attr,
- /* device attributes */
- &dev_attr_urbnum.attr,
- &dev_attr_idVendor.attr,
- &dev_attr_idProduct.attr,
- &dev_attr_bcdDevice.attr,
- &dev_attr_bDeviceClass.attr,
- &dev_attr_bDeviceSubClass.attr,
- &dev_attr_bDeviceProtocol.attr,
- &dev_attr_bNumConfigurations.attr,
- &dev_attr_bMaxPacketSize0.attr,
- &dev_attr_speed.attr,
- &dev_attr_busnum.attr,
- &dev_attr_devnum.attr,
- &dev_attr_devpath.attr,
- &dev_attr_version.attr,
- &dev_attr_maxchild.attr,
- &dev_attr_quirks.attr,
- &dev_attr_avoid_reset_quirk.attr,
- &dev_attr_authorized.attr,
- &dev_attr_remove.attr,
- &dev_attr_removable.attr,
- &dev_attr_ltm_capable.attr,
- NULL,
- };
- static struct attribute_group dev_string_attr_grp = {
- .attrs = dev_string_attrs,
- .is_visible = dev_string_attrs_are_visible,
- };
- static struct attribute *dev_string_attrs[] = {
- &dev_attr_manufacturer.attr,
- &dev_attr_product.attr,
- &dev_attr_serial.attr,
- NULL
- };
*dev_string_attrs[] 和 *dev_attrs[]对应系统目录结构信息为:
- [root@szclou /sys/devices/platform/nuc970-ehci/usb1]#ls
- 1-0:1.0 bmAttributes maxchild
- authorized busnum product
- authorized_default configuration quirks
- avoid_reset_quirk descriptors removable
- bConfigurationValue dev remove
- bDeviceClass devnum serial
- bDeviceProtocol devpath speed
- bDeviceSubClass driver subsystem
- bMaxPacketSize0 ep_00 uevent
- bMaxPower idProduct urbnum
- bNumConfigurations idVendor version
- bNumInterfaces ltm_capable
- bcdDevice manufacturer
- static int usb_register_bus(struct usb_bus *bus)
- {
- int result = -E2BIG;
- int busnum;
-
- mutex_lock(&usb_bus_list_lock);
- busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
- if (busnum >= USB_MAXBUS) {
- printk (KERN_ERR "%s: too many buses\n", usbcore_name);
- goto error_find_busnum;
- }
- set_bit (busnum, busmap.busmap);
- bus->busnum = busnum;
-
- /* Add it to the local list of buses */
- list_add (&bus->bus_list, &usb_bus_list); //将当前usb总线添加到usb_bus_list链表中
- mutex_unlock(&usb_bus_list_lock);
-
- usb_notify_add_bus(bus);
-
- dev_info (bus->controller, "new USB bus registered, assigned bus "
- "number %d\n", bus->busnum);
- return 0;
-
- error_find_busnum:
- mutex_unlock(&usb_bus_list_lock);
- return result;
- }
- if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { //分配一个usb设备,作为root_hub
- dev_err(hcd->self.controller, "unable to allocate root hub\n");
- retval = -ENOMEM;
- goto err_allocate_root_hub;
- }
- hcd->self.root_hub = rhdev; //如果上面usb设备分配成功,将作为hcd主机控制器的根设备
- 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 = bus_to_hcd(bus);
- unsigned root_hub = 0;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
-
- if (!usb_get_hcd(usb_hcd)) {
- 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; //绑定设备的总线为“usb”
- dev->dev.type = &usb_device_type; //设备的类型
- dev->dev.groups = usb_device_groups; //对sysfs文件系统的属性文件操作,上面有对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; //设置usb状态为绑定
- dev->lpm_disable_count = 1;
- 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;
-
- /* 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.
- */
- 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 */
- 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 {
- 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;
- 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;
- INIT_LIST_HEAD(&dev->filelist);
-
- #ifdef CONFIG_PM
- pm_runtime_set_autosuspend_delay(&dev->dev,
- usb_autosuspend_delay * 1000);
- dev->connect_time = jiffies;
- dev->active_duration = -jiffies;
- #endif
- if (root_hub) /* Root hub always ok [and always wired] */
- dev->authorized = 1;
- else {
- dev->authorized = usb_hcd->authorized_default;
- dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
- }
- return dev;
- }
- if (usb_hcd_is_primary_hcd(hcd) && irqnum) {
- retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); //申请中断
- if (retval)
- goto err_request_irq;
- }
- static int usb_hcd_request_irqs(struct usb_hcd *hcd,
- unsigned int irqnum, unsigned long irqflags)
- {
- int retval;
-
- if (hcd->driver->irq) {
-
- /* IRQF_DISABLED doesn't work as advertised when used together
- * with IRQF_SHARED. As usb_hcd_irq() will always disable
- * interrupts we can remove it here.
- */
- if (irqflags & IRQF_SHARED)
- irqflags &= ~IRQF_DISABLED;
-
- snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
- hcd->driver->description, hcd->self.busnum);
- retval = request_irq(irqnum, &usb_hcd_irq, irqflags, //usb_hcd_irq()函数内部将调用hcd->driver->irq(hcd)
- hcd->irq_descr, hcd);
- if (retval != 0) {
- dev_err(hcd->self.controller,
- "request interrupt %d failed\n",
- irqnum);
- return retval;
- }
- hcd->irq = irqnum;
- dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,
- (hcd->driver->flags & HCD_MEMORY) ?
- "io mem" : "io base",
- (unsigned long long)hcd->rsrc_start);
- } else {
- hcd->irq = 0;
- if (hcd->rsrc_start)
- dev_info(hcd->self.controller, "%s 0x%08llx\n",
- (hcd->driver->flags & HCD_MEMORY) ?
- "io mem" : "io base",
- (unsigned long long)hcd->rsrc_start);
- }
- return 0;
- }
- if ((retval = register_root_hub(hcd)) != 0)
- goto err_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;
- 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); //设置usb设备状态,当前为USB_STATE_ADDRESS
-
- mutex_lock(&usb_bus_list_lock);
-
- usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); //给端点0描述符分配64个字节长度空间
- 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;
- }
- if (usb_dev->speed == USB_SPEED_SUPER) { //usb3.0,暂时不分析
- retval = usb_get_bos_descriptor(usb_dev);
- if (retval < 0) {
- mutex_unlock(&usb_bus_list_lock);
- dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
- dev_name(&usb_dev->dev), retval);
- return retval;
- }
- }
-
- retval = usb_new_device (usb_dev); //新建一个usb设备
- if (retval) {
- dev_err (parent_dev, "can't register root hub for %s, %d\n",
- dev_name(&usb_dev->dev), retval);
- } else {
- spin_lock_irq (&hcd_root_hub_lock);
- hcd->rh_registered = 1;
- spin_unlock_irq (&hcd_root_hub_lock);
-
- /* Did the HC die before the root hub was registered? */
- if (HCD_DEAD(hcd))
- usb_hc_died (hcd); /* This time clean up */
- }
- mutex_unlock(&usb_bus_list_lock);
-
- return retval;
- }
该函数主要完成的工作时给usb设备分配一个编号(范围1~127),获取设备描述符usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE),这里使用了一个技巧,因为不知道设备描述符里面有多少个配置,配置里有多少个接口,所以这里直接读取USB_DT_DEVICE_SIZE个字节,而这个字节的长度恰好对应设备描述符的结构体成员长度,如下:
- /* USB_DT_DEVICE: Device descriptor */
- struct usb_device_descriptor {
- __u8 bLength;//设备描述符的字节数大小,为0x12
- __u8 bDescriptorType;//描述符类型编号,为0x01
-
- __le16 bcdUSB;//USB版本号
- __u8 bDeviceClass;//USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型
-
- //0x00不是在设备描述符中定义的,如HID
- __u8 bDeviceSubClass;//usb分配的子类代码,同上,值由USB规定和分配的
- __u8 bDeviceProtocol;//USB分配的设备协议代码,同上
- __u8 bMaxPacketSize0;//端点0的最大包的大小
- __le16 idVendor;//厂商编号
- __le16 idProduct;//产品编号
- __le16 bcdDevice;//设备出厂编号
- __u8 iManufacturer;//描述厂商字符串的索引
- __u8 iProduct;//描述产品字符串的索引
- __u8 iSerialNumber;//描述设备序列号字符串的索引
- __u8 bNumConfigurations;//可能的配置数量
- } __attribute__ ((packed));
再后续时创建了一个新的usb设备,下面将详细分析。
retval = usb_new_device (usb_dev); //新建一个usb设备
- int usb_new_device(struct usb_device *udev)
- {
- int err;
-
- if (udev->parent) {
- /* Initialize non-root-hub device wakeup to disabled;
- * device (un)configuration controls wakeup capable
- * sysfs power/wakeup controls wakeup enabled/disabled
- */
- device_init_wakeup(&udev->dev, 0);
- }
-
- /* Tell the runtime-PM framework the device is active */
- pm_runtime_set_active(&udev->dev);
- pm_runtime_get_noresume(&udev->dev);
- pm_runtime_use_autosuspend(&udev->dev);
- pm_runtime_enable(&udev->dev);
-
- /* By default, forbid autosuspend for all devices. It will be
- * allowed for hubs during binding.
- */
- usb_disable_autosuspend(udev);
-
- //枚举设备
- err = usb_enumerate_device(udev); /* Read descriptors */
- 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 */
- udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
- (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
-
- /* Tell the world! */
- announce_device(udev);
-
- if (udev->serial)
- add_device_randomness(udev->serial, strlen(udev->serial));
- if (udev->product)
- add_device_randomness(udev->product, strlen(udev->product));
- if (udev->manufacturer)
- add_device_randomness(udev->manufacturer,
- strlen(udev->manufacturer));
-
- device_enable_async_suspend(&udev->dev);
-
- /*
- * check whether the hub marks this port as non-removable. Do it
- * now so that platform-specific data can override it in
- * device_add()
- */
- if (udev->parent)
- set_usb_port_removable(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;
- }
-
- /* Create link files between child device and usb port device. */
- if (udev->parent) {
- struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
- struct usb_port *port_dev = hub->ports[udev->portnum - 1];
-
- err = sysfs_create_link(&udev->dev.kobj,
- &port_dev->dev.kobj, "port");
- if (err)
- goto fail;
-
- err = sysfs_create_link(&port_dev->dev.kobj,
- &udev->dev.kobj, "device");
- if (err) {
- sysfs_remove_link(&udev->dev.kobj, "port");
- goto fail;
- }
-
- pm_runtime_get_sync(&port_dev->dev);
- }
-
- (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
- usb_mark_last_busy(udev);
- pm_runtime_put_sync_autosuspend(&udev->dev);
- return err;
-
- fail:
- usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- pm_runtime_disable(&udev->dev);
- pm_runtime_set_suspended(&udev->dev);
- return err;
- }
这里主要分析设备枚举,是这里最核心的一个地方!!!
- //枚举设备
- err = usb_enumerate_device(udev); /* Read descriptors */
- static int usb_enumerate_device(struct usb_device *udev)
- {
- int err;
-
- if (udev->config == NULL) {
- err = usb_get_configuration(udev); //获取配置信息
- if (err < 0) {
- if (err != -ENODEV)
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
- return err;
- }
- }
-
- /* 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_enumerate_device_otg(udev);
- if (err < 0)
- return err;
-
- usb_detect_interface_quirks(udev);
-
- return 0;
- }
- if (udev->config == NULL) {
- err = usb_get_configuration(udev);
- if (err < 0) {
- if (err != -ENODEV)
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
- return err;
- }
- }
- int usb_get_configuration(struct usb_device *dev)
- {
- struct device *ddev = &dev->dev;
- int ncfg = dev->descriptor.bNumConfigurations; //usb配置个数
- int result = 0;
- unsigned int cfgno, length;
- unsigned char *bigbuffer;
- struct usb_config_descriptor *desc;
-
- cfgno = 0;
- 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;
- }
-
- length = ncfg * sizeof(struct usb_host_config);
- dev->config = kzalloc(length, GFP_KERNEL); //分配一个设备下的ncfg个config配置结构体
- if (!dev->config)
- goto err2;
-
- length = ncfg * sizeof(char *);
- dev->rawdescriptors = kzalloc(length, GFP_KERNEL); //分配ncfg个char指针
- if (!dev->rawdescriptors)
- goto err2;
-
- desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
- if (!desc)
- goto err2;
-
- 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,
- desc, USB_DT_CONFIG_SIZE); //由于无法知道配置的长度,这里使用一个小技巧,先读取配置USB_DT_CONFIG_SIZE个字节,从该长度内部可以获取配置下的接口长度,所以这里会读取两次,这是第一次!!!
- if (result < 0) {
- dev_err(ddev, "unable to read config index %d "
- "descriptor/%s: %d\n", cfgno, "start", result);
- if (result != -EPIPE)
- goto err;
- dev_err(ddev, "chopping to %d config(s)\n", cfgno);
- dev->descriptor.bNumConfigurations = cfgno;
- break;
- } else if (result < 4) {
- 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);
-
- /* Now that we know the length, get the whole thing */
- bigbuffer = kmalloc(length, GFP_KERNEL);
- if (!bigbuffer) {
- result = -ENOMEM;
- goto err;
- }
-
- //获取配置的所有长度信息,这里是第二次读取!!!
- 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, cfgno,
- &dev->config[cfgno], bigbuffer, length);
- if (result < 0) {
- ++cfgno;
- goto err;
- }
- }
- result = 0;
-
- err:
- kfree(desc);
- dev->descriptor.bNumConfigurations = cfgno;
- err2:
- if (result == -ENOMEM)
- dev_err(ddev, "out of memory\n");
- return result;
- }
- //解析配置信息
- result = usb_parse_configuration(dev, cfgno,
- &dev->config[cfgno], bigbuffer, length);
- static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
- struct usb_host_config *config, unsigned char *buffer, int size)
- {
- struct device *ddev = &dev->dev;
- 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); //拷贝当前配置信息到config->desc
- if (config->desc.bDescriptorType != USB_DT_CONFIG ||
- config->desc.bLength < USB_DT_CONFIG_SIZE ||
- config->desc.bLength > 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; //当前配置编号值
-
- //这里偏移buffer的目的是啥???不过下面又开始计算配置下的接口了!!!
- //上面是以前的疑问,现在明白了,buffer += config->desc.bLength 表示跳过配置的内容,直接跳转到接口
- buffer += config->desc.bLength; //偏移到接口
- size -= config->desc.bLength; //减去配置的长度
-
- 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;
-
- d = (struct usb_interface_descriptor *) header; //上面通过两个字段确定了为接口,这里直接转换为接口描述符 struct usb_interface_descriptor
- 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;
- }
-
- inum = d->bInterfaceNumber; //获取接口的编号
-
- if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) &&
- n >= nintf_orig) {
- dev_warn(ddev, "config %d has more interface "
- "descriptors, than it declares in "
- "bNumInterfaces, ignoring interface "
- "number: %d\n", cfgno, inum);
- continue;
- }
-
- 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 */
- for (i = 0; i < n; ++i) {
- if (inums[i] == inum) //确定之前是否已经统计了该接口
- break;
- }
- if (i < n) { //
- if (nalts[i] < 255)
- ++nalts[i]; //对当前接口编号相同的进行统计(初始化为1,在else if语句中)
- } else if (n < USB_MAXINTERFACES) {
- inums[n] = inum; //记录当前接口的编号到inums数组中
- nalts[n] = 1; //初始化当前接口值为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 = buffer2 - buffer; //size=一个配置中所有接口描述符的长度
- config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); //config->desc.wTotalLength = 一个配置和接口描述符的总长度
-
- 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);
- 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) { //由于inums数组中存储的是随机接口编号,所以这里通过从小到大的顺序检测是否正常,否则输出调试警告
- 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;
- }
-
- //sizeof(*intfc): 接口缓存的长度
- //sizeof(struct usb_host_interface) * j: 表示一个主机控制的长度*接口个数
- 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; //处理设备中要求的接口个数,之外的接口数据
- 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 += i;
- size -= i;
-
- /* Parse all the interface/altsetting descriptors */
- 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;
- }
- while (size > 0) {
- //解析接口数据
- retval = usb_parse_interface(ddev, cfgno, config,
- buffer, size, inums, nalts);
- if (retval < 0)
- return retval;
-
- buffer += retval;
- size -= retval;
- }
- 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 += 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 = d->bInterfaceNumber; //接口编号
- for (i = 0; i < config->desc.bNumInterfaces; ++i) { //根据设备中获取的接口总数,遍历接口,匹配与当前inum接口编号相等的
- 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;
- 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;
- }
- }
-
- ++intfc->num_altsetting;
- 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;
- 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 */
- 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) {
- if (((struct usb_descriptor_header *) buffer)->bDescriptorType
- == USB_DT_INTERFACE)
- break;
-
- //解析端点
- retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,
- num_ep, buffer, size);
- if (retval < 0)
- return retval;
- ++n;
-
- buffer += retval;
- size -= retval;
- }
-
- 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;
- }
- //解析端点
- retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,
- num_ep, buffer, size);
- 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; //获取端点描述符
- buffer += d->bLength;
- size -= d->bLength;
-
- 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 */
- if (ifp->desc.bNumEndpoints >= num_ep)
- goto skip_to_next_endpoint_or_interface_descriptor;
-
- endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
- ++ifp->desc.bNumEndpoints;
-
- 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. */
-
- //根据不同速率的usb,计算时间
- 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;
- }
-
- /* 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 (usb_endpoint_maxp(&endpoint->desc) > 8)
- endpoint->desc.wMaxPacketSize = cpu_to_le16(8); //低速设备端点字节为8个
- }
-
- /*
- * Some buggy high speed devices have bulk endpoints using
- * maxpacket sizes larger than 64 under full-speed mode.
- * Full speed HCDs may not
- * be able to handle that particular bug, so let's modify
- * the maxpacket size to make it work.
- */
- if (to_usb_device(ddev)->speed == USB_SPEED_FULL
- && usb_endpoint_xfer_bulk(d)) {
-
- if (usb_endpoint_maxp(&endpoint->desc) > 64)
- endpoint->desc.wMaxPacketSize = cpu_to_le16(64); //全速设备端点字节为64个
- }
-
- /*
- * 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 = usb_endpoint_maxp(&endpoint->desc) & 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);
- }
-
- /* Parse a possible SuperSpeed endpoint companion descriptor */
- if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
- usb_parse_ss_endpoint_companion(ddev, cfgno,
- inum, asnum, endpoint, buffer, size);
-
- /* 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,传输不同的字节数,以及主机查询端点的间隔时间。至此分析完了枚举一个usb主机控制器的过程:设备-->N个配置-->N个接口-->N个端点,最后通过如下函数输出控制器的功能信息
announce_device(udev);
- static void announce_device(struct usb_device *udev)
- {
- dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
- dev_info(&udev->dev,
- "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
- udev->descriptor.iManufacturer,
- udev->descriptor.iProduct,
- udev->descriptor.iSerialNumber);
- show_string(udev, "Product", udev->product);
- show_string(udev, "Manufacturer", udev->manufacturer);
- show_string(udev, "SerialNumber", udev->serial);
- }
系统启动时输出上述信息:
- usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
- usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
- usb usb1: Product: Nuvoton NUC970 EHCI Host Controller
- usb usb1: Manufacturer: Linux 3.10.32 ehci_hcd
- usb usb1: SerialNumber: nuc970-ehci
本文开始通过platform总线完成ehci设备和驱动的匹配调用探测函数ehci_nuc970_probe(),在该函数内部完成主机控制器的寄存器资源分配,然后注册一个hcd主机控制器(包括是否使用DMA池),然后增加主机控制器到usb总线上,然后注册一个根hub,期间包括最重要的部分,即设备枚举,在枚举的过程,先获取设备,通过设备获取接口,因接口长度未定,所以分两次读取接口信息,即第一次读取固定长度的接口信息,第二次根据第一次的描述符信息里的长度再读取整个接口信息,最后根据接口信息解析端点,最后将该主机控制器的根hub注册到usb总线上。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。