分享

Linux USB Gadget--各环节的整合

 WUCANADA 2013-10-10
Linux USB Gadget--各环节的整合 2013-07-22 16:12:23         Linux USB Gadget 软件结构一文中分析Linux USB Gadget软件分为三层。这三层其中两层是与硬件无关的,分别是Gadget功能驱动层,USB设备层。一层是 与硬件相关的是UDC层。每一层都提供一种关键的数据结构与函数与其他层交互。
        Gadget功能驱动层:  最主要的结构是struct usb_composite_driver,这个结构在这层定义,并且实现结构中的各个函数。
        USB设备层:  最主要的数据结构是struct usb_composite_dev与usb_gadget_driver。前一个代表一个USB设备,而后一个是Gadget驱动,与UDC层交互。
        UDC层:  最主要的数据结构是struct usb_gadget,通常包含在其他结构体中。这个结构体代表了一个USB设备控制器的所有关于USB通信的信息。
        UDC 层提供usb_gadget_unregister_driver(struct usb_gadget_driver *driver)函数,这个函数 由USB设备层调用,USB设备层将自己定义的struct usb_gadget_driver结构变量传递给他。USB设备层提供 usb_composite_register(struct usb_composite_driver *driver)函数,这个函数由 Gadget功能驱动层调用,Gadget功能驱动层将自己定义的struct usb_composite_driver 结构变量传递给他。下面详细 分析一下这三层是如何结合在一起的。我们将以zero Gadget功能驱动为例子,s3c2410_udc作为底层UDC。
        首先先看一下zero Gadget功能驱动,他是作为一个模块注册到内核中的,首先分析一下他的模块初始化函数:  
  1. staticint __init init(void)  

  2. {  

  3. return usb_composite_register(&zero_driver);  

  4. }  

        很简单,只是调用了usb_composite_register,传递给他的参数是zero_driver。这个结构体如下定义:  
  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. };  

        以上函数都是在zero.c中实现的,比较重要的函数是zero_bind。目前暂时不列出这个函数,等用到的时候再说。下面看一下usb_composite_register函数,他是由USB设备层提供的,定义在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. }  

        这个函数主要的目的是初始化两个结构体变量,一个是composite_driver,这个是USB设备层定义的一个全局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. };  

        这 些函数都要在USB设备层实现。usb_composite_register将composite_driver的function初始化 为"zero"。driver是 struct device_driver结构体。linux设备模型中使用。名字初始化为“zero”。另外一个变量 是composite,它是一个USB设备层定义的struct usb_composite_driver的指针,这样composite就指向了 zero_driver。因此zero Gadget功能驱动层就和USB设备层联系到了一起。最后usb_composite_register函数调 用usb_gadget_register_driver,开始向UDC层联系。这个函数定义在UDC层,系统每个UDC都要实现这样一个函数。我们看一 下s3c2410_udc这个函数的实现:  
  1. int usb_gadget_register_driver(struct usb_gadget_driver *driver)  

  2. {  

  3. struct s3c2410_udc *udc = the_controller; //the_controller指向已经初始化好了的s3c2410_udc结构,这个结构代表了s3c2410 usb设备控制器,当然他包括struct gadget结构 

  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设备层定义的composite_driver,这样就联系了UDC层与USB设备层 

  27.     udc->gadget.dev.driver = &driver->driver; //这里赋值的driver是struct device_driver结构,供linux设备模型使用 

  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 结构,这是向linux设备模型核心注册设备 

  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. }  

    这 个函数最开始的功能是将UDC层与USB设备层联系在一起,然后调用driver->bind (&udc->gadget)函数。 开始了最重要的绑定工作。只有这个函数执行完毕这三层才真正的结合在一起,USB设备正常的工作。driver就是传递过来的在USB设备层定义的 composite_driver。所以driver->bind (&udc->gadget)函数是在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);  //分配内存,struct usb_composite_dev结构代表了一个USB设备 

  6. if (!cdev)  

  7. return status;  

  8.     spin_lock_init(&cdev->lock);  

  9.     cdev->gadget = gadget;   //这个gadget也就是s3c2410_udc.c中定义的 

  10.     set_gadget_data(gadget, cdev); //这个函数的功能就是是得gadget->dev->driver_data指向cdev结构。gadget->dev是struct device结构已经注册到了Linux设备驱动模型核心 

  11.     INIT_LIST_HEAD(&cdev->configs);  //cdev->configs是struct list_head结构指针,这个链表将链接设备的所有配置 

  12. /* preallocate control response and buffer */

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

  14. //    以上函数是非常重要的,关系着USB设备枚举。现在先不分析,当分析到USB设备枚举的时候再回头分析这个函数 

  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代表一个USB设备,他的驱动当然是Gadget功能驱动,这里是composite,在前面usb_composite_register的时候赋值zero_driver 

  24.     usb_gadget_set_selfpowered(gadget); //设置USB设备为自供电设备,因为是设备mini2440开发板已经提供电源,当然是自供电了 

  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);//这个函数主要的功能是遍历gadget端点链表,将端点的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); //这个函数调用就涉及到Gadget功能驱动层了,这里也就是zero.c,composite->bind定义与zero.c中。经过这个调用三层才真正的联系在了一起。 

  35. if (status < 0)  

  36. goto fail;  

  37. //以下代码都是设备描述符相关的,cdev->desc是truct usb_device_descriptor结构代表了一个USB设备描述符。这里用Gadget功能驱动层传递过来的参数初始化这个结构 

  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结构体,通过cdev->gadget = gadget;这条语句将设备与 底层的gadget联系在一起,通过cdev->driver = composite,这条语句将设备与Gadget功能驱动联系在一起。并且给 设备端点0分配了一个struct usb_request,这个结构在USB枚举将发挥重要的作用。然后调用Gadget功能驱动层的bind函数。最 后初始化了USB设备描述符。这个函数最重要的一步就是调用了Gadget功能驱动层的bind函数。这样,三个软件层才真正的联系在了一起。 zero Gadget功能驱动层的 bind函数定义在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. // 这个函数的功能是如果cdev->next_string_id不大于254,将cdev->next_string_id加1,返回加1后 的cdev->next_string_id。这里cdev->next_string_id为0。所以执行完这个函数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定义的字符串描述符数组,以上语句作用是是得生产厂商的字符串描述符的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. //以上语句作用是是得产品的字符串描述符的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. //以上语句作用是是得生产串号的字符串描述符的id为3 

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

  29. //电源管理相关代码,暂时不用看 

  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. //以上代码尤其重要,是设置zero设备配置描述符的。这里不得不说一下zero驱动的功能,他有两种配置。一个是将主机发送给他的内容返回给主机,另外一个就是可以单独发送与接受数据。loopdefault是模块参数,默认值为0 

  43. //所以我们先看else后面的代码,这段代码设置的就是单独发送接受功能。gadget_is_sh是判断usb设备控制器是否支持复合设备,s3c2410不支持。所以现在只需要分析sourcesink_add(cdev, autoresume != 0) 

  44. //这个函数就可以了,见下面sourcesink_add(cdev, autoresume != 0)函数分析。 

  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 函数首先就是设置了几个字符串描述符的id,然后就设置USB配置。主要调用了sourcesink_add函数,传递给的参数是cdev,就是USB设 备层定义的USB设备结构体。这个函数定义在f_sourcesink.c,这个文件以头文件的形式包含在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类型的变量,代表一个接口 

  13. //sourcesink_driver是struct usb_configuration类型的变量,代表一个USB配置,注意不是配置描述符。这两个变量在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.     在分析这个函数之前首先先看一下f_sourcesink.c中关键的一个数据结构,sourcesink_driver。他代表了一个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. };  

        看 完了这个数据结构,我们分析一下sourcesink_add最后调用的函数 usb_add_config(cdev, &sourcesink_driver),这个函数传递的参数一个是USB设备一个是USB配置。显 然功能是给USB设备增加一个配置。函数定义在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. /*---------------------------------------------以上都是检查参数的合法性------------------------------------------*/

  19.     config->cdev = cdev;  

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

  21. //一个USB设备可以有多种配置,这句是将配置加入到设备的配置链表中 

  22.     INIT_LIST_HEAD(&config->functions);  

  23. //初始化配置的functions链表,functions链表要链接struct usb_function类型的数据结构,这个数据结构也很重要,其实他代表一个USB接口 

  24.     config->next_interface_id = 0;  

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

  26. //这里函数调用的是sourcesink_bind_config,这个函数的功能就是初始化一个struct usb_function结构,并且将其加入到配置的functions链表,见下面分析 

  27. if (status < 0) { //status小于0说明上边函数调用失败所以删除配置 

  28.         list_del(&config->list);  

  29.         config->cdev = NULL;  

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

  31.         unsigned    i;  

  32. //打印调试信息 

  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 最大接口数,定义在composite.h中,为16。每个配置可以有16个接口,一下代码遍历这个配置的所有接口,打印调试信息 

  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. //这个函数的主要作用就是将cdev->gadget的所有端点的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. }  

        这个函数初始化了配置,将配置与设备联系在一起,并且打印一些调试信息。这样设备有了配置,但是我们知道一个USB设备的配置下是接口的集合。所以函数调用config->bind(config)给配置添加接口。这个函数如下:  
  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. }  

        可 以看出这个函数分配并初始化了一个struct f_sourcesink结构体,这个结构体包含代表接口的struct usb_function。并 且初始化了struct usb_function的一下回调函数。最后调用 usb_add_function(c, &ss->function);将接口添加到配置中。usb_add_function函数如下 所示:  
  1. int __init 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. /* REVISIT *require* function->bind? */

  16. if (function->bind) { //如果function定义了bind函数则调用他,这里function定义了bind函数,sourcesink_bind。这个函数进行一些初始化的工作 

  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. }  

        我们可以看到这个函数最主要的就是联系接口与配置。并且调用接口的bind函数,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) 实现的功能是判断config->next_interface_id是否大于16如果不是,那么执行 config->interface[id] = f,在将config->next_interface_id加1返回 

  13. /* allocate endpoints */

  14. //下面是分配端点,我们知道根据USB协议。USB设备下来是USB配置,然后是USB接口,接口是USB端点的组合,根据zero sourcesink实现的功能,接口需要连个批量端点,一个In端点一个out端点 

  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. }  

        这 个函数除了初始化接口的接口id。另外就是给接口分配端点了。这也是各层整合的最后一步了。zero sourcesink有一个配置,一个接口。这个接 口有两个端点,一个in端点一个Out端点。usb_ep_autoconfig 函数就担当了分配端点的任务,他定义在epautoconf.c中,这 个文件以头文件的形式包含在了zero.c中。这个函数有两个参数一个是struct usb_gadget类型的指针,一个是 struct usb_endpoint_descriptor类型的指针,也就是端点描述符,这个函数根据端点描述符的信息,自动在 struct usb_gadget里找到合适的端点。
        经过上面的重重函数调用,现在设备终于饱满了,既有配置了,也有接口了, 接口里也有相应的端点了。各层的关系也都联系起来了。但是还是有一点就是感觉有点晕。确实这么多的函数调用,不晕都没办法呀。没关系,我们来重新梳理一下 各个函数之间的调用关系以及各环节整合的过程。这个整合的过程大体分为两个过程:
