為了解決一個問題,簡單看了一遍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的過程。