usb hub和usb device注册过程

来源:互联网 发布:潍坊行知学校新地址 编辑:程序博客网 时间:2024/05/16 17:42

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 0