一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Linux USB Gadget--各環(huán)節(jié)的整合

 WUCANADA 2013-10-10
Linux USB Gadget--各環(huán)節(jié)的整合 2013-07-22 16:12:23
標(biāo)簽:linux usb gadget
        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ù):  
  1. staticint __init init(void)  

  2. {  

  3. return usb_composite_register(&zero_driver);  

  4. }  

        很簡(jiǎn)單,只是調(diào)用了usb_composite_register,傳遞給他的參數(shù)是zero_driver。這個(gè)結(jié)構(gòu)體如下定義:  
  1. staticstruct 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. };  

        以上函數(shù)都是在zero.c中實(shí)現(xiàn)的,比較重要的函數(shù)是zero_bind。目前暫時(shí)不列出這個(gè)函數(shù),等用到的時(shí)候再說。下面看一下usb_composite_register函數(shù),他是由USB設(shè)備層提供的,定義在composite.c中:  
  1. int __init usb_composite_register(struct usb_composite_driver *driver)  

  2. {  

  3. if (!driver || !driver->dev || !driver->bind || composite)  

  4. return -EINVAL;  

  5. if (!driver->name)  

  6.         driver->name = "composite";  

  7.     composite_driver.function =  (char *) driver->name;  

  8.     composite_driver.driver.name = driver->name;  

  9.     composite = driver;  

  10. return usb_gadget_register_driver(&composite_driver);  

  11. }  

        這個(gè)函數(shù)主要的目的是初始化兩個(gè)結(jié)構(gòu)體變量,一個(gè)是composite_driver,這個(gè)是USB設(shè)備層定義的一個(gè)全局struct usb_gadget_driver變量,如下:  
  1. staticstruct usb_gadget_driver composite_driver = {  

  2.     .speed      = USB_SPEED_HIGH,  

  3.     .bind       = composite_bind,  

  4.     .unbind     = __exit_p(composite_unbind),  

  5.     .setup      = composite_setup,  

  6.     .disconnect = composite_disconnect,  

  7.     .suspend    = composite_suspend,  

  8.     .resume     = composite_resume,  

  9.     .driver = {  

  10.         .owner      = THIS_MODULE,  

  11.     },  

  12. };  

        這 些函數(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):  
  1. int usb_gadget_register_driver(struct usb_gadget_driver *driver)  

  2. {  

  3. struct s3c2410_udc *udc = the_controller; //the_controller指向已經(jīng)初始化好了的s3c2410_udc結(jié)構(gòu),這個(gè)結(jié)構(gòu)代表了s3c2410 usb設(shè)備控制器,當(dāng)然他包括struct gadget結(jié)構(gòu) 

  4. int     retval;  

  5.     dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",  

  6.         driver->driver.name);  

  7. /* Sanity checks */

  8. if (!udc)  

  9. return -ENODEV;  

  10. if (udc->driver)  

  11. return -EBUSY;  

  12. if (!driver->bind || !driver->setup  

  13.             || driver->speed < USB_SPEED_FULL) {  

  14.         printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",  

  15.             driver->bind, driver->setup, driver->speed);  

  16. return -EINVAL;  

  17.     }  

  18. #if defined(MODULE) 

  19. if (!driver->unbind) {  

  20.         printk(KERN_ERR "Invalid driver: no unbind method\n");  

  21. return -EINVAL;  

  22.     }  

  23. #endif 

  24. /*---------------------------------------以上都是指針檢查-------------------------------------------------------*/

  25. /* Hook the driver */

  26.     udc->driver = driver;//傳遞過來的driver就是USB設(shè)備層定義的composite_driver,這樣就聯(lián)系了UDC層與USB設(shè)備層 

  27.     udc->gadget.dev.driver = &driver->driver; //這里賦值的driver是struct device_driver結(jié)構(gòu),供linux設(shè)備模型使用 

  28. /* Bind the driver */

  29. if ((retval = device_add(&udc->gadget.dev)) != 0) {  

  30.         printk(KERN_ERR "Error in device_add() : %d\n",retval);  

  31. goto register_error;  

  32.     }  

  33. //udc->gadget.dev是struct device 結(jié)構(gòu),這是向linux設(shè)備模型核心注冊(cè)設(shè)備 

  34.     dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",  

  35.         driver->driver.name);  

  36. if ((retval = driver->bind (&udc->gadget)) != 0) {  

  37.         device_del(&udc->gadget.dev);  

  38. goto register_error;  

  39.     }  

  40. /* Enable udc */

  41.     s3c2410_udc_enable(udc);  

  42. return 0;  

  43. register_error:  

  44.     udc->driver = NULL;  

  45.     udc->gadget.dev.driver = NULL;  

  46. return retval;  

  47. }  

    這 個(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中 定義的,如下:  
  1. staticint __init composite_bind(struct usb_gadget *gadget)  

  2. {  

  3. struct usb_composite_dev    *cdev;  

  4. int             status = -ENOMEM;  

  5.     cdev = kzalloc(sizeof *cdev, GFP_KERNEL);  //分配內(nèi)存,struct usb_composite_dev結(jié)構(gòu)代表了一個(gè)USB設(shè)備 

  6. if (!cdev)  

  7. return status;  

  8.     spin_lock_init(&cdev->lock);  

  9.     cdev->gadget = gadget;   //這個(gè)gadget也就是s3c2410_udc.c中定義的 

  10.     set_gadget_data(gadget, cdev); //這個(gè)函數(shù)的功能就是是得gadget->dev->driver_data指向cdev結(jié)構(gòu)。gadget->dev是struct device結(jié)構(gòu)已經(jīng)注冊(cè)到了Linux設(shè)備驅(qū)動(dòng)模型核心 

  11.     INIT_LIST_HEAD(&cdev->configs);  //cdev->configs是struct list_head結(jié)構(gòu)指針,這個(gè)鏈表將鏈接設(shè)備的所有配置 

  12. /* preallocate control response and buffer */

  13.     cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);  

  14. //    以上函數(shù)是非常重要的,關(guān)系著USB設(shè)備枚舉?,F(xiàn)在先不分析,當(dāng)分析到USB設(shè)備枚舉的時(shí)候再回頭分析這個(gè)函數(shù) 

  15. if (!cdev->req)  

  16. goto fail;  

  17.     cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);  

  18. if (!cdev->req->buf)  

  19. goto fail;  

  20.     cdev->req->complete = composite_setup_complete;  

  21.     gadget->ep0->driver_data = cdev;  

  22.     cdev->bufsiz = USB_BUFSIZ;  

  23.     cdev->driver = composite; //既然struct usb_composite_dev代表一個(gè)USB設(shè)備,他的驅(qū)動(dòng)當(dāng)然是Gadget功能驅(qū)動(dòng),這里是composite,在前面usb_composite_register的時(shí)候賦值z(mì)ero_driver 

  24.     usb_gadget_set_selfpowered(gadget); //設(shè)置USB設(shè)備為自供電設(shè)備,因?yàn)槭窃O(shè)備mini2440開發(fā)板已經(jīng)提供電源,當(dāng)然是自供電了 

  25. /* interface and string IDs start at zero via kzalloc.

  26.      * we force endpoints to start unassigned; few controller

  27.      * drivers will zero ep->driver_data.

  28.      */

  29.     usb_ep_autoconfig_reset(cdev->gadget);//這個(gè)函數(shù)主要的功能是遍歷gadget端點(diǎn)鏈表,將端點(diǎn)的driver_data清空 

  30. /* composite gadget needs to assign strings for whole device (like

  31.      * serial number), register function drivers, potentially update

  32.      * power state and consumption, etc

  33.      */

  34.     status = composite->bind(cdev); //這個(gè)函數(shù)調(diào)用就涉及到Gadget功能驅(qū)動(dòng)層了,這里也就是zero.c,composite->bind定義與zero.c中。經(jīng)過這個(gè)調(diào)用三層才真正的聯(lián)系在了一起。 

  35. if (status < 0)  

  36. goto fail;  

  37. //以下代碼都是設(shè)備描述符相關(guān)的,cdev->desc是truct usb_device_descriptor結(jié)構(gòu)代表了一個(gè)USB設(shè)備描述符。這里用Gadget功能驅(qū)動(dòng)層傳遞過來的參數(shù)初始化這個(gè)結(jié)構(gòu) 

  38.     cdev->desc = *composite->dev;  

  39.     cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  

  40. /* standardized runtime overrides for device ID data */

  41. if (idVendor)  

  42.         cdev->desc.idVendor = cpu_to_le16(idVendor);  

  43. if (idProduct)  

  44.         cdev->desc.idProduct = cpu_to_le16(idProduct);  

  45. if (bcdDevice)  

  46.         cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);  

  47. /* strings can't be assigned before bind() allocates the

  48.      * releavnt identifiers

  49.      */

  50. if (cdev->desc.iManufacturer && iManufacturer)  

  51.         string_override(composite->strings,  

  52.             cdev->desc.iManufacturer, iManufacturer);  

  53. if (cdev->desc.iProduct && iProduct)  

  54.         string_override(composite->strings,  

  55.             cdev->desc.iProduct, iProduct);  

  56. if (cdev->desc.iSerialNumber && iSerialNumber)  

  57.         string_override(composite->strings,  

  58.             cdev->desc.iSerialNumber, iSerialNumber);  

  59.     INFO(cdev, "%s ready\n", composite->name);  

  60. return 0;  

  61. fail:  

  62.     composite_unbind(gadget);  

  63. return status;  

  64. }  

        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中,如下:  
  1. staticint __init zero_bind(struct usb_composite_dev *cdev)  

  2. {  

  3. int         gcnum;  

  4. struct usb_gadget   *gadget = cdev->gadget;  

  5. int         id;  

  6. /* Allocate string descriptor numbers ... note that string

  7.      * contents can be overridden by the composite_dev glue.

  8.      */

  9.     id = usb_string_id(cdev);   

  10. // 這個(gè)函數(shù)的功能是如果cdev->next_string_id不大于254,將cdev->next_string_id加1,返回加1后 的cdev->next_string_id。這里cdev->next_string_id為0。所以執(zhí)行完這個(gè)函數(shù)id = 1; 

  11. if (id < 0)  

  12. return id;  

  13.     strings_dev[STRING_MANUFACTURER_IDX].id = id;  

  14.     device_desc.iManufacturer = id;  

  15. //strings_dev是zero定義的字符串描述符數(shù)組,以上語句作用是是得生產(chǎn)廠商的字符串描述符的id為1 

  16.     id = usb_string_id(cdev);  

  17. if (id < 0)  

  18. return id;  

  19.     strings_dev[STRING_PRODUCT_IDX].id = id;  

  20.     device_desc.iProduct = id;  

  21. //以上語句作用是是得產(chǎn)品的字符串描述符的id為2 

  22.     id = usb_string_id(cdev);  

  23. if (id < 0)  

  24. return id;  

  25.     strings_dev[STRING_SERIAL_IDX].id = id;  

  26.     device_desc.iSerialNumber = id;  

  27. //以上語句作用是是得生產(chǎn)串號(hào)的字符串描述符的id為3 

  28.     setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);  

  29. //電源管理相關(guān)代碼,暫時(shí)不用看 

  30. /* Register primary, then secondary configuration.  Note that

  31.      * SH3 only allows one config...

  32.      */

  33. if (loopdefault) {  

  34.         loopback_add(cdev, autoresume != 0);  

  35. if (!gadget_is_sh(gadget))  

  36.             sourcesink_add(cdev, autoresume != 0);  

  37.     } else {  

  38.         sourcesink_add(cdev, autoresume != 0);  

  39. if (!gadget_is_sh(gadget))  

  40.             loopback_add(cdev, autoresume != 0);  

  41.     }  

  42. //以上代碼尤其重要,是設(shè)置zero設(shè)備配置描述符的。這里不得不說一下zero驅(qū)動(dòng)的功能,他有兩種配置。一個(gè)是將主機(jī)發(fā)送給他的內(nèi)容返回給主機(jī),另外一個(gè)就是可以單獨(dú)發(fā)送與接受數(shù)據(jù)。loopdefault是模塊參數(shù),默認(rèn)值為0 

  43. //所以我們先看else后面的代碼,這段代碼設(shè)置的就是單獨(dú)發(fā)送接受功能。gadget_is_sh是判斷usb設(shè)備控制器是否支持復(fù)合設(shè)備,s3c2410不支持。所以現(xiàn)在只需要分析sourcesink_add(cdev, autoresume != 0) 

  44. //這個(gè)函數(shù)就可以了,見下面sourcesink_add(cdev, autoresume != 0)函數(shù)分析。 

  45.     gcnum = usb_gadget_controller_number(gadget);  

  46. if (gcnum >= 0)  

  47.         device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);  

  48. else {  

  49. /* gadget zero is so simple (for now, no altsettings) that

  50.          * it SHOULD NOT have problems with bulk-capable hardware.

  51.          * so just warn about unrcognized controllers -- don't panic.

  52.          *

  53.          * things like configuration and altsetting numbering

  54.          * can need hardware-specific attention though.

  55.          */

  56.         pr_warning("%s: controller '%s' not recognized\n",  

  57.             longname, gadget->name);  

  58.         device_desc.bcdDevice = cpu_to_le16(0x9999);  

  59.     }  

  60.     INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);  

  61.     snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",  

  62.         init_utsname()->sysname, init_utsname()->release,  

  63.         gadget->name);  

  64. return 0;  

  65. }  

        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中。如下所示:  
  1. int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)  

  2. {  

  3. int id;  

  4. /* allocate string ID(s) */

  5.     id = usb_string_id(cdev);  

  6. if (id < 0)  

  7. return id;  

  8.     strings_sourcesink[0].id = id;  

  9. //以上初始化一下字符串描述符的id 

  10.     source_sink_intf.iInterface = id;  

  11.     sourcesink_driver.iConfiguration = id;  

  12. //source_sink_intf是struct usb_interface_descriptor類型的變量,代表一個(gè)接口 

  13. //sourcesink_driver是struct usb_configuration類型的變量,代表一個(gè)USB配置,注意不是配置描述符。這兩個(gè)變量在f_sourcesink.c中定義 

  14. /* support autoresume for remote wakeup testing */

  15. if (autoresume)  

  16.         sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  

  17. /* support OTG systems */

  18. if (gadget_is_otg(cdev->gadget)) {  

  19.         sourcesink_driver.descriptors = otg_desc;  

  20.         sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  

  21.     }  

  22. return usb_add_config(cdev, &sourcesink_driver);  

  23. }  

  24.     在分析這個(gè)函數(shù)之前首先先看一下f_sourcesink.c中關(guān)鍵的一個(gè)數(shù)據(jù)結(jié)構(gòu),sourcesink_driver。他代表了一個(gè)USB配置,里面說明了配置的功能。如下:  

  25. staticstruct usb_configuration sourcesink_driver = {  

  26.     .label      = "source/sink",  

  27.     .strings    = sourcesink_strings,  

  28.     .bind       = sourcesink_bind_config,  

  29.     .setup      = sourcesink_setup,  

  30.     .bConfigurationValue = 3,  

  31.     .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,  

  32. /* .iConfiguration = DYNAMIC */

  33. };  

        看 完了這個(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中,如下:  
  1. int __init usb_add_config(struct usb_composite_dev *cdev,  

  2. struct usb_configuration *config)  

  3. {  

  4. int             status = -EINVAL;  

  5. struct usb_configuration    *c;  

  6.     DBG(cdev, "adding config #%u '%s'/%p\n",  

  7.             config->bConfigurationValue,  

  8.             config->label, config);  

  9. if (!config->bConfigurationValue || !config->bind)  

  10. goto done;  

  11. /* Prevent duplicate configuration identifiers */

  12.     list_for_each_entry(c, &cdev->configs, list) {  

  13. if (c->bConfigurationValue == config->bConfigurationValue) {  

  14.             status = -EBUSY;  

  15. goto done;  

  16.         }  

  17.     }  

  18. /*---------------------------------------------以上都是檢查參數(shù)的合法性------------------------------------------*/

  19.     config->cdev = cdev;  

  20.     list_add_tail(&config->list, &cdev->configs);  

  21. //一個(gè)USB設(shè)備可以有多種配置,這句是將配置加入到設(shè)備的配置鏈表中 

  22.     INIT_LIST_HEAD(&config->functions);  

  23. //初始化配置的functions鏈表,functions鏈表要鏈接struct usb_function類型的數(shù)據(jù)結(jié)構(gòu),這個(gè)數(shù)據(jù)結(jié)構(gòu)也很重要,其實(shí)他代表一個(gè)USB接口 

  24.     config->next_interface_id = 0;  

  25.     status = config->bind(config);  

  26. //這里函數(shù)調(diào)用的是sourcesink_bind_config,這個(gè)函數(shù)的功能就是初始化一個(gè)struct usb_function結(jié)構(gòu),并且將其加入到配置的functions鏈表,見下面分析 

  27. if (status < 0) { //status小于0說明上邊函數(shù)調(diào)用失敗所以刪除配置 

  28.         list_del(&config->list);  

  29.         config->cdev = NULL;  

  30.     } else {  //給配置增加接口成功 

  31.         unsigned    i;  

  32. //打印調(diào)試信息 

  33.         DBG(cdev, "cfg %d/%p speeds:%s%s\n",  

  34.             config->bConfigurationValue, config,  

  35.             config->highspeed ? " high" : "",  

  36.             config->fullspeed  

  37.                  (gadget_is_dualspeed(cdev->gadget)  

  38.                      " full"

  39.                     : " full/low")  

  40.                 : "");  

  41. //MAX_CONFIG_INTERFACES 最大接口數(shù),定義在composite.h中,為16。每個(gè)配置可以有16個(gè)接口,一下代碼遍歷這個(gè)配置的所有接口,打印調(diào)試信息 

  42. for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {  

  43. struct usb_function *f = config->interface[i];  

  44. if (!f)  

  45. continue;  

  46.             DBG(cdev, "  interface %d = %s/%p\n",  

  47.                 i, f->name, f);  

  48.         }  

  49.     }  

  50. /* set_alt(), or next config->bind(), sets up

  51.      * ep->driver_data as needed.

  52.      */

  53.     usb_ep_autoconfig_reset(cdev->gadget);  

  54. //這個(gè)函數(shù)的主要作用就是將cdev->gadget的所有端點(diǎn)的driver_data清空 

  55. done:  

  56. if (status)  

  57.         DBG(cdev, "added config '%s'/%u --> %d\n", config->label,  

  58.                 config->bConfigurationValue, status);  

  59. return status;  

  60. }  

        這個(gè)函數(shù)初始化了配置,將配置與設(shè)備聯(lián)系在一起,并且打印一些調(diào)試信息。這樣設(shè)備有了配置,但是我們知道一個(gè)USB設(shè)備的配置下是接口的集合。所以函數(shù)調(diào)用config->bind(config)給配置添加接口。這個(gè)函數(shù)如下:  
  1. staticint __init sourcesink_bind_config(struct usb_configuration *c)  

  2. {  

  3. struct f_sourcesink *ss;  

  4. int         status;  

  5.     ss = kzalloc(sizeof *ss, GFP_KERNEL);  

  6. if (!ss)  

  7. return -ENOMEM;  

  8.     ss->function.name = "source/sink";  

  9.     ss->function.descriptors = fs_source_sink_descs;  

  10.     ss->function.bind = sourcesink_bind;  

  11.     ss->function.unbind = sourcesink_unbind;  

  12.     ss->function.set_alt = sourcesink_set_alt;  

  13.     ss->function.disable = sourcesink_disable;  

  14.     status = usb_add_function(c, &ss->function);  

  15. if (status)  

  16.         kfree(ss);  

  17. return status;  

  18. }  

        可 以看出這個(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ù)如下 所示:  
  1. int __init usb_add_function(struct usb_configuration *config,  

  2. struct usb_function *function)  

  3. {  

  4. int value = -EINVAL;  

  5. //打印調(diào)試信息 

  6.     DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",  

  7.             function->name, function,  

  8.             config->label, config);  

  9. //檢查參數(shù)合法性 

  10. if (!function->set_alt || !function->disable)  

  11. goto done;  

  12. //添加接口到配置 

  13.     function->config = config;  

  14.     list_add_tail(&function->list, &config->functions);  

  15. /* REVISIT *require* function->bind? */

  16. if (function->bind) { //如果function定義了bind函數(shù)則調(diào)用他,這里function定義了bind函數(shù),sourcesink_bind。這個(gè)函數(shù)進(jìn)行一些初始化的工作 

  17.         value = function->bind(config, function);  

  18. if (value < 0) {  

  19.             list_del(&function->list);  

  20.             function->config = NULL;  

  21.         }  

  22.     } else

  23.         value = 0;  

  24. /* We allow configurations that don't work at both speeds.

  25.      * If we run into a lowspeed Linux system, treat it the same

  26.      * as full speed ... it's the function drivers that will need

  27.      * to avoid bulk and ISO transfers.

  28.      */

  29. if (!config->fullspeed && function->descriptors)  

  30.         config->fullspeed = true;  

  31. if (!config->highspeed && function->hs_descriptors)  

  32.         config->highspeed = true;  

  33. done:  

  34. if (value)  

  35.         DBG(config->cdev, "adding '%s'/%p --> %d\n",  

  36.                 function->name, function, value);  

  37. return value;  

  38. }  

        我們可以看到這個(gè)函數(shù)最主要的就是聯(lián)系接口與配置。并且調(diào)用接口的bind函數(shù),zero sourcesink配置的接口的bind為sourcesink_bind。如下定義:  
  1. staticint __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. /* allocate interface ID(s) */

  8.     id = usb_interface_id(c, f);  

  9. if (id < 0)  

  10. return id;  

  11.     source_sink_intf.bInterfaceNumber = id;  

  12. //usb_interface_id(c, f) 實(shí)現(xiàn)的功能是判斷config->next_interface_id是否大于16如果不是,那么執(zhí)行 config->interface[id] = f,在將config->next_interface_id加1返回 

  13. /* allocate endpoints */

  14. //下面是分配端點(diǎn),我們知道根據(jù)USB協(xié)議。USB設(shè)備下來是USB配置,然后是USB接口,接口是USB端點(diǎn)的組合,根據(jù)zero sourcesink實(shí)現(xiàn)的功能,接口需要連個(gè)批量端點(diǎn),一個(gè)In端點(diǎn)一個(gè)out端點(diǎn) 

  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.     ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);  

  24. if (!ss->out_ep)  

  25. goto autoconf_fail;  

  26.     ss->out_ep->driver_data = cdev;   /* claim */

  27. /* support high speed hardware */

  28. if (gadget_is_dualspeed(c->cdev->gadget)) {  

  29.         hs_source_desc.bEndpointAddress =  

  30.                 fs_source_desc.bEndpointAddress;  

  31.         hs_sink_desc.bEndpointAddress =  

  32.                 fs_sink_desc.bEndpointAddress;  

  33.         f->hs_descriptors = hs_source_sink_descs;  

  34.     }  

  35.     DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",  

  36.             gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",  

  37.             f->name, ss->in_ep->name, ss->out_ep->name);  

  38. return 0;  

  39. }  

        這 個(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):  
  1. struct usb_composite_dev {  

  2. struct usb_gadget       *gadget; //聯(lián)系底層的UDC中的usb_gadget 

  3. struct usb_request      *req;    //端點(diǎn)0的傳輸結(jié)構(gòu),在設(shè)備枚舉的時(shí)候使用 

  4.     unsigned            bufsiz;  

  5. struct usb_configuration    *config; //USB配置 

  6. /* private: */

  7. /* internals */

  8. struct usb_device_descriptor    desc;   //設(shè)備描述符 

  9. struct list_head        configs; //USB配置鏈表 

  10. struct usb_composite_driver *driver;  //聯(lián)系上層的Gadget功能驅(qū)動(dòng)層 

  11.     u8              next_string_id;  

  12. /* the gadget driver won't enable the data pullup

  13.      * while the deactivation count is nonzero.

  14.      */

  15.     unsigned            deactivations;  

  16. /* protects at least deactivation count */

  17.     spinlock_t          lock;  

  18. };  

        經(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ù)用的意思,不知道是不是為了 原因而命名的。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    九九热国产这里只有精品| 国产小青蛙全集免费看| 女同伦理国产精品久久久| 空之色水之色在线播放| 欧美二区视频在线观看| 欧美精品激情视频一区| 亚洲男人天堂网在线视频| 高潮少妇高潮久久精品99| 日韩欧美综合中文字幕| 我想看亚洲一级黄色录像| 欧美一区二区黑人在线| 精品人妻av区波多野结依| 国产韩国日本精品视频| 日韩成人免费性生活视频| 国产又大又黄又粗又免费| 亚洲成人精品免费在线观看| 黄片美女在线免费观看| 九九热在线免费在线观看| 中文字幕在线五月婷婷| 久久99午夜福利视频| 九九热视频经典在线观看| 噜噜中文字幕一区二区| 色综合伊人天天综合网中文| 欧美日韩亚洲精品在线观看| 成人精品国产亚洲av久久| 国产精品熟女乱色一区二区| 一区二区日韩欧美精品| 亚洲一区二区三区三州| 国产又大又黄又粗的黄色| 日本本亚洲三级在线播放| 欧美夫妻性生活一区二区| 国产综合一区二区三区av| 亚洲成人久久精品国产| 国产成人在线一区二区三区| 91欧美日韩精品在线| 国产欧美日韩精品成人专区| 五月天婷亚洲天婷综合网| 天堂av一区一区一区| 国产成人精品国内自产拍| 精品视频一区二区三区不卡| 暴力性生活在线免费视频|