Linux usb gadget框架概述

  很幸運,在公司開發了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爲例:                                                                                                                    

  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\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函數。

    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 "\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爲例。

    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\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框架只驅動註冊過程已經介紹完成。下面再來介紹下驅動的註冊流程。

      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函數。枚舉過程將在另一篇文章中介紹。
相關文章
相關標籤/搜索