• Linux usb gadget框架概述


      很幸运,在公司开发了gadget相关驱动,总结下来,大大小小开发了四个与gadget相关的驱动,字符驱动、g_multi、g_ether、g_zero,在这里把自己对gadget的开发中自己的感悟记录之。

    想要了解gadget,必须了解其框架,知道composite、gadget、udc三者之间的联系,知道usb描述符的作用。

    一个usb device有一个设备描述符。

    有一个或者多个配置描述符

    一个配置描述符有一个或者多个接口(在gadget端,接口正式命名是usb_func)。

    一个接口有0个或者多个端点。

    编写gadget的关键是在于了解udc、gadget、composite三者之间的联系和架构层次,在实际应用中gadget是不需要我们去编写的,需要我们自己去编写的是composite层,以及地对udc层的修改,下面开始详细介绍着三者。

    1、composite英文意思是复合的意思,估计是编写usb gadget层设备驱动都整合到一起,通过统一的函数usb_composite_register注册。功能各异,杂七杂八,所以称为复合层吧。

    在该层,我们需要注意的相关结构体和函数有如下:

    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驱动的注册过程,讲完后介绍驱动的编写过程。

    以zero.c为例:                                                                                                                    

    1. 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
      ");
      1707             
      1708     INFO(cdev, "%s ready
      ", 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 ", 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函数。

      1. 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 "
        ", 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
        ",
         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 ",
           229 function->name, function, value);
           230 return value;
           231 }

        以f_loopback.c中的bind为例。

      2. 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
        ",
        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
        ",
        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框架只驱动注册过程已经介绍完成。下面再来介绍下驱动的注册流程。

        1. 填充usb_composite_driver驱动实例,调用usb_composite_probe进行注。
        2. 移花接木,填充usb_composite驱动中gadget_driver,调用usb_gadget_probe_driver(gadget_driver);使得udc能够和composite设备联系起来。
        3. 调用udc_bind_to_driver,慢慢的将udc和composite绑定在一起。
        4. 调用driver->bind(udc->gadget, driver);实际上是调用composite_bind函数,该函数由内核实现。该函数主要是创建cdev设备,将真正的驱动和cdev绑定在一起。
        5. 此后再调用编写的驱动的bind函数。此时主要是讲cdev设备的配置和function进行填充。设备必须有配置,配置必须有接口。
        6. 针对多function的驱动,必须再次绑定bind函数,此次主要是设置接口id,实例化ep等。
        7. 前6步操作的完成,表示composite设备驱动已经注册成功了。成功了之后呢?那就涉及到对udc的操作了,udc进入请求连接状态,等待中断的响应。
        8. 中断响应也就是响应主设备发起的枚举操作,完成枚举过程,枚举响应主要是调用function->setup函数。枚举过程将在另外一篇文章中介绍。
  • 相关阅读:
    团队作业6——复审与事后分析
    Alpha阶段项目复审
    测试与发布( Alpha版本 )
    测试与发布(Alpha版本)
    团队作业4——项目冲刺
    第 1 篇 Scrum 冲刺博客
    第 7篇 Scrum 冲刺博客
    第 6篇 Scrum 冲刺博客
    第 5篇 Scrum 冲刺博客
    第 4篇 Scrum 冲刺博客
  • 原文地址:https://www.cnblogs.com/haoxing990/p/8799133.html
Copyright © 2020-2023  润新知