(1) 过程方向 Gadget功能驱动层-->USB设备层-->UDC层。
         以四个数据结构为基础:struct usb_composite_driver struct usb_composite_dev struct usb_gadget_driver struct usb_gadget 
         两个register函数为导向: usb_composite_register(&zero_driver) usb_gadget_register_driver(&composite_driver)
(2) 过程方向 UDC层-->USB设备层-->Gadget功能驱动层
         四个bind函数为串联点,带出一连串数据结构与初始化。这四个bind函数分配是:
         USB 设备层的composite_bind 由UDC层的usb_gadget_register_driver函数调用。功能是分配 struct usb_composite_dev cdev 并初始化。struct usb_composite_dev结构串联了UDC层的 usb_gadget与Gadget功能驱动层的usb_composite_driver。并且调用下一个上层的bind
         Gadget功能驱动层的zero_bind 这个函数主要的任务就是用Gadget功能驱动层的USB设备信息去进一步初始化struct usb_composite_dev结构。并且引出下面两个bind函数。
         另 外两个bind函数都是与USB设备信息相关,一个是添加配置时调用的,一个是添加接口的时候调用的。这两个函数由sourcesink_add引 出。 usb_add_config将配置添加到设备中引出config->bind:sourcesink_bind_config.这个 bind分配并初始化接口,调用usb_add_function将接口添加到配置到,usb_add_function引出 function->bind:sourcesink_bind 根据功能,在gadget里查找合适的端点。并进一步初始化 struct usb_composite_dev。我们发现这些bind就是一个目的,初始化struct usb_composite_dev结构, 使其逐渐丰满。因为这个结构代表一个USB设备。经过合适的初始化后设备才能正确的工作。经过重重初始化,三层总算整合在了一起了。这三层最终形成了一个 饱满的struct usb_composite_dev结构。这个结构包含USB设备运行各种信息。包括:配置,接口,端点等。我们再来看一下这个结 构:  
  1. struct usb_composite_dev {  

  2. struct usb_gadget       *gadget; //联系底层的UDC中的usb_gadget 

  3. struct usb_request      *req;    //端点0的传输结构,在设备枚举的时候使用 

  4.     unsigned            bufsiz;  

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

  6. /* private: */

  7. /* internals */

  8. struct usb_device_descriptor    desc;   //设备描述符 

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

  10. struct usb_composite_driver *driver;  //联系上层的Gadget功能驱动层 

  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. };  

        经 过初始化设备已经准备好了,将mini2440插入USB主机,就开始了设备枚举.这就涉及到了主机与设备的通信。以后再分析USB设备枚举与数据传输过 程。Linux USB Gadget虽然有三层软件结构。但是只有UDC层与Gadget功能驱动层作为模块注册到内核。只有USB设备层有关的文件 composite.c是以头文件的形式包含在各种Gadget功能驱动里的。以前的内核代码没有USB设备层的。所有的Gadget功能驱动都必须自己 处理USB设备相关的细节,代码重复率较高,所以才出现这个USB设备层以以增加代码的重用性。composite字面上是复用的意思,不知道是不是为了 原因而命名的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多