很幸運,在公司開發了gadget相關驅動,總結下來,大大小小開發了四個與gadget相關的驅動,字符驅動、g_multi、g_ether、g_zero,在這裏把本身對gadget的開發中本身的感悟記錄之。架構
想要了解gadget,必須瞭解其框架,知道composite、gadget、udc三者之間的聯繫,知道usb描述符的做用。框架
一個usb device有一個設備描述符。ide
有一個或者多個配置描述符函數
一個配置描述符有一個或者多個接口(在gadget端,接口正式命名是usb_func)。oop
一個接口有0個或者多個端點。ui
編寫gadget的關鍵是在於瞭解udc、gadget、composite三者之間的聯繫和架構層次,在實際應用中gadget是不須要咱們去編寫的,須要咱們本身去編寫的是composite層,以及地對udc層的修改,下面開始詳細介紹着三者。spa
一、composite英文意思是複合的意思,估計是編寫usb gadget層設備驅動都整合到一塊兒,經過統一的函數usb_composite_register註冊。功能各異,雜七雜八,因此稱爲複合層吧。設計
在該層,咱們須要注意的相關結構體和函數有以下:code
struct usb_composite_dev { //做爲composite複合設備,全部composite設備都必須實現該設備。 struct usb_gadget *gadget; //設備和gadget交互,gadget和udc交互。 struct usb_request *req; //每一個設備自帶一個usb請求,全部的數據交互都是經過該請求發送的。 struct usb_configuration *config; 一個設備有一個或者多個配置。 /* private: */ /* internals */ unsigned int suspended:1; struct usb_device_descriptor desc; //設備描述符,惟一 struct list_head configs; //配置 struct list_head gstrings; //字符描述 struct usb_composite_driver *driver; //設備綁定的驅動 u8 next_string_id; char *def_manufacturer; //默認製造商 /* the gadget driver won't enable the data pullup * while the deactivation count is nonzero. */ unsigned deactivations; /* the composite driver won't complete the control transfer's * data/status stages till delayed_status is zero. */ int delayed_status; /* protects deactivations and delayed_status counts*/ spinlock_t lock; };
307 struct usb_composite_driver { //全部compesite驅動必須填充該結構體。 308 const char *name; 309 const struct usb_device_descriptor *dev; //必須實現 310 struct usb_gadget_strings **strings; 311 enum usb_device_speed max_speed; 312 unsigned needs_serial:1; 313 314 int (*bind)(struct usb_composite_dev *cdev); //必須實現的 315 int (*unbind)(struct usb_composite_dev *); //必須實現 316 317 void (*disconnect)(struct usb_composite_dev *); 318 319 /* global suspend hooks */ 320 void (*suspend)(struct usb_composite_dev *); 321 void (*resume)(struct usb_composite_dev *); 322 struct usb_gadget_driver gadget_driver; //這個地方的驅動由composite提供,全部和composite相關的驅動都會默認分配該驅動。該驅動是 323 };
852 struct usb_gadget_driver { //該驅動是usbcore和composite之間交互必不可少的一環,二者之間的聯繫主要靠他來維持,內核已經提供好了,不須要咱們去實現。 853 char *function; 854 enum usb_device_speed max_speed; 855 int (*bind)(struct usb_gadget *gadget, 856 struct usb_gadget_driver *driver); 857 void (*unbind)(struct usb_gadget *); 858 int (*setup)(struct usb_gadget *, //枚舉過程當中必不可少的函數。不須要驅動去實現。 859 const struct usb_ctrlrequest *); 860 void (*disconnect)(struct usb_gadget *); 861 void (*suspend)(struct usb_gadget *); 862 void (*resume)(struct usb_gadget *); 863 864 /* FIXME support safe rmmod */ 865 struct device_driver driver; 866 };
1772 static const struct usb_gadget_driver composite_driver_template = { //全部的composite設備都會在註冊gadet驅動的時候採用該實例填充。
//筆者認爲這麼作的緣由是gadget驅動永遠只有一個,composite能夠隨便實現。體現分層的思想。 1773 .bind = composite_bind, 1774 .unbind = composite_unbind, 1775 1776 .setup = composite_setup, 1777 .disconnect = composite_disconnect, 1778 1779 .suspend = composite_suspend, 1780 .resume = composite_resume, 1781 1782 .driver = { 1783 .owner = THIS_MODULE, 1784 }, 1785 };
下面首先介紹composite驅動的註冊過程,講完後介紹驅動的編寫過程。blog
以zero.c爲例:
static int __init init(void) { return usb_composite_register(&zero_driver); }
usb_composite_register(&zero_driver);
1========》 driver->gadget_driver = composite_driver_template; //此過程並未涉及到對compoite設備的註冊的操做,
//而是將composite驅動中註冊的相關信息填充到gadget中,利用gadget去和udc打交道
---->return usb_gadget_probe_driver(gadget_driver); ////該函數首先斷定bind setup等函數是否實現了。不須要咱們去實現。
----> list_for_each_entry(udc, &udc_list, list) //查找註冊在內核中的udc實例,找到了進行下一步操做,沒找到退出。驅動註冊失敗。
----> ret = udc_bind_to_driver(udc, driver); //將udc和gadget驅動綁定在一塊兒。
2======》 udc_bind_to_driver(udc, driver);
---->404 ret = driver->bind(udc->gadget, driver);//最關鍵的莫過於該函數了,最初筆者分析的時候,覺得是composite的bind函數,後來才弄清楚是gadget層
//的bind函數composite_bind ,將在後面介紹。
-----> ret = usb_gadget_udc_start(udc->gadget, driver); //此處能夠理解爲一切就緒,udc相關設置已經寫入寄存器。
-----> ret = usb_gadget_connect(udc->gadget); //插入host usb口,檢查D+電平的變化。也就是枚舉過沖
3=====》 composite_bind //最重要的函數了。是理解gadget設計的關鍵
1672 static int composite_bind(struct usb_gadget *gadget,//該函數zhu要是實現配置描述符接口等操做。 1673 struct usb_gadget_driver *gdriver) 1674 { 1675 struct usb_composite_dev *cdev; 1676 struct usb_composite_driver *composite = to_cdriver(gdriver); 1677 int status = -ENOMEM; 1678 1679 cdev = kzalloc(sizeof *cdev, GFP_KERNEL); 1680 if (!cdev) 1681 return status; 1682 1683 spin_lock_init(&cdev->lock); 1684 cdev->gadget = gadget; 1685 set_gadget_data(gadget, cdev); 1686 INIT_LIST_HEAD(&cdev->configs); 1687 INIT_LIST_HEAD(&cdev->gstrings); 1688 1689 status = composite_dev_prepare(composite, cdev); 1690 if (status) 1691 goto fail; 1692 1693 /* composite gadget needs to assign strings for whole device (like 1694 ┊* serial number), register function drivers, potentially update 1695 ┊* power state and consumption, etc 1696 ┊*/ 1697 /*此處纔是開始調用驅動的bind函數*/ 1698 status = composite->bind(cdev); 1699 if (status < 0) 1700 goto fail; 1701 1702 update_unchanged_dev_desc(&cdev->desc, composite->dev); 1703 1704 /* has userspace failed to provide a serial number? */ 1705 if (composite->needs_serial && !cdev->desc.iSerialNumber) 1706 WARNING(cdev, "userspace failed to provide iSerialNumber\n"); 1707 1708 INFO(cdev, "%s ready\n", composite->name); 1709 return 0; 1710 1711 fail: 1712 __composite_unbind(gadget, false); 1713 return status;
}
1====》 composite_bind
---->1676 struct usb_composite_driver *composite = to_cdriver(gdriver); //這個函數就是將gadet轉換爲composite的關鍵。在gadget驅動註冊時聯繫在一塊兒。
//return container_of(gdrv, struct usb_composite_driver, gadget_driver);
---->cdev = kzalloc(sizeof *cdev, GFP_KERNEL); //實現cdev設備。
---->set_gadget_data(gadget, cdev); //填充私有數據,以便內核中能夠經過gadget獲取cdev.
---->INIT_LIST_HEAD(&cdev->configs); //初始化配置描述鏈表,在開頭本人介紹過,一個設備有一個或者多種配置。
---->1689 status = composite_dev_prepare(composite, cdev); //這個函數十分重要,包括usb_request、complete(回調函數實現)、設備和驅動的綁定等)
---->1698 status = composite->bind(cdev) //此處纔是開始調用驅動的bind函數,後面會詳細介紹該函數。
----> INFO(cdev, "%s ready\n", composite->name); //至此,composite設備建立成功。
1610 int composite_dev_prepare(struct usb_composite_driver *composite, //該函數主要是實現了相當重要的usb_request,針對端點0,即控制端點 1611 struct usb_composite_dev *cdev) 1612 { 1613 struct usb_gadget *gadget = cdev->gadget; 1614 int ret = -ENOMEM; 1615 1616 /* preallocate control response and buffer */ 1617 cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); //申請控制端點usb請求 1618 if (!cdev->req) 1619 return -ENOMEM; 1620 1621 cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); //請求發送內容將保持在此 1622 if (!cdev->req->buf) 1623 goto fail; 1624 1625 ret = device_create_file(&gadget->dev, &dev_attr_suspended);//建立設備文件,位於/sys/class/dev目錄下 1626 if (ret) 1627 goto fail_dev; 1628 1629 cdev->req->complete = composite_setup_complete; //回調函數。 1630 gadget->ep0->driver_data = cdev; //經過端點便可獲取設備。 1631 1632 cdev->driver = composite; //將composite設備和驅動綁定在一塊兒,因此usb gadget端是沒有枚舉過程的,驅動直接註冊成功,建立設備。 1633 1634 /* 1635 ┊* As per USB compliance update, a device that is actively drawing 1636 ┊* more than 100mA from USB must report itself as bus-powered in 1637 ┊* the GetStatus(DEVICE) call. 1638 ┊*/ 1639 if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) 1640 usb_gadget_set_selfpowered(gadget); 1641 1642 /* interface and string IDs start at zero via kzalloc. 1643 ┊* we force endpoints to start unassigned; few controller 1644 ┊* drivers will zero ep->driver_data. 1645 ┊*/ 1646 usb_ep_autoconfig_reset(gadget); // 1647 return 0; 1648 fail_dev
1649 kfree(cdev->req->buf);
1650 fail:
/* 此處知識初始化了usb配置鏈表,並未實例化接口和端點,因此將端點driver_data又重設爲空,批量輸入和輸出點號爲0;
1642 /* interface and string IDs start at zero via kzalloc.
1643 ┊* we force endpoints to start unassigned; few controller
1644 ┊* drivers will zero ep->driver_data.
1645 ┊*/
1646 usb_ep_autoconfig_reset(gadget);
*/
1651 usb_ep_free_request(gadget->ep0, cdev->req);
1652 cdev->req = NULL;
1653 return ret;
1654 }
下面即將進行到相當重要的一環,調用composite驅動的bind函數。
275 static int __init zero_bind(struct usb_composite_dev *cdev) //裏面是實現composite設備的關鍵,設計到strings,配置描述符,接口(function)、端點的實例化。 /276 { 277 struct f_ss_opts *ss_opts; 278 struct f_lb_opts *lb_opts; 279 int status; 280 281 /* Allocate string descriptor numbers ... note that string 282 ┊* contents can be overridden by the composite_dev glue. 283 ┊*/ 284 status = usb_string_ids_tab(cdev, strings_dev); 285 if (status < 0) 286 return status; 287 288 device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;//製造商 289 device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;//產品Id 290 device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id;//設備序列號功能索引,我的認爲是針對多function設備而言的。 291 292 setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); 293 294 func_inst_ss = usb_get_function_instance("SourceSink"); //獲取function,此處的實現十分巧妙,經過usb_function_register實現。 295 if (IS_ERR(func_inst_ss)) 296 return PTR_ERR(func_inst_ss); 297 298 ss_opts = container_of(func_inst_ss, struct f_ss_opts, func_inst); 299 ss_opts->pattern = gzero_options.pattern; 300 ss_opts->isoc_interval = gzero_options.isoc_interval; 301 ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; 302 ss_opts->isoc_mult = gzero_options.isoc_mult; 303 ss_opts->isoc_maxburst = gzero_options.isoc_maxburst; 304 ss_opts->bulk_buflen = gzero_options.bulk_buflen; //每次傳送的buf大小 305 306 func_ss = usb_get_function(func_inst_ss); //獲取source_link實例,一樣經過usb_function_register註冊獲取。 307 if (IS_ERR(func_ss)) { 308 status = PTR_ERR(func_ss); 309 goto err_put_func_inst_ss; 310 } 311 312 func_inst_lb = usb_get_function_instance("Loopback"); 313 if (IS_ERR(func_inst_lb)) { 314 status = PTR_ERR(func_inst_lb); 315 goto err_put_func_ss; 316 } 317 318 lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst); 319 lb_opts->bulk_buflen = gzero_options.bulk_buflen; //在usb_function_registe註冊時就已經分配了。 320 lb_opts->qlen = gzero_options.qlen; 321 322 func_lb = usb_get_function(func_inst_lb); 323 if (IS_ERR(func_lb)) { 324 status = PTR_ERR(func_lb); 325 goto err_put_func_inst_lb; 326 } 327 328 sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id;//設置配置描述符索引 329 loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id; 330 331 /* support autoresume for remote wakeup testing */ 332 sourcesink_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; 333 loopback_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; 334 sourcesink_driver.descriptors = NULL; 335 loopback_driver.descriptors = NULL; 336 if (autoresume) { 337 sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 338 loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 339 autoresume_step_ms = autoresume * 1000; 340 } 341 342 /* support OTG systems */ 343 if (gadget_is_otg(cdev->gadget)) { 344 sourcesink_driver.descriptors = otg_desc; 345 sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 346 loopback_driver.descriptors = otg_desc; 347 loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 348 } 349 350 /* Register primary, then secondary configuration. Note that 351 ┊* SH3 only allows one config... 352 ┊*/ 353 if (loopdefault) {//若只支持loopback即迴環模式。 354 usb_add_config_only(cdev, &loopback_driver);//則loopback配置先註冊 355 usb_add_config_only(cdev, &sourcesink_driver);//後註冊 356 } else { 357 usb_add_config_only(cdev, &sourcesink_driver);//同上 358 usb_add_config_only(cdev, &loopback_driver); 359 } 360 status = usb_add_function(&sourcesink_driver, func_ss);//將功能即接口綁定到配置描述符,此處還有一次bind操做,隱藏的極深。 361 if (status) 362 goto err_conf_flb; 363 364 usb_ep_autoconfig_reset(cdev->gadget);//從新設置ep 365 status = usb_add_function(&loopback_driver, func_lb); 366 if (status) 367 goto err_conf_flb; 368 369 usb_ep_autoconfig_reset(cdev->gadget); 370 usb_composite_overwrite_options(cdev, &coverwrite);//支持傳參。修改iverdor iproduct等。 371 372 INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); 373 374 return 0; 375 376 err_conf_flb: 377 usb_put_function(func_lb); 378 func_lb = NULL; 379 err_put_func_inst_lb: 380 usb_put_function_instance(func_inst_lb); 381 func_inst_lb = NULL; 382 err_put_func_ss: 383 usb_put_function(func_ss); 384 func_ss = NULL; 385 err_put_func_inst_ss: 386 usb_put_function_instance(func_inst_ss); 387 func_inst_ss = NULL; 388 return status; 389 }
189 int usb_add_function(struct usb_configuration *config, //配置中實例化接口。 190 struct usb_function *function) 191 { 192 int value = -EINVAL; 193 194 DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", 195 function->name, function, 196 config->label, config); 197 198 if (!function->set_alt || !function->disable)//接口是否設置了set_alt函數,該函數調用表示當前接口可用,其餘接口不可用。 199 goto done; 200 201 function->config = config; 202 list_add_tail(&function->list, &config->functions); 203 204 /* REVISIT *require* function->bind? */
205 if (function->bind) {
206 value = function->bind(config, function);//對於一個配置多個接口的cdev設備,再次對function進行bin操做。
207 if (value < 0) {
208 list_del(&function->list);
209 function->config = NULL;
210 }
211 } else
212 value = 0;
213
214 /* We allow configurations that don't work at both speeds.
215 ┊* If we run into a lowspeed Linux system, treat it the same
216 ┊* as full speed ... it's the function drivers that will need
217 ┊* to avoid bulk and ISO transfers.
218 ┊*/
219 if (!config->fullspeed && function->fs_descriptors)
220 config->fullspeed = true;
221 if (!config->highspeed && function->hs_descriptors)
222 config->highspeed = true;
223 if (!config->superspeed && function->ss_descriptors)
224 config->superspeed = true;
225
226 done:
227 if (value)
228 DBG(config->cdev, "adding '%s'/%p --> %d\n",
229 function->name, function, value);
230 return value;
231 }
以f_loopback.c中的bind爲例。
175 static int loopback_bind(struct usb_configuration *c, struct usb_function *f) //將配置和功能綁定在一塊兒 176 { 177 struct usb_composite_dev *cdev = c->cdev; 178 struct f_loopback *loop = func_to_loop(f); 179 int id; 180 int ret; 181 182 /* allocate interface ID(s) */ 183 id = usb_interface_id(c, f);//通常從0開始配置。分配接口id號 184 if (id < 0) 185 return id; 186 loopback_intf.bInterfaceNumber = id; 187 188 id = usb_string_id(cdev);//獲取字符描述符索引 189 if (id < 0) 190 return id; 191 strings_loopback[0].id = id; 192 loopback_intf.iInterface = id; 193 194 /* allocate endpoints */ 195 196 loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);//分配批量輸入端點 197 if (!loop->in_ep) { 198 autoconf_fail: 199 ERROR(cdev, "%s: can't autoconfigure on %s\n", 200 f->name, cdev->gadget->name); 201 return -ENODEV; 202 } 203 loop->in_ep->driver_data = cdev; /* claim */ 204 205 loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);//分配批量輸出端點 206 if (!loop->out_ep) 207 goto autoconf_fail; 208 loop->out_ep->driver_data = cdev; /* claim */ 209 210 /* support high speed hardware */ 211 hs_loop_source_desc.bEndpointAddress = 212 fs_loop_source_desc.bEndpointAddress; 213 hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; 214 215 /* support super speed hardware */ 216 ss_loop_source_desc.bEndpointAddress = 217 fs_loop_source_desc.bEndpointAddress; 218 ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; 219 220 ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs, //此處主要設設置usb速度。 221 ss_loopback_descs); 222 if (ret) 223 return ret; 224 225 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", 226 ┊ (gadget_is_superspeed(c->cdev->gadget) ? "super" : 227 ┊ ┊(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), 228 f->name, loop->in_ep->name, loop->out_ep->name); 229 return 0; 230 }
至此gadget框架只驅動註冊過程已經介紹完成。下面再來介紹下驅動的註冊流程。