usb hub和usb device注册过程

A10的cpu有两个hub,也就是root hub,作为host用;还有一个otg功能的hub,可以配置成root hub,也可以配置成device,或者两者同时配置(这时候要通过ID脚来决定当前模式),它的端点0支持最大64字节的控制传送,另外具有5个端点(4个批量传输和一个中断传输);root hub下面最多能外接一个hub。如果作为device用,简称udc(USB Device Control);如果作为host用,简称hcd(Host Control Device)。

     他们作为平台设备注册进内核,平台资源在drivers/usb/sun4i_usb/manager/usbc0_platform.c中:

    switch(port_info->port_type){
        case USB_PORT_TYPE_DEVICE:
            platform_device_register(&sw_udc_device);
        break;

        case USB_PORT_TYPE_HOST:
            platform_device_register(&sw_hcd_device);
        break;

        case USB_PORT_TYPE_OTG:
            platform_device_register(&sw_udc_device);
            platform_device_register(&sw_hcd_device);
        break;

        default:
            DMSG_PANIC("ERR: unkown port_type(%d)\n", port_info->port_type);
    }   

平台驱动有两个,udc的在udc/sw_udc.c中:

static int __init udc_init(void)
{
。。。。。。
    retval = platform_driver_probe(&sw_udc_driver, sw_udc_probe);
。。。。。。
}

platform_driver_probe说明注册的是不支持热拔插的设备,并且device必须已经先注册过了的。


如果最为host用,那么,最终会调用sw_hcd_probe_host_only -> sw_hcd_init_controller函数:

allocate_instance(dev, plat->config, ctrl) ->  usb_create_hcd(&sw_hcd_hc_driver, dev, dev_name(dev));//创建hcd

usb_add_hcd(sw_hcd_to_hcd(sw_hcd), -1, 0),注册hcd到USB核心:

int usb_add_hcd(struct usb_hcd *hcd,
        unsigned int irqnum, unsigned long irqflags)
{
。。。。。。 
   if ((retval = usb_register_bus(&hcd->self)) < 0) 
        goto err_register_bus;

    if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {                                                                                                
        dev_err(hcd->self.controller, "unable to allocate root hub\n");
        retval = -ENOMEM;
        goto err_allocate_root_hub;
    }
    hcd->self.root_hub = rhdev;
。。。。。。
    /* 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);
。。。。。。
}
usb_register_bus表示注册一条usb总线,每个hub对应一条,注册后在/sys/bus/usb/devices下可以看到。如果全部作为host用,则A10有3条usb总线了,分别为usb1、usb2、usb3。

usb_alloc_dev前面一篇文章已经分析过了,不过这次注册的是root_hub;

register_root_hub(hcd):

static int register_root_hub(struct usb_hcd *hcd)
{
。。。。。。
    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);
    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);
    }
。。。。。。
}

可以看到,也和前面一篇文章分析的一样,走usb_get_device_descriptor、usb_new_device的过程,这时候匹配到的device_driver也是usb_generic_driver,接着创建表示接口描述符的device匹配到的device_driver是hub_driver,在drivers/usb/core/hub.c中:

int usb_hub_init(void)
{
    if (usb_register(&hub_driver) < 0) { 
        printk(KERN_ERR "%s: can't register hub driver\n",
            usbcore_name);
        return -1;
    }    

    khubd_task = kthread_run(hub_thread, NULL, "khubd");
    if (!IS_ERR(khubd_task))
        return 0;

    /* Fall through if kernel_thread failed */
    usb_deregister(&hub_driver);                                                                                                                               
    printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);

    return -1;
}

和一般的usb设备一样,root hub也是有设备描述符、接口描述符和端点的,也会创建一个device来表示,但是hub还有hub描述符,用来表明这是hub设备;hub只有一个端点,而且必须是输入方向的中断端点。

在probe中最后用创建urb,并用  usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,  hub, endpoint->bInterval);来注册一个中断;

注册完成后hub平时处于休眠状态,当有usb设备插入后,hub_irq中断函数响应:

static void hub_irq(struct urb *urb)
{
。。。。。。

    /* Something happened, let khubd figure it out */
    kick_khubd(hub);
。。。。。。
}

static void kick_khubd(struct usb_hub *hub)
{
    unsigned long   flags;

    spin_lock_irqsave(&hub_event_lock, flags);
    if (!hub->disconnected && list_empty(&hub->event_list)) {
        list_add_tail(&hub->event_list, &hub_event_list);

        /* Suppress autosuspend until khubd runs */
        usb_autopm_get_interface_no_resume(
                to_usb_interface(hub->intfdev));
        wake_up(&khubd_wait);                                                                                                                                  
    }
    spin_unlock_irqrestore(&hub_event_lock, flags);
}

用wake_up来唤醒hub内核线程:

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_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内核线程就是睡眠在wait_event_freezable上,唤醒后调用hub_events来创建新设备。


接着看注册为device的过程sw_udc_probe_device_only:

   static int sw_udc_probe_device_only(struct platform_device *pdev)
{
。。。。。。 
    device_initialize(&udc->gadget.dev);
    udc->gadget.dev.parent = &pdev->dev;
    udc->gadget.dev.dma_mask = pdev->dev.dma_mask;

    is_controller_alive = 1; 
    the_controller = udc; 
    platform_set_drvdata(pdev, udc);

    sw_udc_disable(udc);
    sw_udc_reinit(udc);

    udc->sw_udc_io = &g_sw_udc_io;
    udc->usbc_no = usbd_port_no;
    strcpy((char *)udc->driver_name, gadget_name);
    udc->irq_no  = irq; 
                                                                                                                                                               
    if(is_udc_support_dma()){
        retval = sw_udc_dma_probe(udc);
        if(retval != 0){
            DMSG_PANIC("ERR: sw_udc_dma_probe failef\n");
            retval = -EBUSY;
            goto err; 
        }
    }

    retval = request_irq(irq, sw_udc_irq,
                 IRQF_DISABLED, gadget_name, udc);
。。。。。。
}

创建设备和注册irq,但是并没有把设备添加到设备层中去,因为这个动作是留给其他驱动完成的,在android系统中,如果作为device用,那么就是把硬盘的一个分区模拟成一个u盘设备;或者看成mtp设备;或者adb功能等,而这些功能必须要有usb端点支持才行,所以添加设备动作导出为USB gadget驱动用的。

所以进入drivers/usb/gadget目录下,从Makefile和内核的config文件可以看出,这里涉及到的文件有f_mass_storage.c(对应usb mass storage),android.c,f_mtp.c,f_accessory.c,composite.c等文件,其入口为android.c。

下一篇文章分析gadget驱动。







你可能感兴趣的:(usb hub和usb device注册过程)