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); }
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; }
在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); }
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; }
接着看注册为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); 。。。。。。 }
所以进入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驱动。