为了解决一个问题,简单看了一遍linux gadget驱动的加载流程.做一下记录.
使用的内核为linux 2.6.35 硬件为芯唐NUC950. gadget是在UDC驱动上面的一层,如果要编写gadget驱动只需调用linux 的gadget API,不需设计底层的UDC驱动. 但要是分析驱动BUG,就需要了同时了解一下UDC.
下面以简单的gadget zero驱动分析驱动的加载流程.
主要是一系列的bind的调用,让gadget驱动一步步与硬件的端点联系起来.
从insmod g_zero.ko开始.
zero.c
1 static struct usb_composite_driver zero_driver = { 2 .name = "zero", 3 .dev = &device_desc, 4 .strings = dev_strings, 5 .bind = zero_bind, 6 .unbind = zero_unbind, 7 .suspend = zero_suspend, 8 .resume = zero_resume, 9 };
这个结构体是zero.c中的,如果是自己写的gadget驱动,这个结构体及这些函数需要自己实现.
先不去细看结构体中的具体内容,现在只关注注册流程.
1 static int __init init(void) 2 { 3 return usb_composite_register(&zero_driver); 4 }
调用
usb_composite_register(&zero_driver);
zero_driver作为参数传递,类型为struct usb_composite_driver
composite.c
int usb_composite_register(struct usb_composite_driver *driver)//zero_driver { if (!driver || !driver->dev || !driver->bind || composite) return -EINVAL; if (!driver->name) driver->name = "composite"; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; composite = driver; return usb_gadget_register_driver(&composite_driver); }
composite_driver定义在composite.c中
1 static struct usb_gadget_driver composite_driver = { 2 .speed = USB_SPEED_HIGH, 3 4 .bind = composite_bind, 5 .unbind = composite_unbind, 6 7 .setup = composite_setup, 8 .disconnect = composite_disconnect, 9 10 .suspend = composite_suspend, 11 .resume = composite_resume, 12 13 .driver = { 14 .owner = THIS_MODULE, 15 }, 16 };
composite = driver;
用全局指针指向zero_driver,后面用到compoite这个指针时候知道它的值在这里赋好了.
最后调用usb_gadget_register_driver(&composite_driver);
不同的芯片实现不同,但原理应该类似,一般在xxx_udc.c中
nuc950在nuc900_udc.c中:
1 int usb_gadget_register_driver (struct usb_gadget_driver *driver) 2 { 3 struct nuc900_udc *udc = &controller; 4 int retval; 5 6 7 printk("usb_gadget_register_driver() '%s'\n", driver->driver.name); 8 9 if (!udc) 10 return -ENODEV; 11 12 if (udc->driver) 13 return -EBUSY; 14 if (!driver->bind || !driver->unbind || !driver->setup 15 || driver->speed == USB_SPEED_UNKNOWN) 16 return -EINVAL; 17 printk("driver->speed=%d\n", driver->speed); 18 udc->gadget.name = gadget_name; 19 udc->gadget.ops = &nuc900_ops; 20 udc->gadget.is_dualspeed = 1; 21 udc->gadget.speed = USB_SPEED_HIGH;//USB_SPEED_FULL; 22 udc->ep0state = EP0_IDLE; 23 24 udc->gadget.dev.release = nop_release; 25 26 udc->driver = driver; 27 28 udc->gadget.dev.driver = &driver->driver; 29 30 printk( "binding gadget driver '%s'\n", driver->driver.name); 31 if ((retval = driver->bind (&udc->gadget)) != 0) { 32 printk("bind fail\n"); 33 udc->driver = 0; 34 udc->gadget.dev.driver = 0; 35 return retval; 36 } 37 printk( "after driver bind:%p\n" , driver->bind); 38 39 mdelay(300); 40 __raw_writel(__raw_readl(REG_PWRON) | 0x400, REG_PWRON);//power on usb D+ high 41 42 return 0; 43 }
controller是udc中很重要的一个变量,结构为
1 struct nuc900_udc { 2 spinlock_t lock; 3 4 struct nuc900_ep ep[NUC900_ENDPOINTS]; 5 struct usb_gadget gadget; 6 struct usb_gadget_driver *driver; 7 struct platform_device *pdev; 8 9 struct clk *clk; 10 struct resource *res; 11 void __iomem *reg; 12 int irq; 13 14 enum ep0_state ep0state; 15 16 u8 usb_devstate; 17 u8 usb_address; 18 19 20 u8 usb_dma_dir; 21 22 u8 usb_dma_trigger;//bool. dma triggered 23 u8 usb_dma_trigger_next;//need trigger again 24 u8 usb_less_mps; 25 u32 usb_dma_cnt;//one dma transfer count 26 u32 usb_dma_loop;//for short packet only;dma loop, each loop 32byte; 27 u32 usb_dma_owner; 28 29 struct usb_ctrlrequest crq; 30 s32 setup_ret; 31 32 u32 irq_enbl; 33 };
这个结构中大部分不需要关注,需要关注的是第5行:
struct usb_gadget gadget;
定义在gadget.h中,这linux标准的结构体:
1 struct usb_gadget { 2 /* readonly to gadget driver */ 3 const struct usb_gadget_ops *ops; 4 struct usb_ep *ep0; 5 struct list_head ep_list; /* of usb_ep */ 6 enum usb_device_speed speed; 7 unsigned is_dualspeed:1; 8 unsigned is_otg:1; 9 unsigned is_a_peripheral:1; 10 unsigned b_hnp_enable:1; 11 unsigned a_hnp_support:1; 12 unsigned a_alt_hnp_support:1; 13 const char *name; 14 struct device dev; 15 };
大致先扫一下这个结构,然后回到
usb_gadget_register_driver函数。
大体意思就是对上面的结构体进行了一番赋值,具体意义再回头看
然后在31行调用
if ((retval = driver->bind (&udc->gadget)) != 0)
第一个bind被调用了。
继续贴代码
1 static int composite_bind(struct usb_gadget *gadget) 2 { 3 struct usb_composite_dev *cdev; 4 int status = -ENOMEM; 5 6 cdev = kzalloc(sizeof *cdev, GFP_KERNEL); 7 if (!cdev) 8 return status; 9 10 spin_lock_init(&cdev->lock); 11 cdev->gadget = gadget; 12 set_gadget_data(gadget, cdev); 13 INIT_LIST_HEAD(&cdev->configs); 14 15 /* preallocate control response and buffer */ 16 cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); 17 if (!cdev->req) 18 goto fail; 19 cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); 20 if (!cdev->req->buf) 21 goto fail; 22 cdev->req->complete = composite_setup_complete; 23 gadget->ep0->driver_data = cdev; 24 25 cdev->bufsiz = USB_BUFSIZ; 26 cdev->driver = composite; 27 28 usb_gadget_set_selfpowered(gadget); 29 30 /* interface and string IDs start at zero via kzalloc. 31 * we force endpoints to start unassigned; few controller 32 * drivers will zero ep->driver_data. 33 */ 34 usb_ep_autoconfig_reset(cdev->gadget); 35 36 /* standardized runtime overrides for device ID data */ 37 if (idVendor) 38 cdev->desc.idVendor = cpu_to_le16(idVendor); 39 if (idProduct) 40 cdev->desc.idProduct = cpu_to_le16(idProduct); 41 if (bcdDevice) 42 cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); 43 44 /* composite gadget needs to assign strings for whole device (like 45 * serial number), register function drivers, potentially update 46 * power state and consumption, etc 47 */ 48 status = composite->bind(cdev); 49 if (status < 0) 50 goto fail; 51 52 cdev->desc = *composite->dev; 53 cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; 54 55 /* strings can't be assigned before bind() allocates the 56 * releavnt identifiers 57 */ 58 if (cdev->desc.iManufacturer && iManufacturer) 59 string_override(composite->strings, 60 cdev->desc.iManufacturer, iManufacturer); 61 if (cdev->desc.iProduct && iProduct) 62 string_override(composite->strings, 63 cdev->desc.iProduct, iProduct); 64 if (cdev->desc.iSerialNumber && iSerialNumber) 65 string_override(composite->strings, 66 cdev->desc.iSerialNumber, iSerialNumber); 67 68 status = device_create_file(&gadget->dev, &dev_attr_suspended); 69 if (status) 70 goto fail; 71 72 INFO(cdev, "%s ready\n", composite->name); 73 return 0; 74 75 fail: 76 composite_unbind(gadget); 77 return status; 78 }
还是简单分析
11~12行就是你中有我,我中有你
13行值得注意一下,初始化一个链表,config就是配置链表。
一个设备可能有多个配置
一个配置可能有多个接口
一个接口可能有多个端点或设置
15~23行 都与ep0这个控制端口有关,控制端口的相关内直接在设备bind的时候做也比较合理。
26行 cdev->driver = composite; //还记得composite指向的是谁,就是zero_driver
这就bind好了吧。
直接看48行
status = composite->bind(cdev);
第二个bind被调用,
satic int __init zero_bind(struct usb_composite_dev *cdev)
这个函数需要关注的这几行
if (loopdefault) { loopback_add(cdev, autoresume != 0); sourcesink_add(cdev, autoresume != 0); } else { sourcesink_add(cdev, autoresume != 0); loopback_add(cdev, autoresume != 0); }
应该就是gadget zero的两种配置
sourcesink_add()在f_sourcesink.c中,是自己实现的
在此函数中调用
1 return usb_add_config(cdev, &sourcesink_driver);
1 static struct usb_configuration sourcesink_driver = { 2 .label = "source/sink", 3 .strings = sourcesink_strings, 4 .bind = sourcesink_bind_config, 5 .setup = sourcesink_setup, 6 .bConfigurationValue = 3, 7 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 8 /* .iConfiguration = DYNAMIC */ 9 };
注意这个结构体中又出现一个bind
usb_add_config 在composite.c 中
1 int usb_add_config(struct usb_composite_dev *cdev, 2 struct usb_configuration *config) 3 { 4 int status = -EINVAL; 5 struct usb_configuration *c; 6 7 DBG(cdev, "adding config #%u '%s'/%p\n", 8 config->bConfigurationValue, 9 config->label, config); 10 11 if (!config->bConfigurationValue || !config->bind) 12 goto done; 13 14 /* Prevent duplicate configuration identifiers */ 15 list_for_each_entry(c, &cdev->configs, list) { 16 if (c->bConfigurationValue == config->bConfigurationValue) { 17 status = -EBUSY; 18 goto done; 19 } 20 } 21 22 config->cdev = cdev; 23 list_add_tail(&config->list, &cdev->configs); 24 25 INIT_LIST_HEAD(&config->functions); 26 config->next_interface_id = 0; 27 28 status = config->bind(config); 29 if (status < 0) { 30 list_del(&config->list); 31 config->cdev = NULL; 32 } else { 33 unsigned i; 34 35 DBG(cdev, "cfg %d/%p speeds:%s%s\n", 36 config->bConfigurationValue, config, 37 config->highspeed ? " high" : "", 38 config->fullspeed 39 ? (gadget_is_dualspeed(cdev->gadget) 40 ? " full" 41 : " full/low") 42 : ""); 43 44 for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { 45 struct usb_function *f = config->interface[i]; 46 47 if (!f) 48 continue; 49 DBG(cdev, " interface %d = %s/%p\n", 50 i, f->name, f); 51 } 52 } 53 54 /* set_alt(), or next config->bind(), sets up 55 * ep->driver_data as needed. 56 */ 57 usb_ep_autoconfig_reset(cdev->gadget); 58 59 done: 60 if (status) 61 DBG(cdev, "added config '%s'/%u --> %d\n", config->label, 62 config->bConfigurationValue, status); 63 return status; 64 }
23行,把配置插入链表。(bind设备的时候初始化的那个链表)
25行,又初始化一个function链表。(一个配置可以有多个接口)
28行,status = config->bind(config);
第三次调用bind
找到config->bind的真身,在f_sourcesink.c中
1 static int __init sourcesink_bind_config(struct usb_configuration *c) 2 { 3 struct f_sourcesink *ss; 4 int status; 5 6 ss = kzalloc(sizeof *ss, GFP_KERNEL); 7 if (!ss) 8 return -ENOMEM; 9 init_completion(&ss->gdt_completion); 10 ss->function.name = "source/sink"; 11 ss->function.descriptors = fs_source_sink_descs; 12 ss->function.bind = sourcesink_bind; 13 ss->function.unbind = sourcesink_unbind; 14 ss->function.set_alt = sourcesink_set_alt; 15 ss->function.disable = sourcesink_disable; 16 17 status = usb_add_function(c, &ss->function); 18 if (status) 19 kfree(ss); 20 return status; 21 }
留意一下12行function.bind
17行status = usb_add_function(c, &ss->function);
函数在composite.c中
1 int usb_add_function(struct usb_configuration *config, 2 struct usb_function *function) 3 { 4 int value = -EINVAL; 5 6 DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", 7 function->name, function, 8 config->label, config); 9 10 if (!function->set_alt || !function->disable) 11 goto done; 12 13 function->config = config; 14 list_add_tail(&function->list, &config->functions); 15 16 /* REVISIT *require* function->bind? */ 17 if (function->bind) { 18 value = function->bind(config, function); 19 if (value < 0) { 20 list_del(&function->list); 21 function->config = NULL; 22 } 23 } else 24 value = 0; 25 26 /* We allow configurations that don't work at both speeds. 27 * If we run into a lowspeed Linux system, treat it the same 28 * as full speed ... it's the function drivers that will need 29 * to avoid bulk and ISO transfers. 30 */ 31 if (!config->fullspeed && function->descriptors) 32 config->fullspeed = true; 33 if (!config->highspeed && function->hs_descriptors) 34 config->highspeed = true; 35 36 done: 37 if (value) 38 DBG(config->cdev, "adding '%s'/%p --> %d\n", 39 function->name, function, value); 40 return value; 41 }
14行,同样把function插入链表
18行,第四次调用bind
回顾一下第一次bind设备,第二次bind配置,第三次bind接口,第四次该端点了
直接到f_sourcesink.c中:
1 static int __init 2 sourcesink_bind(struct usb_configuration *c, struct usb_function *f) 3 { 4 struct usb_composite_dev *cdev = c->cdev; 5 struct f_sourcesink *ss = func_to_ss(f); 6 int id; 7 8 /* allocate interface ID(s) */ 9 id = usb_interface_id(c, f); 10 if (id < 0) 11 return id; 12 source_sink_intf.bInterfaceNumber = id; 13 14 /* allocate endpoints */ 15 ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); 16 if (!ss->in_ep) { 17 autoconf_fail: 18 ERROR(cdev, "%s: can't autoconfigure on %s\n", 19 f->name, cdev->gadget->name); 20 return -ENODEV; 21 } 22 ss->in_ep->driver_data = cdev; /* claim */ 23 24 ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc); 25 if (!ss->out_ep) 26 goto autoconf_fail; 27 ss->out_ep->driver_data = cdev; /* claim */ 28 29 /* support high speed hardware */ 30 if (gadget_is_dualspeed(c->cdev->gadget)) { 31 hs_source_desc.bEndpointAddress = 32 fs_source_desc.bEndpointAddress; 33 hs_sink_desc.bEndpointAddress = 34 fs_sink_desc.bEndpointAddress; 35 f->hs_descriptors = hs_source_sink_descs; 36 } 37 38 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", 39 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", 40 f->name, ss->in_ep->name, ss->out_ep->name); 41 return 0; 42 }
15 和24 行分别获得了一个端口。 gadget zero设备使用了两个端口来收发数据。
以上差不多就是gadget驱动的注册和bind的过程。