Linux USB Gadget--各環(huán)節(jié)的整合
2013-07-22 16:12:23
Linux USB Gadget
軟件結(jié)構(gòu)一文中分析Linux USB Gadget軟件分為三層。這三層其中兩層是與硬件無關(guān)的,分別是Gadget功能驅(qū)動(dòng)層,USB設(shè)備層。一層是
與硬件相關(guān)的是UDC層。每一層都提供一種關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)與函數(shù)與其他層交互。 Gadget功能驅(qū)動(dòng)層: 最主要的結(jié)構(gòu)是struct usb_composite_driver,這個(gè)結(jié)構(gòu)在這層定義,并且實(shí)現(xiàn)結(jié)構(gòu)中的各個(gè)函數(shù)。 USB設(shè)備層: 最主要的數(shù)據(jù)結(jié)構(gòu)是struct usb_composite_dev與usb_gadget_driver。前一個(gè)代表一個(gè)USB設(shè)備,而后一個(gè)是Gadget驅(qū)動(dòng),與UDC層交互。 UDC層: 最主要的數(shù)據(jù)結(jié)構(gòu)是struct usb_gadget,通常包含在其他結(jié)構(gòu)體中。這個(gè)結(jié)構(gòu)體代表了一個(gè)USB設(shè)備控制器的所有關(guān)于USB通信的信息。 UDC
層提供usb_gadget_unregister_driver(struct usb_gadget_driver *driver)函數(shù),這個(gè)函數(shù)
由USB設(shè)備層調(diào)用,USB設(shè)備層將自己定義的struct usb_gadget_driver結(jié)構(gòu)變量傳遞給他。USB設(shè)備層提供
usb_composite_register(struct usb_composite_driver *driver)函數(shù),這個(gè)函數(shù)由
Gadget功能驅(qū)動(dòng)層調(diào)用,Gadget功能驅(qū)動(dòng)層將自己定義的struct usb_composite_driver 結(jié)構(gòu)變量傳遞給他。下面詳細(xì)
分析一下這三層是如何結(jié)合在一起的。我們將以zero Gadget功能驅(qū)動(dòng)為例子,s3c2410_udc作為底層UDC。 首先先看一下zero Gadget功能驅(qū)動(dòng),他是作為一個(gè)模塊注冊(cè)到內(nèi)核中的,首先分析一下他的模塊初始化函數(shù):
staticint __init init(void) { return usb_composite_register(&zero_driver); }
很簡(jiǎn)單,只是調(diào)用了usb_composite_register,傳遞給他的參數(shù)是zero_driver。這個(gè)結(jié)構(gòu)體如下定義:
staticstruct usb_composite_driver zero_driver = { .name = "zero", .dev = &device_desc, .strings = dev_strings, .bind = zero_bind, .unbind = zero_unbind, .suspend = zero_suspend, .resume = zero_resume, };
以上函數(shù)都是在zero.c中實(shí)現(xiàn)的,比較重要的函數(shù)是zero_bind。目前暫時(shí)不列出這個(gè)函數(shù),等用到的時(shí)候再說。下面看一下usb_composite_register函數(shù),他是由USB設(shè)備層提供的,定義在composite.c中:
int __init usb_composite_register(struct usb_composite_driver *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); }
這個(gè)函數(shù)主要的目的是初始化兩個(gè)結(jié)構(gòu)體變量,一個(gè)是composite_driver,這個(gè)是USB設(shè)備層定義的一個(gè)全局struct usb_gadget_driver變量,如下:
staticstruct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, .bind = composite_bind, .unbind = __exit_p(composite_unbind), .setup = composite_setup, .disconnect = composite_disconnect, .suspend = composite_suspend, .resume = composite_resume, .driver = { .owner = THIS_MODULE, }, };
這
些函數(shù)都要在USB設(shè)備層實(shí)現(xiàn)。usb_composite_register將composite_driver的function初始化
為"zero"。driver是 struct device_driver結(jié)構(gòu)體。linux設(shè)備模型中使用。名字初始化為“zero”。另外一個(gè)變量
是composite,它是一個(gè)USB設(shè)備層定義的struct usb_composite_driver的指針,這樣composite就指向了
zero_driver。因此zero Gadget功能驅(qū)動(dòng)層就和USB設(shè)備層聯(lián)系到了一起。最后usb_composite_register函數(shù)調(diào)
用usb_gadget_register_driver,開始向UDC層聯(lián)系。這個(gè)函數(shù)定義在UDC層,系統(tǒng)每個(gè)UDC都要實(shí)現(xiàn)這樣一個(gè)函數(shù)。我們看一
下s3c2410_udc這個(gè)函數(shù)的實(shí)現(xiàn):
int usb_gadget_register_driver(struct usb_gadget_driver *driver) { struct s3c2410_udc *udc = the_controller; int retval; dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n", driver->driver.name); if (!udc) return -ENODEV; if (udc->driver) return -EBUSY; if (!driver->bind || !driver->setup || driver->speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", driver->bind, driver->setup, driver->speed); return -EINVAL; } #if defined(MODULE) if (!driver->unbind) { printk(KERN_ERR "Invalid driver: no unbind method\n"); return -EINVAL; } #endif udc->driver = driver; udc->gadget.dev.driver = &driver->driver; if ((retval = device_add(&udc->gadget.dev)) != 0) { printk(KERN_ERR "Error in device_add() : %d\n",retval); goto register_error; } dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&udc->gadget)) != 0) { device_del(&udc->gadget.dev); goto register_error; } s3c2410_udc_enable(udc); return 0; register_error: udc->driver = NULL; udc->gadget.dev.driver = NULL; return retval; }
這
個(gè)函數(shù)最開始的功能是將UDC層與USB設(shè)備層聯(lián)系在一起,然后調(diào)用driver->bind (&udc->gadget)函數(shù)。
開始了最重要的綁定工作。只有這個(gè)函數(shù)執(zhí)行完畢這三層才真正的結(jié)合在一起,USB設(shè)備正常的工作。driver就是傳遞過來的在USB設(shè)備層定義的
composite_driver。所以driver->bind (&udc->gadget)函數(shù)是在composite.c中
定義的,如下:
staticint __init composite_bind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; int status = -ENOMEM; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); if (!cdev) return status; spin_lock_init(&cdev->lock); cdev->gadget = gadget; set_gadget_data(gadget, cdev); INIT_LIST_HEAD(&cdev->configs); cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!cdev->req) goto fail; cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; cdev->req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; cdev->bufsiz = USB_BUFSIZ; cdev->driver = composite; usb_gadget_set_selfpowered(gadget); usb_ep_autoconfig_reset(cdev->gadget); status = composite->bind(cdev); if (status < 0) goto fail; cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; if (idVendor) cdev->desc.idVendor = cpu_to_le16(idVendor); if (idProduct) cdev->desc.idProduct = cpu_to_le16(idProduct); if (bcdDevice) cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); if (cdev->desc.iManufacturer && iManufacturer) string_override(composite->strings, cdev->desc.iManufacturer, iManufacturer); if (cdev->desc.iProduct && iProduct) string_override(composite->strings, cdev->desc.iProduct, iProduct); if (cdev->desc.iSerialNumber && iSerialNumber) string_override(composite->strings, cdev->desc.iSerialNumber, iSerialNumber); INFO(cdev, "%s ready\n", composite->name); return 0; fail: composite_unbind(gadget); return status; }
composite_bind
首先定義并初始化了struct usb_composite_dev結(jié)構(gòu)體,通過cdev->gadget = gadget;這條語句將設(shè)備與
底層的gadget聯(lián)系在一起,通過cdev->driver = composite,這條語句將設(shè)備與Gadget功能驅(qū)動(dòng)聯(lián)系在一起。并且給
設(shè)備端點(diǎn)0分配了一個(gè)struct usb_request,這個(gè)結(jié)構(gòu)在USB枚舉將發(fā)揮重要的作用。然后調(diào)用Gadget功能驅(qū)動(dòng)層的bind函數(shù)。最
后初始化了USB設(shè)備描述符。這個(gè)函數(shù)最重要的一步就是調(diào)用了Gadget功能驅(qū)動(dòng)層的bind函數(shù)。這樣,三個(gè)軟件層才真正的聯(lián)系在了一起。
zero Gadget功能驅(qū)動(dòng)層的 bind函數(shù)定義在zero.c中,如下:
staticint __init zero_bind(struct usb_composite_dev *cdev) { int gcnum; struct usb_gadget *gadget = cdev->gadget; int id; id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_MANUFACTURER_IDX].id = id; device_desc.iManufacturer = id; id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_PRODUCT_IDX].id = id; device_desc.iProduct = id; id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); if (loopdefault) { loopback_add(cdev, autoresume != 0); if (!gadget_is_sh(gadget)) sourcesink_add(cdev, autoresume != 0); } else { sourcesink_add(cdev, autoresume != 0); if (!gadget_is_sh(gadget)) loopback_add(cdev, autoresume != 0); } gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); else { pr_warning("%s: controller '%s' not recognized\n", longname, gadget->name); device_desc.bcdDevice = cpu_to_le16(0x9999); } INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", init_utsname()->sysname, init_utsname()->release, gadget->name); return 0; }
zero_bind
函數(shù)首先就是設(shè)置了幾個(gè)字符串描述符的id,然后就設(shè)置USB配置。主要調(diào)用了sourcesink_add函數(shù),傳遞給的參數(shù)是cdev,就是USB設(shè)
備層定義的USB設(shè)備結(jié)構(gòu)體。這個(gè)函數(shù)定義在f_sourcesink.c,這個(gè)文件以頭文件的形式包含在zero.c中。如下所示:
int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) { int id; id = usb_string_id(cdev); if (id < 0) return id; strings_sourcesink[0].id = id; source_sink_intf.iInterface = id; sourcesink_driver.iConfiguration = id; if (autoresume) sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; if (gadget_is_otg(cdev->gadget)) { sourcesink_driver.descriptors = otg_desc; sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } return usb_add_config(cdev, &sourcesink_driver); } 在分析這個(gè)函數(shù)之前首先先看一下f_sourcesink.c中關(guān)鍵的一個(gè)數(shù)據(jù)結(jié)構(gòu),sourcesink_driver。他代表了一個(gè)USB配置,里面說明了配置的功能。如下: staticstruct usb_configuration sourcesink_driver = { .label = "source/sink", .strings = sourcesink_strings, .bind = sourcesink_bind_config, .setup = sourcesink_setup, .bConfigurationValue = 3, .bmAttributes = USB_CONFIG_ATT_SELFPOWER, };
看
完了這個(gè)數(shù)據(jù)結(jié)構(gòu),我們分析一下sourcesink_add最后調(diào)用的函數(shù)
usb_add_config(cdev, &sourcesink_driver),這個(gè)函數(shù)傳遞的參數(shù)一個(gè)是USB設(shè)備一個(gè)是USB配置。顯
然功能是給USB設(shè)備增加一個(gè)配置。函數(shù)定義在composite.c中,如下:
int __init usb_add_config(struct usb_composite_dev *cdev, struct usb_configuration *config) { int status = -EINVAL; struct usb_configuration *c; DBG(cdev, "adding config #%u '%s'/%p\n", config->bConfigurationValue, config->label, config); if (!config->bConfigurationValue || !config->bind) goto done; list_for_each_entry(c, &cdev->configs, list) { if (c->bConfigurationValue == config->bConfigurationValue) { status = -EBUSY; goto done; } } config->cdev = cdev; list_add_tail(&config->list, &cdev->configs); INIT_LIST_HEAD(&config->functions); config->next_interface_id = 0; status = config->bind(config); if (status < 0) { list_del(&config->list); config->cdev = NULL; } else { unsigned i; DBG(cdev, "cfg %d/%p speeds:%s%s\n", config->bConfigurationValue, config, config->highspeed ? " high" : "", config->fullspeed (gadget_is_dualspeed(cdev->gadget) " full" : " full/low") : ""); for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { struct usb_function *f = config->interface[i]; if (!f) continue; DBG(cdev, " interface %d = %s/%p\n", i, f->name, f); } } usb_ep_autoconfig_reset(cdev->gadget); done: if (status) DBG(cdev, "added config '%s'/%u --> %d\n", config->label, config->bConfigurationValue, status); return status; }
這個(gè)函數(shù)初始化了配置,將配置與設(shè)備聯(lián)系在一起,并且打印一些調(diào)試信息。這樣設(shè)備有了配置,但是我們知道一個(gè)USB設(shè)備的配置下是接口的集合。所以函數(shù)調(diào)用config->bind(config)給配置添加接口。這個(gè)函數(shù)如下:
staticint __init sourcesink_bind_config(struct usb_configuration *c) { struct f_sourcesink *ss; int status; ss = kzalloc(sizeof *ss, GFP_KERNEL); if (!ss) return -ENOMEM; ss->function.name = "source/sink"; ss->function.descriptors = fs_source_sink_descs; ss->function.bind = sourcesink_bind; ss->function.unbind = sourcesink_unbind; ss->function.set_alt = sourcesink_set_alt; ss->function.disable = sourcesink_disable; status = usb_add_function(c, &ss->function); if (status) kfree(ss); return status; }
可
以看出這個(gè)函數(shù)分配并初始化了一個(gè)struct f_sourcesink結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體包含代表接口的struct usb_function。并
且初始化了struct usb_function的一下回調(diào)函數(shù)。最后調(diào)用
usb_add_function(c, &ss->function);將接口添加到配置中。usb_add_function函數(shù)如下
所示:
int __init usb_add_function(struct usb_configuration *config, struct usb_function *function) { int value = -EINVAL; DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", function->name, function, config->label, config); if (!function->set_alt || !function->disable) goto done; function->config = config; list_add_tail(&function->list, &config->functions); if (function->bind) { value = function->bind(config, function); if (value < 0) { list_del(&function->list); function->config = NULL; } } else value = 0; if (!config->fullspeed && function->descriptors) config->fullspeed = true; if (!config->highspeed && function->hs_descriptors) config->highspeed = true; done: if (value) DBG(config->cdev, "adding '%s'/%p --> %d\n", function->name, function, value); return value; }
我們可以看到這個(gè)函數(shù)最主要的就是聯(lián)系接口與配置。并且調(diào)用接口的bind函數(shù),zero sourcesink配置的接口的bind為sourcesink_bind。如下定義:
staticint __init sourcesink_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_sourcesink *ss = func_to_ss(f); int id; id = usb_interface_id(c, f); if (id < 0) return id; source_sink_intf.bInterfaceNumber = id; ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); if (!ss->in_ep) { autoconf_fail: ERROR(cdev, "%s: can't autoconfigure on %s\n", f->name, cdev->gadget->name); return -ENODEV; } ss->in_ep->driver_data = cdev; ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc); if (!ss->out_ep) goto autoconf_fail; ss->out_ep->driver_data = cdev; if (gadget_is_dualspeed(c->cdev->gadget)) { hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; f->hs_descriptors = hs_source_sink_descs; } DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", f->name, ss->in_ep->name, ss->out_ep->name); return 0; }
這
個(gè)函數(shù)除了初始化接口的接口id。另外就是給接口分配端點(diǎn)了。這也是各層整合的最后一步了。zero sourcesink有一個(gè)配置,一個(gè)接口。這個(gè)接
口有兩個(gè)端點(diǎn),一個(gè)in端點(diǎn)一個(gè)Out端點(diǎn)。usb_ep_autoconfig 函數(shù)就擔(dān)當(dāng)了分配端點(diǎn)的任務(wù),他定義在epautoconf.c中,這
個(gè)文件以頭文件的形式包含在了zero.c中。這個(gè)函數(shù)有兩個(gè)參數(shù)一個(gè)是struct usb_gadget類型的指針,一個(gè)是
struct usb_endpoint_descriptor類型的指針,也就是端點(diǎn)描述符,這個(gè)函數(shù)根據(jù)端點(diǎn)描述符的信息,自動(dòng)在
struct usb_gadget里找到合適的端點(diǎn)。 經(jīng)過上面的重重函數(shù)調(diào)用,現(xiàn)在設(shè)備終于飽滿了,既有配置了,也有接口了,
接口里也有相應(yīng)的端點(diǎn)了。各層的關(guān)系也都聯(lián)系起來了。但是還是有一點(diǎn)就是感覺有點(diǎn)暈。確實(shí)這么多的函數(shù)調(diào)用,不暈都沒辦法呀。沒關(guān)系,我們來重新梳理一下
各個(gè)函數(shù)之間的調(diào)用關(guān)系以及各環(huán)節(jié)整合的過程。這個(gè)整合的過程大體分為兩個(gè)過程: (1) 過程方向 Gadget功能驅(qū)動(dòng)層-->USB設(shè)備層-->UDC層。 以四個(gè)數(shù)據(jù)結(jié)構(gòu)為基礎(chǔ):struct usb_composite_driver struct usb_composite_dev struct usb_gadget_driver struct usb_gadget 兩個(gè)register函數(shù)為導(dǎo)向: usb_composite_register(&zero_driver) usb_gadget_register_driver(&composite_driver) (2) 過程方向 UDC層-->USB設(shè)備層-->Gadget功能驅(qū)動(dòng)層 四個(gè)bind函數(shù)為串聯(lián)點(diǎn),帶出一連串?dāng)?shù)據(jù)結(jié)構(gòu)與初始化。這四個(gè)bind函數(shù)分配是: USB
設(shè)備層的composite_bind 由UDC層的usb_gadget_register_driver函數(shù)調(diào)用。功能是分配
struct usb_composite_dev cdev 并初始化。struct usb_composite_dev結(jié)構(gòu)串聯(lián)了UDC層的
usb_gadget與Gadget功能驅(qū)動(dòng)層的usb_composite_driver。并且調(diào)用下一個(gè)上層的bind Gadget功能驅(qū)動(dòng)層的zero_bind 這個(gè)函數(shù)主要的任務(wù)就是用Gadget功能驅(qū)動(dòng)層的USB設(shè)備信息去進(jìn)一步初始化struct usb_composite_dev結(jié)構(gòu)。并且引出下面兩個(gè)bind函數(shù)。 另
外兩個(gè)bind函數(shù)都是與USB設(shè)備信息相關(guān),一個(gè)是添加配置時(shí)調(diào)用的,一個(gè)是添加接口的時(shí)候調(diào)用的。這兩個(gè)函數(shù)由sourcesink_add引
出。 usb_add_config將配置添加到設(shè)備中引出config->bind:sourcesink_bind_config.這個(gè)
bind分配并初始化接口,調(diào)用usb_add_function將接口添加到配置到,usb_add_function引出
function->bind:sourcesink_bind 根據(jù)功能,在gadget里查找合適的端點(diǎn)。并進(jìn)一步初始化
struct usb_composite_dev。我們發(fā)現(xiàn)這些bind就是一個(gè)目的,初始化struct usb_composite_dev結(jié)構(gòu),
使其逐漸豐滿。因?yàn)檫@個(gè)結(jié)構(gòu)代表一個(gè)USB設(shè)備。經(jīng)過合適的初始化后設(shè)備才能正確的工作。經(jīng)過重重初始化,三層總算整合在了一起了。這三層最終形成了一個(gè)
飽滿的struct usb_composite_dev結(jié)構(gòu)。這個(gè)結(jié)構(gòu)包含USB設(shè)備運(yùn)行各種信息。包括:配置,接口,端點(diǎn)等。我們?cè)賮砜匆幌逻@個(gè)結(jié)
構(gòu):
struct usb_composite_dev { struct usb_gadget *gadget; struct usb_request *req; unsigned bufsiz; struct usb_configuration *config; struct usb_device_descriptor desc; struct list_head configs; struct usb_composite_driver *driver; u8 next_string_id; unsigned deactivations; spinlock_t lock; };
經(jīng)
過初始化設(shè)備已經(jīng)準(zhǔn)備好了,將mini2440插入U(xiǎn)SB主機(jī),就開始了設(shè)備枚舉.這就涉及到了主機(jī)與設(shè)備的通信。以后再分析USB設(shè)備枚舉與數(shù)據(jù)傳輸過
程。Linux USB Gadget雖然有三層軟件結(jié)構(gòu)。但是只有UDC層與Gadget功能驅(qū)動(dòng)層作為模塊注冊(cè)到內(nèi)核。只有USB設(shè)備層有關(guān)的文件
composite.c是以頭文件的形式包含在各種Gadget功能驅(qū)動(dòng)里的。以前的內(nèi)核代碼沒有USB設(shè)備層的。所有的Gadget功能驅(qū)動(dòng)都必須自己
處理USB設(shè)備相關(guān)的細(xì)節(jié),代碼重復(fù)率較高,所以才出現(xiàn)這個(gè)USB設(shè)備層以以增加代碼的重用性。composite字面上是復(fù)用的意思,不知道是不是為了
原因而命名的。
|