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驱动。







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
The USB Device Tree Viewer, short UsbTreeView is based upon the Microsoft "USBView" sample application found in the Windows Driver Development Kits and now standalone at GitHub. But it is source code only, there is no executable for end users provided. Meanwhile USBView comes as executables as part of the "Debugging Tools für Windows", see here: USBView. UsbTreeView started with the USBView source code from the DDK for Server 2003. Here are the improvements I've done: Informations from the Windows Device Management are collected and matched with the found USB devices; Therefore UsbTreeView can show the child devices, including drive letters and COM-ports Window position is saved Background color and font of the right pane can be set (the font shown in the screenshots is DOSLike 7) Text output rearranged Keeps the tree item selection over refresh way more descriptors are decoded, as Audio 2.0 Hexdump of the descriptors can be shown Safe removal, device restart and port restart Extended USB information available under Windows 8 (taken from the latest USBView sample application) Extended information about host controllers Enumeration of the USB devices accelerated and independent from the treeview Failed USB requests are re-tried in the background, e.g. if a USB mouse was moved while requesting its properties Toolbar with jump-lists for easily finding devices in complex trees TreeView with handmade 16x16 icons, USBView used 32x32 icons scaled down to 15x15 many minor improvements With V3.0 No more enumeration of all devices on arrival and removal of a USB device Search function (not full text, only things like device ID, drive letter, volume name etc) Some new Keyboard shortcuts (Alt+D to open the drives list, Alt+O the Others list, Alt+S to focus the search edit, Alt+Left/Right to cycle thru the search hits Options not to expand empty hubs or hub with only empty hubs attached Options to jump to arrived and removed devices Option to expand tree items to make selected

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值