USB的gadget driver及usb枚舉分 析

本文轉載自 http://blog.csdn.net/fanqipin/article/details/8450694#comments

一.簡介

     一個完整的USB系統由兩部分構成,即usb主機(usb host)和usb設備(usb device)。usb主機通常是指我們的pc機、具有host controller的嵌入式設備;像u盤、usb鼠標、鍵盤屬於usb設備,具有otg controller的usb設備,它即可工作在host模式又可以工作在device模式,模式之間通過HNP協議來進行轉換,如我們平時比較常用的智能手機,當它連接到電腦上時,工作在device模式,電腦可以像u盤一樣對手機裏的存儲空間進行操作,而當把SD卡或其它外設接到手機上時,手機就可以對SD卡等外設進行操作,這個時候它就工作在host模式。
       由於USB系統由兩部組成,所以usb驅動也由相應兩部分組成。主機側驅動主要由應用層驅動,用於管理hub和hcd的usb core層驅動,主機控制器驅動這三部分組成,應用層驅動主要是通過usb的基本數據通信結構urb對usb設備進行操作,這類驅動是針對某一個usb接口寫的,所以也叫作usb 接口驅動,通常在主機端驅動人員要寫的就是這類驅動。usb core驅動裏包含一個守護進程,通常進程是休眠的,當usb port上產生變化,usb root hub監控到其端口上有設備插入或拔出,它就會去喚醒守護進程,然後運行usb設備的枚舉,進而運行後面操作。主機控制器驅動裏包含兩部分,一部分是和usb接口標準相關的驅動,一部分是和控制器本身相關的,其中和接口標準相關的驅動佔主要部分。主機控制器接口標準分三類:ohci,uhci和ehci,不同的生產產家有着不同的usb標準,一個usb控制器生產出來時就已經決定了其標準類型,像inter生產的通常是uhci標準的,而像本文中要用到的s3c6410是採用ohci標準的,不同標準的usb設備之間軟件和硬件上分工不同,像uhci設備它在硬件邏輯上比較簡單,而軟件實現上比較複雜,而ohci在硬件實現上比較複雜,軟件上比較簡單。要完成一個usb控制器驅動無非是運用內核裏各種usb 標準的API。
        在usb設備側,驅動由三層組成:Upper Layers,gadget drivers, device controller drivers, upper layers屬於應用層,通過gadget drivers來使用和控制device controllers,gadget drivers使用gadget API,實現與具體硬件無關,device controller drivers提供gadget API,實現gadget ops和endpoint ops,具體的可參考<Linux-USB Gadget API Framework>.
        不管是在主機側還是設備側,一個usb device它主要可由配置,接口,端口三部分表示,在主機側它們分別由usb_host_config, usb_inferface,usb_host_endpoint表示,而設備側由 usb_configuration,usb_function表示。配置,像我們現在的智能手機它可以用來拍照也可以用來當U盤,這兩種就屬於不同的配置,一個usb設備它可能包含多個配置,在使用某些功能前必需選擇好相應的配置;一個配置由多個接口組成 ,一個接口表示一個功能,一個接口裏可以包含多個接口設置,每個接口設置裏包含與實現某一功能相關的端口,配置,接口和端口結構示意如圖1所示。

 圖1 配置,接口和端口結構示意圖

      當一個usb設備插入到host端時,主機端的root hub通過輪訓監控或中斷方式來觸發usb枚舉,當usb設備通過枚舉後,通過usb總線找到與其配置驅動,然後usb設備才能正常工作,這個枚舉過程由主機和設備共同完成,對於沒有運行操作系統的usb設備,生產產家已經把設備側枚舉所需過程固化在設備裏,驅動工程師可不用去關心設備枚舉,他們只需要完成usb 接口驅動程序。但對於有運行操作系統的usb設備就完全不一樣了,驅動工程師不僅要實現usb設備功能驅動,還得實現與主機枚舉過程相對應的驅動,如主機在對usb設備進行復位操作後,主機會發usb請求去設置usb設備的地址,相應的usb設備側必須實現設備地址機制,並返回0長度usb請求,做爲收到數據ACK,當主機要獲取usb設備各種描述符或設置各種配置時,usb設備側也要實現相應操作。本文主機爲pc機,設備以samsung s3c6410 的otg controller爲控制器,驅動爲zero_driver,通過對zero_driver分析,儘量掌握gadget 驅動系統框架及設備側枚舉過程。

二. usb枚舉過程分析

      usb設備主要有6種狀態:attached,powered,default,address,configured,suspend.當root hub監測到有設備插入時,將其設置爲attached和powered態,然後復位hub port,將其設置成default,復位成功後設置usb設備地址,獲取設備、配置描述符,最後選擇並設置合適的usb配置。usb請求都是由usb主機發起的,usb設備只是被動響應主機的請求,不會主動向主機發送任何usb請求,以6410爲控制器的設備枚舉設備側程序流程大致如圖2,圖3所示。


圖2 以s3c6410爲設備控制器的usb枚舉過程設備側程序流程1


圖3  以s3c6410爲設備控制器的usb枚舉過程設備側程序流程2

如圖2,由於usb設備處理被動地位,不能主動去發送數據,所有的請求都是由主機發起,而usb設備在接收到來自主機的請求後,產生接收數據中斷,在中斷處理程序中,通過不同的請求類型響應不同操作。

三.程序分析

       在響應host端的枚舉過程前,device側要先把device controller和gadget driver註冊到系統中,否則device側不會對host請求做出任務反映,這點在<usb gadget api for linux>裏的3.1 driver life cycle講得比較清楚,所以在講枚舉過程前要先分析device controller和gadget driver註冊到系統過程,下面幾個數據結構是device側經常用到,在這裏簡單介紹一下:
struct usb_gadget_driver:用來存放gadget驅動;
struct usb_request:用來存放usb device側usb請求數據;
struct usb_gadget:用來表示一個usb設備側設備;
struct usb_gadget_ops:gadget API函數接口,和設備控制器相關;
struct usb_ep_ops:用於操作usb設備endpoint函數接口,和設備控制器相關。
struct usb_composite_driver:複合型設備驅動;
struct usb_composite_dev:複合型設備;

1. usb device controller註冊

s3c6410 otg controller driver通過平臺註冊方式註冊,當平臺驅動和平臺設備通過platform_match時,就會調用s3c_hsotg_probe.
[html] view plaincopy
  1. static int __devinit s3c_hsotg_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c_hsotg_plat *plat = pdev->dev.platform_data;  
  4.     struct device *dev = &pdev->dev;  
  5.     struct s3c_hsotg *hsotg;  
  6.     struct resource *res;  
  7.     int epnum;  
  8.     int ret;  
  9.   
  10.     if (!plat)  
  11.         plat = &s3c_hsotg_default_pdata;  
  12.   
  13.     hsotg = kzalloc(sizeof(struct s3c_hsotg) +  
  14.             sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS,  
  15.             GFP_KERNEL);  
  16.     if (!hsotg) {  
  17.         dev_err(dev, "cannot get memory\n");  
  18.         return -ENOMEM;  
  19.     }  
  20.   
  21.     hsotg->dev = dev;  
  22.     hsotg->plat = plat;  
  23.   
  24.     hsotg->clk = clk_get(&pdev->dev, "otg");  
  25.     if (IS_ERR(hsotg->clk)) {  
  26.         dev_err(dev, "cannot get otg clock\n");  
  27.         ret = PTR_ERR(hsotg->clk);  
  28.         goto err_mem;  
  29.     }  
  30.   
  31.     platform_set_drvdata(pdev, hsotg);  
  32.   
  33.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  34.     if (!res) {  
  35.         dev_err(dev, "cannot find register resource 0\n");  
  36.         ret = -EINVAL;  
  37.         goto err_clk;  
  38.     }  
  39.   
  40.     hsotg->regs_res = request_mem_region(res->start, resource_size(res),  
  41.                          dev_name(dev));  
  42.     if (!hsotg->regs_res) {  
  43.         dev_err(dev, "cannot reserve registers\n");  
  44.         ret = -ENOENT;  
  45.         goto err_clk;  
  46.     }  
  47.   
  48.     hsotg->regs = ioremap(res->start, resource_size(res));  
  49.     if (!hsotg->regs) {  
  50.         dev_err(dev, "cannot map registers\n");  
  51.         ret = -ENXIO;  
  52.         goto err_regs_res;  
  53.     }  
  54.   
  55.     ret = platform_get_irq(pdev, 0);  
  56.     if (ret < 0) {  
  57.         dev_err(dev, "cannot find IRQ\n");  
  58.         goto err_regs;  
  59.     }  
  60.   
  61.     hsotg->irq = ret;  
  62.   
  63.     ret = request_irq(ret, s3c_hsotg_irq, 0, dev_name(dev), hsotg);  
  64.     if (ret < 0) {  
  65.         dev_err(dev, "cannot claim IRQ\n");  
  66.         goto err_regs;  
  67.     }  
  68.   
  69.     dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);  
  70.   
  71.     device_initialize(&hsotg->gadget.dev);  
  72.   
  73.     dev_set_name(&hsotg->gadget.dev, "gadget");  
  74.   
  75.     hsotg->gadget.is_dualspeed = 1;  
  76.     hsotg->gadget.ops = &s3c_hsotg_gadget_ops;  
  77.     hsotg->gadget.name = dev_name(dev);  
  78.   
  79.     hsotg->gadget.dev.parent = dev;  
  80.     hsotg->gadget.dev.dma_mask = dev->dma_mask;  
  81.   
  82.     /* setup endpoint information */  
  83.   
  84.     INIT_LIST_HEAD(&hsotg->gadget.ep_list);  
  85.     hsotg->gadget.ep0 = &hsotg->eps[0].ep;  
  86.   
  87.     /* allocate EP0 request */  
  88.   
  89.     hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep,  
  90.                              GFP_KERNEL);  
  91.     if (!hsotg->ctrl_req) {  
  92.         dev_err(dev, "failed to allocate ctrl req\n");  
  93.         goto err_regs;  
  94.     }  
  95.   
  96.     /* reset the system */  
  97.   
  98.     clk_enable(hsotg->clk);  
  99.   
  100.     s3c_hsotg_gate(pdev, true);  
  101.   
  102.     s3c_hsotg_otgreset(hsotg);  
  103.     s3c_hsotg_corereset(hsotg);  
  104.     s3c_hsotg_init(hsotg);  
  105.   
  106.     /* initialise the endpoints now the core has been initialised */  
  107.     for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)  
  108.         s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);  
  109.   
  110.     ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);  
  111.     if (ret)  
  112.         goto err_add_udc;  
  113.   
  114.     s3c_hsotg_create_debug(hsotg);  
  115.   
  116.     s3c_hsotg_dump(hsotg);  
  117.   
  118.     our_hsotg = hsotg;  
  119.     return 0;  
  120.   
  121. err_add_udc:  
  122.     s3c_hsotg_gate(pdev, false);  
  123.     clk_disable(hsotg->clk);  
  124.     clk_put(hsotg->clk);  
  125.   
  126. err_regs:  
  127.     iounmap(hsotg->regs);  
  128.   
  129. err_regs_res:  
  130.     release_resource(hsotg->regs_res);  
  131.     kfree(hsotg->regs_res);  
  132. err_clk:  
  133.     clk_put(hsotg->clk);  
  134. err_mem:  
  135.     kfree(hsotg);  
  136.     return ret;  
  137. }  

s3c_hsotg_probe主要分爲3個部分內容:
第一部分由12-67行,主要用於申請內存、中斷資源,並映射內存、申請中斷。
第二部分69-108行,主要實現用gadget結構,各endpoint初始化,併爲endpoint0申請用於接收host請求的usb request數據結構.
第三部分110行,通過usb_add_gadget_udc把gadget設備註冊到系統中,系統中有一個udc_list,專門用於管理通過usb_add_gadget_udc註冊到系統的struct usb_udc.

2.usb composite driver和gadget driver註冊

  根據usb協議5.3.2節定義"A device that has multiple interfaces controlled independently of each other is referred to as a composite device",如果一個usb設備由多個相互獨立控制接口構成,則做複合型usb設備,具體可參考<http://www.cygnal.org/ubb/Forum9/HTML/001050.html>這裏有對composite device進行比較詳細說明。由於複合型設備由各個獨立的接口組成,一個接口對應一個功能驅動,對於一個新的複合型設備,就沒必要開發一個完整驅動,完全可以直接使用現有的接口驅動,所以複合型設備有利於usb設備驅動開發。
    目前,內核中提供了usb_composite_driver和usb_composite_dev用表徵一個複合型驅動和設備,除此之外,內核還提供了像usb_add_config,usb_add_function等接口用來添加一個設備的配置和功能接口。
    本文將以內核中比較簡單的zero_driver來對composite框架進行分析,zero是用來測試主機控制器驅動的設備側驅動,主機端一般用usb_test,usb_skeleton模塊,zero模塊包含兩種配置,一個是迴環傳輸,它有兩個端口(endpoint),一個是in,一個是out,in用來接收host端數據,out用來將host收到的數據轉發給host;另一個配置是source/sink傳輸,它也有兩個端口sink和source,sink是用來接收來自 host端口數據,而source則用來發送數據給host,發數的數據要麼全0或由算法得到。

[html] view plaincopy
  1. static struct usb_composite_driver zero_driver = {  
  2.     .name       = "zero",  
  3.     .dev        = &device_desc,  
  4.     .strings    = dev_strings,  
  5.     .max_speed  = USB_SPEED_SUPER,  
  6.     .unbind     = zero_unbind,  
  7.     .suspend    = zero_suspend,  
  8.     .resume     = zero_resume,  
  9. };  
           zero_driver中dev定義了初始的usb設備描述符,之後會在zero_bind中補全其它參量,在usb枚舉的過程中會將這個完整的設備描述符發送回給host。
           strings定義了struct usb_gadget_string結構數組,裏而包含了生產產家,產品編號及序列號等信息。
        composite設備驅動由usb_composite_probe註冊,usb_composite_unregister接口卸載。

[html] view plaincopy
  1. static int __init init(void)  
  2. {  
  3.     return usb_composite_probe(&zero_driver, zero_bind);  
  4. }  
  5. module_init(init);  
  6.   
  7. static void __exit cleanup(void)  
  8. {  
  9.     usb_composite_unregister(&zero_driver);  
  10. }  
  11. module_exit(cleanup);  
         usb_composite_probe接口定義如下,它有兩個型參,一個是usb_composite_driver,一個是 composite驅動的回調函數,回調函數工作主要有:通過usb_add_config來添加usb配置,補全設備描述符,獲取設備ID,具體後面用到時再分析,接下來先看usb_composite_probe函數。
[html] view plaincopy
  1. int usb_composite_probe(struct usb_composite_driver *driver,  
  2.                    int (*bind)(struct usb_composite_dev *cdev))  
  3. {  
  4.     if (!driver || !driver->dev || !bind || composite)  
  5.         return -EINVAL;  
  6.   
  7.     if (!driver->name)  
  8.         driver->name = "composite";  
  9.     if (!driver->iProduct)  
  10.         driver->iProduct = driver->name;  
  11.     composite_driver.function =  (char *) driver->name;  
  12.     composite_driver.driver.name = driver->name;  
  13.     composite_driver.speed = min((u8)composite_driver.speed,  
  14.                      (u8)driver->max_speed);  
  15.     composite = driver;  
  16.     composite_gadget_bind = bind;  
  17.   
  18.     return usb_gadget_probe_driver(&composite_driver, composite_bind);  
  19. }  
       usb_composite_probe用來將usb_composite_driver註冊到composite driver框架中,這裏通過一個composite變量用來保存composite driver,composite_gadget_bind保存bind,並通過composite driver中的些變量來補全一個usb_gadget_driver composite_driver.之前簡介裏有提到過,gadget設備側程序主要由gadget driver和device controller driver組成 ,這裏這個composite_driver就是device controller driver上面的那與硬件無關的那一層,composite_driver定義如下:
[html] view plaincopy
  1. static struct usb_gadget_driver composite_driver = {  
  2. #ifdef CONFIG_USB_GADGET_SUPERSPEED  
  3.     .speed      = USB_SPEED_SUPER,  
  4. #else  
  5.     .speed      = USB_SPEED_HIGH,  
  6. #endif  
  7.   
  8.     .unbind     = composite_unbind,  
  9.   
  10.     .setup      = composite_setup,  
  11.     .disconnect = composite_disconnect,  
  12.   
  13.     .suspend    = composite_suspend,  
  14.     .resume     = composite_resume,  
  15.   
  16.     .driver = {  
  17.         .owner      = THIS_MODULE,  
  18.     },  
  19. };  
      composite_driver中的setup函數最爲重要,簡介中曾經說過,device controller driver用來完成和硬件相關的設備或迴應,如設置usb設備地址,ACK應答之類機制。但像獲取設備描述符,設置配置,設置接口等機制並沒有實現,這些請求的處理機制就是在這個setup裏完成的。
      usb_gadget_driver由usb_gadget_probe_driver和usb_gadget_unregister_dirver完成。usb_gadget_probe_driver除了包含gadget driver外,還包括了gadget驅動中的回調函數composite_bind.
[html] view plaincopy
  1. int usb_gadget_probe_driver(struct usb_gadget_driver *driver,  
  2.         int (*bind)(struct usb_gadget *))  
  3. {  
  4.     struct usb_udc      *udc = NULL;  
  5.     int         ret;  
  6.   
  7.     if (!driver || !bind || !driver->setup)  
  8.         return -EINVAL;  
  9.   
  10.     mutex_lock(&udc_lock);  
  11.     list_for_each_entry(udc, &udc_list, list) {  
  12.         /* For now we take the first one */  
  13.         if (!udc->driver)  
  14.             goto found;  
  15.     }  
  16.   
  17.     pr_debug("couldn't find an available UDC\n");  
  18.     mutex_unlock(&udc_lock);  
  19.     return -ENODEV;  
  20.   
  21. found:  
  22.     dev_dbg(&udc->dev, "registering UDC driver [%s]\n",  
  23.             driver->function);  
  24.   
  25.     udc->driver = driver;  
  26.     udc->dev.driver = &driver->driver;  
  27.   
  28.     if (udc_is_newstyle(udc)) {  
  29.         ret = bind(udc->gadget);  
  30.         if (ret)  
  31.             goto err1;  
  32.         ret = usb_gadget_udc_start(udc->gadget, driver);  
  33.         if (ret) {  
  34.             driver->unbind(udc->gadget);  
  35.             goto err1;  
  36.         }  
  37.         usb_gadget_connect(udc->gadget);  
  38.     } else {  
  39.   
  40.         ret = usb_gadget_start(udc->gadget, driver, bind);  
  41.         if (ret)  
  42.             goto err1;  
  43.   
  44.     }  
  45.   
  46.     kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);  
  47.     mutex_unlock(&udc_lock);  
  48.     return 0;  
  49.   
  50. err1:  
  51.     dev_err(&udc->dev, "failed to start %s: %d\n",  
  52.             udc->driver->function, ret);  
  53.     udc->driver = NULL;  
  54.     udc->dev.driver = NULL;  
  55.     mutex_unlock(&udc_lock);  
  56.     return ret;  
  57. }  
        這前在講device controller 註冊時講過,通過usb_add_gadget_udc註冊device controller時,linux系統是通過一個struct usb_udc結構的udc_list列表中進行管理設備控制器的,struct usb_udc結構如下:
[html] view plaincopy
  1. struct usb_udc {  
  2.     struct usb_gadget_driver    *driver;  
  3.     struct usb_gadget       *gadget;  
  4.     struct device           dev;  
  5.     struct list_head        list;  
  6. };  
           driver用於表示一個udc驅動,而 list就是用來加入到udc_list列表的入口變量。
           在usb_gadget_probe_driver中的11-15行,對udc_list 列表進行遍歷,查看是否有udc控制器沒有添加相對應的驅動,如果找不到說明系統中沒有註冊udc或每個udc都有相應的驅動。
        如果udc列表中有某個udc沒有驅動,則將usb_gadgett_driver和相應udc關聯在一起。
        28-44行通過判斷usb device controller實現模式爲選擇運行程序,由於版本兼容原因,操作控制器硬件的ops裏包含了新的和舊的操作接口。
[html] view plaincopy
  1.        int  (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *);  
  2. int (*udc_stop)(struct usb_gadget *, struct usb_gadget_driver *);  
  3. /* Those two are deprecated */  
  4. int (*start)(struct usb_gadget_driver *, int (*bind)(struct usb_gadget *));  
  5. int (*stop)(struct usb_gadget_driver *);  
         其中,udc_start 和udc_stop爲新版本操作接口 ,而start 和stop老版本操作接口。
         由於本文所採用的內核是老版本的接口,所以會運行下面usb_gadget_start函數。
         usb_gadget_start函數將會以gadget_driver和composite_bind爲參數調用usb device controller的ops中的start回調函數,在註冊usb device controller時就定義了ops 的start回調函數爲s3c_hsotg_start
         如果usb_gadget_start運行正常則通過object_uevent來通知用戶發生了KOBJ_CHANGE事件,用戶空間中的udev程序就會採取相應操作。
         s3c_hsotg_start函數裏主要是涉及低層寄存器控制,在這裏就不去深入研究了,composite_bind將會在s3c_hsotg_start中被調用。
 
[html] view plaincopy
  1. static int composite_bind(struct usb_gadget *gadget)  
  2. {  
  3.     struct usb_composite_dev    *cdev;  
  4.     int             status = -ENOMEM;  
  5.   
  6.     cdev = kzalloc(sizeof *cdev, GFP_KERNEL);  
  7.     if (!cdev)  
  8.         return status;  
  9.   
  10.     spin_lock_init(&cdev->lock);  
  11.     cdev->gadget = gadget;  
  12.     set_gadget_data(gadget, cdev);  
  13.     INIT_LIST_HEAD(&cdev->configs);  
  14.   
  15.     /* preallocate control response and buffer */  
  16.     cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);  
  17.     if (!cdev->req)  
  18.         goto fail;  
  19.     cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);  
  20.     if (!cdev->req->buf)  
  21.         goto fail;  
  22.     cdev->req->complete = composite_setup_complete;  
  23.     gadget->ep0->driver_data = cdev;  
  24.   
  25.     cdev->bufsiz = USB_BUFSIZ;  
  26.     cdev->driver = composite;  
  27.   
  28.     /*  
  29.      * As per USB compliance update, a device that is actively drawing  
  30.      * more than 100mA from USB must report itself as bus-powered in  
  31.      * the GetStatus(DEVICE) call.  
  32.      */  
  33.     if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)  
  34.         usb_gadget_set_selfpowered(gadget);  
  35.   
  36.     /* interface and string IDs start at zero via kzalloc.  
  37.      * we force endpoints to start unassigned; few controller  
  38.      * drivers will zero ep->driver_data.  
  39.      */  
  40.     usb_ep_autoconfig_reset(cdev->gadget);  
  41.   
  42.     /* composite gadget needs to assign strings for whole device (like  
  43.      * serial number), register function drivers, potentially update  
  44.      * power state and consumption, etc  
  45.      */  
  46.     status = composite_gadget_bind(cdev);  
  47.     if (status < 0)  
  48.         goto fail;  
  49.   
  50.     cdev->desc = *composite->dev;  
  51.   
  52.     /* standardized runtime overrides for device ID data */  
  53.     if (idVendor)  
  54.         cdev->desc.idVendor = cpu_to_le16(idVendor);  
  55.     if (idProduct)  
  56.         cdev->desc.idProduct = cpu_to_le16(idProduct);  
  57.     if (bcdDevice)  
  58.         cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);  
  59.   
  60.     /* string overrides */  
  61.     if (iManufacturer || !cdev->desc.iManufacturer) {  
  62.         if (!iManufacturer && !composite->iManufacturer &&  
  63.             !*composite_manufacturer)  
  64.             snprintf(composite_manufacturer,  
  65.                  sizeof composite_manufacturer,  
  66.                  "%s %s with %s",  
  67.                  init_utsname()->sysname,  
  68.                  init_utsname()->release,  
  69.                  gadget->name);  
  70.   
  71.         cdev->manufacturer_override =  
  72.             override_id(cdev, &cdev->desc.iManufacturer);  
  73.     }  
  74.   
  75.     if (iProduct || (!cdev->desc.iProduct && composite->iProduct))  
  76.         cdev->product_override =  
  77.             override_id(cdev, &cdev->desc.iProduct);  
  78.   
  79.     if (iSerialNumber)  
  80.         cdev->serial_override =  
  81.             override_id(cdev, &cdev->desc.iSerialNumber);  
  82.   
  83.     /* has userspace failed to provide a serial number? */  
  84.     if (composite->needs_serial && !cdev->desc.iSerialNumber)  
  85.         WARNING(cdev, "userspace failed to provide iSerialNumber\n");  
  86.   
  87.     /* finish up */  
  88.     status = device_create_file(&gadget->dev, &dev_attr_suspended);  
  89.     if (status)  
  90.         goto fail;  
  91.   
  92.     INFO(cdev, "%s ready\n", composite->name);  
  93.     return 0;  
  94.   
  95. fail:  
  96.     composite_unbind(gadget);  
  97.     return status;  
  98. }  
         在將gadget driver和usb device controller聯繫在一起後,composite_bind將會生成一個composite dev數據結構,並對其進行初始化,然後申請用於回覆endpoint0的控制端口的usb request資源,最後調用composite回調函數zero_bind用來爲composite usb device 添加配置。
         第6-8行爲composite dev結構申請空間。
         第10-13行初始化composite dev中自旋鎖,對向列表頭等。
         第16-23行,申請用於回覆endpoint0控制口的usb請求資源,這個請求用來回復host端獲取設備描述符,配置描述符等需要返回數據的usb請求,併爲usb請求申請用於存放發送數據內存空間,爲usb請求回調函數賦值,當usb請求被髮送出去後就會調用回調函數來通知usb請求發出者.
         第26行,把之前保存在composite裏的composite_driver賦值給cdev->driver。
         第46行,調用usb_composite_driver回調函數zero_bind。
         第47行,把複合型設備描述符保存在cdev的desc裏。
         第52-57行,如果在加載模塊時指定了生產產家ID,產口ID和設備版本號,則用指定的值來代替原來的值。
         第60-80行,用於設置設備描述符中的iManufacturer,iProduct和iSerialNumber,如果沒有設置這幾個變量的index,則通過override_id來獲取ID,本文已經在zero_driver中的zero_bind獲取了。
         第84-85行,如果設置在usb_composite_driver設置了need_serial項,則需要用戶空間提供usb設備的serial id,如果沒有提供則發出warn。
         第88行,通過device_create_file生成一個用生查詢usb設備是否suspend狀態的設備屬性函數。
         如果假設zero_bind運行正常,還有下面創建設備文件也正常,則 一個gadget設備準備工作都已經完成 ,gadget設備可以與host設備進行通信 。
         在講具體的枚舉過程之前,先完成對zero_bind函數裏面分析。
      
[html] view plaincopy
  1. static int __init zero_bind(struct usb_composite_dev *cdev)  
  2. {  
  3.     int         gcnum;  
  4.     struct usb_gadget   *gadget = cdev->gadget;  
  5.     int         id;  
  6.   
  7.     /* Allocate string descriptor numbers ... note that string  
  8.      * contents can be overridden by the composite_dev glue.  
  9.      */  
  10.     id = usb_string_id(cdev);  
  11.     if (id < 0)  
  12.         return id;  
  13.     strings_dev[STRING_MANUFACTURER_IDX].id = id;  
  14.     device_desc.iManufacturer = id;  
  15.   
  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.   
  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.   
  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.         sourcesink_add(cdev, autoresume != 0);  
  36.     } else {  
  37.         sourcesink_add(cdev, autoresume != 0);  
  38.         loopback_add(cdev, autoresume != 0);  
  39.     }  
  40.   
  41.     gcnum = usb_gadget_controller_number(gadget);  
  42.     if (gcnum >= 0)  
  43.         device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);  
  44.     else {  
  45.         /* gadget zero is so simple (for now, no altsettings) that  
  46.          * it SHOULD NOT have problems with bulk-capable hardware.  
  47.          * so just warn about unrcognized controllers -- don't panic.  
  48.          *  
  49.          * things like configuration and altsetting numbering  
  50.          * can need hardware-specific attention though.  
  51.          */  
  52.         pr_warning("%s: controller '%s' not recognized\n",  
  53.             longname, gadget->name);  
  54.         device_desc.bcdDevice = cpu_to_le16(0x9999);  
  55.     }  
  56.   
  57.   
  58.     INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);  
  59.   
  60.     snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",  
  61.         init_utsname()->sysname, init_utsname()->release,  
  62.         gadget->name);  
  63.   
  64.     return 0;  
  65. }  
       zero_bind主要用於設置設備描述符中bcdDevice,iManufacturer,iProduct及iSerialNumber,然後通過loopback_add和sourcesink_add添加usb配置。
       10-14行,通過usb_string_id來爲生產產家獲取一個 ID,在usb_composite_dev中的next_string_id專門用來管理string ID,只要next_string_id小於254就可以合法獲取string ID,獲取到stringID後把它保存到usb設備描述符裏的iManufacturer及複合設備結構中的strings裏。
       16-20行,用於獲取產品ID,並存入設備描述符和複合設備結構中的strings裏。
       22-26行,用於獲取設備系列號,並存入相應結構中。
       28行,設備一個timer_list定時器,用於設備suspend和resume這裏不深入分析。
       34-39行通過loopback_add和sourcesink_add添加usb配置,前面有提到過,loopback配置用來將從host 接收到的數據發送給host,而sourcesink配置則是在接收到host數據後,向host發送全0或算法生成的數據,兩者只是在發送回給host的數據存在差別,這裏只對其中的loopback進行分析, sourcesind_add就不深入研究了。
       41-55行根據device controller類型來獲取設備版本號,如果device controller沒有匹配項,則將設備版本號設置成0X9999.
[html] view plaincopy
  1. int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)  
  2. {  
  3.     int id;  
  4.   
  5.     /* allocate string ID(s) */  
  6.     id = usb_string_id(cdev);  
  7.     if (id < 0)  
  8.         return id;  
  9.     strings_loopback[0].id = id;  
  10.   
  11.     loopback_intf.iInterface = id;  
  12.     loopback_driver.iConfiguration = id;  
  13.   
  14.     /* support autoresume for remote wakeup testing */  
  15.     if (autoresume)  
  16.         sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  
  17.   
  18.     /* support OTG systems */  
  19.     if (gadget_is_otg(cdev->gadget)) {  
  20.         loopback_driver.descriptors = otg_desc;  
  21.         loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  
  22.     }  
  23.   
  24.     return usb_add_config(cdev, &loopback_driver, loopback_bind_config);  
  25. }  
       loopback_add主要是完成loopback這個配置描述符裏的配置ID設置,並通過usb_add_config向usb設備添加loopback_driver這個配置。
       6-12行用於獲取配置的ID,並保存到配置描述符中。
       15-16行,如果usb設備這個配置支持喚醒功能,則在usb_configuration時的bmAttributes裏wakeup置位。
       19-22行,如果支持otg功能,則還需要添加otg 描述符。
       24行通過usb_add_config添加loopback_driver配置,loopback_driver定義如下:
[html] view plaincopy
  1. static struct usb_configuration loopback_driver = {  
  2.     .label      = "loopback",  
  3.     .strings    = loopback_strings,  
  4.     .bConfigurationValue = 2,  
  5.     .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,  
  6.     /* .iConfiguration = DYNAMIC */  
  7. };  
        label爲配置名字,strings裏用於申明配置功能的string,bConfigurationValue用來表示當前配置值,在USB枚舉時就能通過選擇合適的配置值來設備usb設備的配置,bmAttributes用來表明配置的特性,如自供電,遠程喚醒等。
      用usb_add_config添加配置時,需要三個參數,usb_composite_dev結構cdev, usb配置loopback_driver和配置的回調函數loopback_bind_config.
[html] view plaincopy
  1. int usb_add_config(struct usb_composite_dev *cdev,  
  2.         struct usb_configuration *config,  
  3.         int (*bind)(struct usb_configuration *))  
  4. {  
  5.     int             status = -EINVAL;  
  6.     struct usb_configuration    *c;  
  7.   
  8.     DBG(cdev, "adding config #%u '%s'/%p\n",  
  9.             config->bConfigurationValue,  
  10.             config->label, config);  
  11.   
  12.     if (!config->bConfigurationValue || !bind)  
  13.         goto done;  
  14.   
  15.     /* Prevent duplicate configuration identifiers */  
  16.     list_for_each_entry(c, &cdev->configs, list) {  
  17.         if (c->bConfigurationValue == config->bConfigurationValue) {  
  18.             status = -EBUSY;  
  19.             goto done;  
  20.         }  
  21.     }  
  22.   
  23.     config->cdev = cdev;  
  24.     list_add_tail(&config->list, &cdev->configs);  
  25.   
  26.     INIT_LIST_HEAD(&config->functions);  
  27.     config->next_interface_id = 0;  
  28.   
  29.     status = bind(config);  
  30.     if (status < 0) {  
  31.         list_del(&config->list);  
  32.         config->cdev = NULL;  
  33.     } else {  
  34.         unsigned    i;  
  35.   
  36.         DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",  
  37.             config->bConfigurationValue, config,  
  38.             config->superspeed ? " super" : "",  
  39.             config->highspeed ? " high" : "",  
  40.             config->fullspeed  
  41.                 ? (gadget_is_dualspeed(cdev->gadget)  
  42.                     ? " full"  
  43.                     : " full/low")  
  44.                 : "");  
  45.   
  46.         for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {  
  47.             struct usb_function *f = config->interface[i];  
  48.   
  49.             if (!f)  
  50.                 continue;  
  51.             DBG(cdev, "  interface %d = %s/%p\n",  
  52.                 i, f->name, f);  
  53.         }  
  54.     }  
  55.   
  56.     /* set_alt(), or next bind(), sets up  
  57.      * ep->driver_data as needed.  
  58.      */  
  59.     usb_ep_autoconfig_reset(cdev->gadget);  
  60.   
  61. done:  
  62.     if (status)  
  63.         DBG(cdev, "added config '%s'/%u --> %d\n", config->label,  
  64.                 config->bConfigurationValue, status);  
  65.     return status;  
  66. }  
usb_add_config用來向複合型usb設備添加一個usb配置,並對配置進行初始化,最後調用配置的回調函數loopback_bind_config向當前配置添加usb接口。
在配置描述符中的bConfigurationValue用來表示配置值,一個複合型設備有可能包含多個配置,配置之間通過這個bConfigurationValue來區別。第12-21行,在添加配置前會先判斷配置值和回調函數是否已經設置,然後再通過遍歷複合設備中配置列表來判斷當前配置是否已經添加到設備,如果已經添加就會返回busy錯誤,以防止向設備添加同一配置值的配置。
23-24行,配置和複合設備進行相互綁定,複合設備結構中有專門用於管理設備配置的雙向列表,把當前配置加入到雙向列表中。
25-27行,對配置結構中function列表頭和用於管理當前配置接口ID變量進行初始化。
29行,調用配置回調函數loopback_bind_config,向配置中添加usb接口(usb_function,在usb中,一個接口對應一個功能)。

[html] view plaincopy
  1. static int __init loopback_bind_config(struct usb_configuration *c)  
  2. {  
  3.     struct f_loopback   *loop;  
  4.     int         status;  
  5.   
  6.     loop = kzalloc(sizeof *loop, GFP_KERNEL);  
  7.     if (!loop)  
  8.         return -ENOMEM;  
  9.   
  10.     loop->function.name = "loopback";  
  11.     loop->function.descriptors = fs_loopback_descs;  
  12.     loop->function.bind = loopback_bind;  
  13.     loop->function.unbind = loopback_unbind;  
  14.     loop->function.set_alt = loopback_set_alt;  
  15.     loop->function.disable = loopback_disable;  
  16.   
  17.     status = usb_add_function(c, &loop->function);  
  18.     if (status)  
  19.         kfree(loop);  
  20.     return status;  
  21. }  

loopback_bind_config用來向當前配置添加接口功能,它先申請了一個f_loopback數據結構,裏面包含了usb的接口和端口,然後對接口一些函數接口進行初始化,最後調用usb_add_function把接口添加到配置中。在接口的操作函數接口中,bind和set_alt相對比較重要,在usb_add_function中會調用bind來完成某個接口中各端口(endpoint)的初始化,而在枚舉過程中設置接口USB請求就是通過這個接口實現。

[html] view plaincopy
  1. int 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.   
  16.     /* REVISIT *require* function->bind? */  
  17.     if (function->bind) {  
  18.         value = function->bind(config, function);  
  19.         if (value < 0) {  
  20.             list_del(&function->list);  
  21.             function->config = NULL;  
  22.         }  
  23.     } else  
  24.         value = 0;  
  25.   
  26.     /* We allow configurations that don't work at both speeds.  
  27.      * If we run into a lowspeed Linux system, treat it the same  
  28.      * as full speed ... it's the function drivers that will need  
  29.      * to avoid bulk and ISO transfers.  
  30.      */  
  31.     if (!config->fullspeed && function->descriptors)  
  32.         config->fullspeed = true;  
  33.     if (!config->highspeed && function->hs_descriptors)  
  34.         config->highspeed = true;  
  35.     if (!config->superspeed && function->ss_descriptors)  
  36.         config->superspeed = true;  
  37.   
  38. done:  
  39.     if (value)  
  40.         DBG(config->cdev, "adding '%s'/%p --> %d\n",  
  41.                 function->name, function, value);  
  42.     return value;  
  43. }  
usb_add_function主要用來綁定配置和接口,然後調用接口中bind函數。
13-14行,配置和接口相互綁定,將接口添加到配置裏用於管理接口的雙向列表中。
17-24行,哪裏在接口操作函數中定義了bind函數,則調用bind函數,如調用失敗則將綁定的配置和接口分開。
31-36行,根據接口中定義的各種速度的接口和字符串標識來確定當前配置所支持速度。
[html] view plaincopy
  1. static int __init  
  2. loopback_bind(struct usb_configuration *c, struct usb_function *f)  
  3. {  
  4.     struct usb_composite_dev *cdev = c->cdev;  
  5.     struct f_loopback   *loop = func_to_loop(f);  
  6.     int         id;  
  7.   
  8.     /* allocate interface ID(s) */  
  9.     id = usb_interface_id(c, f);  
  10.     if (id < 0)  
  11.         return id;  
  12.     loopback_intf.bInterfaceNumber = id;  
  13.   
  14.     /* allocate endpoints */  
  15.   
  16.     loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);  
  17.     if (!loop->in_ep) {  
  18. autoconf_fail:  
  19.         ERROR(cdev, "%s: can't autoconfigure on %s\n",  
  20.             f->name, cdev->gadget->name);  
  21.         return -ENODEV;  
  22.     }  
  23.     loop->in_ep->driver_data = cdev;  /* claim */  
  24.   
  25.     loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);  
  26.     if (!loop->out_ep)  
  27.         goto autoconf_fail;  
  28.     loop->out_ep->driver_data = cdev; /* claim */  
  29.   
  30.     /* support high speed hardware */  
  31.     if (gadget_is_dualspeed(c->cdev->gadget)) {  
  32.         hs_loop_source_desc.bEndpointAddress =  
  33.                 fs_loop_source_desc.bEndpointAddress;  
  34.         hs_loop_sink_desc.bEndpointAddress =  
  35.                 fs_loop_sink_desc.bEndpointAddress;  
  36.         f->hs_descriptors = hs_loopback_descs;  
  37.     }  
  38.   
  39.     /* support super speed hardware */  
  40.     if (gadget_is_superspeed(c->cdev->gadget)) {  
  41.         ss_loop_source_desc.bEndpointAddress =  
  42.                 fs_loop_source_desc.bEndpointAddress;  
  43.         ss_loop_sink_desc.bEndpointAddress =  
  44.                 fs_loop_sink_desc.bEndpointAddress;  
  45.         f->ss_descriptors = ss_loopback_descs;  
  46.     }  
  47.   
  48.     DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",  
  49.         (gadget_is_superspeed(c->cdev->gadget) ? "super" :  
  50.          (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),  
  51.             f->name, loop->in_ep->name, loop->out_ep->name);  
  52.     return 0;  
  53. }  
loopback_bind主要用於配置接口中的端口。
一個usb配置有可能包含多個接口,可能用接口號來表示不同的接口,前面講過配置中有一個專門用來管理接口號的變量next_interface_id,9-12行,用於獲取一個接口號並把它存入到接口描述符中。
第16-23和25-28行,分別 調用usb_ep_autoconfig函數,從gadget的ep_list找到in和out端口;
在usb接口數據結構中有三個指針數組descriptors,hs_descriptors, ss_descriptors,它們分別用來存放三種不同速度的接口和端口描述符指針頭,descriptors用來存放全速接口和端口描述符指針頭,而hs_descriptors用來保存高速指針頭,ss_descriptors則用來保存超速指針頭。
第31-37行,判斷該usb設備是否支持高速傳輸,如果支持將高速端口描述符中的bEndpointAddress設置成和全速一樣,bEndpointAddress用來描述端口傳輸方向和端口號,這個和傳輸速度無關,所以都設置成一樣的。
第40-46行,判斷該usb設備是否支持超高速傳輸,如果支持超高速端口描述符中的bEndpointAddress設置成和全速一樣。
[html] view plaincopy
  1. struct usb_ep *usb_ep_autoconfig(  
  2.     struct usb_gadget       *gadget,  
  3.     struct usb_endpoint_descriptor  *desc  
  4. )  
  5. {  
  6.     return usb_ep_autoconfig_ss(gadget, desc, NULL);  
  7. }  
usb_ep_autoconfig函數是從gadget裏的ep_list找到與所給端口描述符相匹配的端口,函數裏面實際上是調用usb_ep_autoconfig_ss來實現端口匹配的。

[html] view plaincopy
  1. struct usb_ep *usb_ep_autoconfig_ss(  
  2.     struct usb_gadget       *gadget,  
  3.     struct usb_endpoint_descriptor  *desc,  
  4.     struct usb_ss_ep_comp_descriptor *ep_comp  
  5. )  
  6. {  
  7.     struct usb_ep   *ep;  
  8.     u8      type;  
  9.   
  10.     type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;  
  11.   
  12.     /* First, apply chip-specific "best usage" knowledge.  
  13.      * This might make a good usb_gadget_ops hook ...  
  14.      */  
  15.     if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {  
  16.         /* ep-e, ep-f are PIO with only 64 byte fifos */  
  17.         ep = find_ep (gadget, "ep-e");  
  18.         if (ep && ep_matches(gadget, ep, desc, ep_comp))  
  19.             return ep;  
  20.         ep = find_ep (gadget, "ep-f");  
  21.         if (ep && ep_matches(gadget, ep, desc, ep_comp))  
  22.             return ep;  
  23.   
  24.     } else if (gadget_is_goku (gadget)) {  
  25.         if (USB_ENDPOINT_XFER_INT == type) {  
  26.             /* single buffering is enough */  
  27.             ep = find_ep(gadget, "ep3-bulk");  
  28.             if (ep && ep_matches(gadget, ep, desc, ep_comp))  
  29.                 return ep;  
  30.         } else if (USB_ENDPOINT_XFER_BULK == type  
  31.                 && (USB_DIR_IN & desc->bEndpointAddress)) {  
  32.             /* DMA may be available */  
  33.             ep = find_ep(gadget, "ep2-bulk");  
  34.             if (ep && ep_matches(gadget, ep, desc,  
  35.                           ep_comp))  
  36.                 return ep;  
  37.         }  
  38.   
  39. #ifdef CONFIG_BLACKFIN  
  40.     } else if (gadget_is_musbhdrc(gadget)) {  
  41.         if ((USB_ENDPOINT_XFER_BULK == type) ||  
  42.             (USB_ENDPOINT_XFER_ISOC == type)) {  
  43.             if (USB_DIR_IN & desc->bEndpointAddress)  
  44.                 ep = find_ep (gadget, "ep5in");  
  45.             else  
  46.                 ep = find_ep (gadget, "ep6out");  
  47.         } else if (USB_ENDPOINT_XFER_INT == type) {  
  48.             if (USB_DIR_IN & desc->bEndpointAddress)  
  49.                 ep = find_ep(gadget, "ep1in");  
  50.             else  
  51.                 ep = find_ep(gadget, "ep2out");  
  52.         } else  
  53.             ep = NULL;  
  54.         if (ep && ep_matches(gadget, ep, desc, ep_comp))  
  55.             return ep;  
  56. #endif  
  57.     }  
  58.   
  59.     /* Second, look at endpoints until an unclaimed one looks usable */  
  60.     list_for_each_entry (ep, &gadget->ep_list, ep_list) {  
  61.         if (ep_matches(gadget, ep, desc, ep_comp))  
  62.             return ep;  
  63.     }  
  64.   
  65.     /* Fail */  
  66.     return NULL;  
  67. }  
usb_ep_autoconfig_ss函數有三個形參,分別是表示usb設備側設備gadget,端口描述符desc和專門用於描述超高速端口特性(usb 3.0裏纔有)的ep_comp,它首先通過匹配設備控制器芯片和端口傳輸類型來選擇端口,如沒有找到則在gadget的ep_list列表中尋找ep,並通過ep_matches匹配,如果找到相匹配的endpoint就返回該端口,否則返回null。

[html] view plaincopy
  1. static int  
  2. ep_matches (  
  3.     struct usb_gadget       *gadget,  
  4.     struct usb_ep           *ep,  
  5.     struct usb_endpoint_descriptor  *desc,  
  6.     struct usb_ss_ep_comp_descriptor *ep_comp  
  7. )  
  8. {  
  9.     u8      type;  
  10.     const char  *tmp;  
  11.     u16     max;  
  12.   
  13.     int     num_req_streams = 0;  
  14.   
  15.     /* endpoint already claimed? */  
  16.     if (NULL != ep->driver_data)  
  17.         return 0;  
  18.   
  19.     /* only support ep0 for portable CONTROL traffic */  
  20.     type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;  
  21.     if (USB_ENDPOINT_XFER_CONTROL == type)  
  22.         return 0;  
  23.   
  24.     /* some other naming convention */  
  25.     if ('e' != ep->name[0])  
  26.         return 0;  
  27.   
  28.     /* type-restriction:  "-iso", "-bulk", or "-int".  
  29.      * direction-restriction:  "in", "out".  
  30.      */  
  31.     if ('-' != ep->name[2]) {  
  32.         tmp = strrchr (ep->name, '-');  
  33.         if (tmp) {  
  34.             switch (type) {  
  35.             case USB_ENDPOINT_XFER_INT:  
  36.                 /* bulk endpoints handle interrupt transfers,  
  37.                  * except the toggle-quirky iso-synch kind  
  38.                  */  
  39.                 if ('s' == tmp[2])  // == "-iso"  
  40.                     return 0;  
  41.                 /* for now, avoid PXA "interrupt-in";  
  42.                  * it's documented as never using DATA1.  
  43.                  */  
  44.                 if (gadget_is_pxa (gadget)  
  45.                         && 'i' == tmp [1])  
  46.                     return 0;  
  47.                 break;  
  48.             case USB_ENDPOINT_XFER_BULK:  
  49.                 if ('b' != tmp[1])  // != "-bulk"  
  50.                     return 0;  
  51.                 break;  
  52.             case USB_ENDPOINT_XFER_ISOC:  
  53.                 if ('s' != tmp[2])  // != "-iso"  
  54.                     return 0;  
  55.             }  
  56.         } else {  
  57.             tmp = ep->name + strlen (ep->name);  
  58.         }  
  59.   
  60.         /* direction-restriction:  "..in-..", "out-.." */  
  61.         tmp--;  
  62.         if (!isdigit (*tmp)) {  
  63.             if (desc->bEndpointAddress & USB_DIR_IN) {  
  64.                 if ('n' != *tmp)  
  65.                     return 0;  
  66.             } else {  
  67.                 if ('t' != *tmp)  
  68.                     return 0;  
  69.             }  
  70.         }  
  71.     }  
  72.   
  73.     /*  
  74.      * Get the number of required streams from the EP companion  
  75.      * descriptor and see if the EP matches it  
  76.      */  
  77.     if (usb_endpoint_xfer_bulk(desc)) {  
  78.         if (ep_comp) {  
  79.             num_req_streams = ep_comp->bmAttributes & 0x1f;  
  80.             if (num_req_streams > ep->max_streams)  
  81.                 return 0;  
  82.             /* Update the ep_comp descriptor if needed */  
  83.             if (num_req_streams != ep->max_streams)  
  84.                 ep_comp->bmAttributes = ep->max_streams;  
  85.         }  
  86.   
  87.     }  
  88.   
  89.     /*  
  90.      * If the protocol driver hasn't yet decided on wMaxPacketSize  
  91.      * and wants to know the maximum possible, provide the info.  
  92.      */  
  93.     if (desc->wMaxPacketSize == 0)  
  94.         desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket);  
  95.   
  96.     /* endpoint maxpacket size is an input parameter, except for bulk  
  97.      * where it's an output parameter representing the full speed limit.  
  98.      * the usb spec fixes high speed bulk maxpacket at 512 bytes.  
  99.      */  
  100.     max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);  
  101.     switch (type) {  
  102.     case USB_ENDPOINT_XFER_INT:  
  103.         /* INT:  limit 64 bytes full speed, 1024 high/super speed */  
  104.         if (!gadget->is_dualspeed && max > 64)  
  105.             return 0;  
  106.         /* FALLTHROUGH */  
  107.   
  108.     case USB_ENDPOINT_XFER_ISOC:  
  109.         /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */  
  110.         if (ep->maxpacket < max)  
  111.             return 0;  
  112.         if (!gadget->is_dualspeed && max > 1023)  
  113.             return 0;  
  114.   
  115.         /* BOTH:  "high bandwidth" works only at high speed */  
  116.         if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {  
  117.             if (!gadget->is_dualspeed)  
  118.                 return 0;  
  119.             /* configure your hardware with enough buffering!! */  
  120.         }  
  121.         break;  
  122.     }  
  123.   
  124.     /* MATCH!! */  
  125.   
  126.     /* report address */  
  127.     desc->bEndpointAddress &= USB_DIR_IN;  
  128.     if (isdigit (ep->name [2])) {  
  129.         u8  num = simple_strtoul (&ep->name [2], NULL, 10);  
  130.         desc->bEndpointAddress |= num;  
  131. #ifdef  MANY_ENDPOINTS  
  132.     } else if (desc->bEndpointAddress & USB_DIR_IN) {  
  133.         if (++in_epnum > 15)  
  134.             return 0;  
  135.         desc->bEndpointAddress = USB_DIR_IN | in_epnum;  
  136. #endif  
  137.     } else {  
  138.         if (++epnum > 15)  
  139.             return 0;  
  140.         desc->bEndpointAddress |= epnum;  
  141.     }  
  142.   
  143.     /* report (variable) full speed bulk maxpacket */  
  144.     if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {  
  145.         int size = ep->maxpacket;  
  146.   
  147.         /* min() doesn't work on bitfields with gcc-3.5 */  
  148.         if (size > 64)  
  149.             size = 64;  
  150.         desc->wMaxPacketSize = cpu_to_le16(size);  
  151.     }  
  152.     ep->address = desc->bEndpointAddress;  
  153.     return 1;  
  154. }  
ep_matches通過端口描述符的一些特性來和gadget ep_list進行比較,device controller在初始化endpoint時,會將endpoint的名字設置成好幾種類型:

1.ep1,  ep2, ... 地址確定,方向和類型不確定;

2. ep1in, ep2out, ...地址和方向確定,類型不確定;

3. ep1-bulk, ep2-bulk, ... 地址和類型確定,方向不確定;

4. ep1in-bulk, ep2out-iso, ... 地址,方向和類型都確定;

5.  ep-* ... 沒有任何限制;

ep_matches首先通過比較端口傳輸地址,方向和類型,然後再比較速度等信息來匹配,如果不匹配則返回0,否則如果條件都滿足則返回1。

31-58行,首先根據endpoint的name和端口描述符所指定的傳輸類型進行比較,對於中斷傳輸如'-'後面第二個字符是s,即表示iso,那肯定不匹配,直接返回,對於批量傳輸如果‘-’後面第一個字符不是b,則不匹配,對於等時傳輸,‘-’後第二個字符應該是s.

62-69根據端口描述符中的bEndpointAddress和endpoint中的name進行比較,如果端口傳輸方向爲in,但發現name卻不是以n字符結尾,則不匹配,如果端口傳輸方面是out,而name不以t結尾,則不匹配;

77-87行是對超高速設備進行判斷;

93-94行,如果端口描述符裏沒有指定最大傳輸長度,但將當前endpoint的最大傳輸長度賦值給端口描述符。

端口描述符中的wMaxPacketSize用來表示,wMaxPacketSize中低11位用來表示最大傳輸長度,對於高速的中斷和等時傳輸類型,wMaxPacketSize中的第12,13位用來表示每幀數據裏額外傳輸事務的數量。

100-105行,通過端點傳輸類型,傳輸最大長度和端口速度來進行匹配,對於全速的中斷傳輸,最大數據長度爲64個字節,如大於64個字節,則不匹配;

108-120行,對於等時傳輸,如端口描述符裏指定的最大傳輸長度大於endpoint裏的最大傳輸長度,那肯定不匹配,在全速時最大數據長度不能超過1023個字節,而額外事務傳輸只有是在高速的情況下才能滿足。

如果當前端口通過上面這些匹配條件,表明當前的endpoint就是所需的端口,接下來進行一些如端口傳輸方向,地址等設置。

運行到目前爲止,device controller ,composite driver, gadget driver都已經成功註冊到系統中,並完成了對複合設備配置,接口和端口添加和配置,表示usb設備準備完成 ,可以開始響應host 端的枚舉請求。

3. 響應host枚舉

host端枚舉過程如下:
a. 當hub檢測到hub狀態寄存器發生變化時,去喚醒hub的守護進程,去查看具體是那 一個port引起的;
b.  如果發現有設備插入,等待100ms使設備穩定後,root hub會向插入設備的port發送reset請求,reset成功後usb設備處於default狀態;
c. 向新插入的設備發送設置地址請求,用來設置設備地址;
d. 獲取usb設備的設備描述符; 
e.根據usb設備的配置個數,獲取對應usb設備配置描述符;

f. 選擇e獲取的配置描述符,選擇合適 的usb配置,對usb設備進行配置;

對於usb device 而言,它不會主動的去和host進行數據傳輸,它都是處於被動的位置,它只是對host請求做出響應,請求都是由host發起。

由圖2可以看到usb設備側對host的請求都是通過中斷進行觸發的, device controller中斷是在控制器初始化過程中申請的,中斷處理函數爲s3c_hsotg_irq,對於host的請求都是從這個函數開始。

[html] view plaincopy
  1. static irqreturn_t s3c_hsotg_irq(int irq, void *pw)  
  2. {  
  3.     struct s3c_hsotg *hsotg = pw;  
  4.     int retry_count = 8;  
  5.     u32 gintsts;  
  6.     u32 gintmsk;  
  7.   
  8. irq_retry:  
  9.     gintsts = readl(hsotg->regs + S3C_GINTSTS);  
  10.     gintmsk = readl(hsotg->regs + S3C_GINTMSK);  
  11.   
  12.     dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",  
  13.         __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);  
  14.   
  15.     gintsts &= gintmsk;  
  16.   
  17.     if (gintsts & S3C_GINTSTS_OTGInt) {  
  18.         u32 otgint = readl(hsotg->regs + S3C_GOTGINT);  
  19.   
  20.         dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);  
  21.   
  22.         writel(otgint, hsotg->regs + S3C_GOTGINT);  
  23.     }  
  24.   
  25.     if (gintsts & S3C_GINTSTS_DisconnInt) {  
  26.         dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__);  
  27.         writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS);  
  28.   
  29.         s3c_hsotg_disconnect_irq(hsotg);  
  30.     }  
  31.   
  32.     if (gintsts & S3C_GINTSTS_SessReqInt) {  
  33.         dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);  
  34.         writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS);  
  35.     }  
  36.   
  37.     if (gintsts & S3C_GINTSTS_EnumDone) {  
  38.         writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);  
  39.   
  40.         s3c_hsotg_irq_enumdone(hsotg);  
  41.     }  
  42.   
  43.     if (gintsts & S3C_GINTSTS_ConIDStsChng) {  
  44.         dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",  
  45.             readl(hsotg->regs + S3C_DSTS),  
  46.             readl(hsotg->regs + S3C_GOTGCTL));  
  47.   
  48.         writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS);  
  49.     }  
  50.   
  51.     if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) {  
  52.         u32 daint = readl(hsotg->regs + S3C_DAINT);  
  53.         u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT;  
  54.         u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT);  
  55.         int ep;  
  56.   
  57.         dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);  
  58.   
  59.         for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) {  
  60.             if (daint_out & 1)  
  61.                 s3c_hsotg_epint(hsotg, ep, 0);  
  62.         }  
  63.   
  64.         for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) {  
  65.             if (daint_in & 1)  
  66.                 s3c_hsotg_epint(hsotg, ep, 1);  
  67.         }  
  68.     }  
  69.   
  70.     if (gintsts & S3C_GINTSTS_USBRst) {  
  71.         dev_info(hsotg->dev, "%s: USBRst\n", __func__);  
  72.         dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",  
  73.             readl(hsotg->regs + S3C_GNPTXSTS));  
  74.   
  75.         writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);  
  76.   
  77.         kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);  
  78.   
  79.         /* it seems after a reset we can end up with a situation  
  80.          * where the TXFIFO still has data in it... the docs  
  81.          * suggest resetting all the fifos, so use the init_fifo  
  82.          * code to relayout and flush the fifos.  
  83.          */  
  84.   
  85.         s3c_hsotg_init_fifo(hsotg);  
  86.   
  87.         s3c_hsotg_enqueue_setup(hsotg);  
  88.     }  
  89.   
  90.     /* check both FIFOs */  
  91.   
  92.     if (gintsts & S3C_GINTSTS_NPTxFEmp) {  
  93.         dev_dbg(hsotg->dev, "NPTxFEmp\n");  
  94.   
  95.         /* Disable the interrupt to stop it happening again  
  96.          * unless one of these endpoint routines decides that  
  97.          * it needs re-enabling */  
  98.   
  99.         s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);  
  100.         s3c_hsotg_irq_fifoempty(hsotg, false);  
  101.     }  
  102.   
  103.     if (gintsts & S3C_GINTSTS_PTxFEmp) {  
  104.         dev_dbg(hsotg->dev, "PTxFEmp\n");  
  105.   
  106.         /* See note in S3C_GINTSTS_NPTxFEmp */  
  107.   
  108.         s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);  
  109.         s3c_hsotg_irq_fifoempty(hsotg, true);  
  110.     }  
  111.   
  112.     if (gintsts & S3C_GINTSTS_RxFLvl) {  
  113.         /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,  
  114.          * we need to retry s3c_hsotg_handle_rx if this is still  
  115.          * set. */  
  116.   
  117.         s3c_hsotg_handle_rx(hsotg);  
  118.     }  
  119.   
  120.     if (gintsts & S3C_GINTSTS_ModeMis) {  
  121.         dev_warn(hsotg->dev, "warning, mode mismatch triggered\n");  
  122.         writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS);  
  123.     }  
  124.   
  125.     if (gintsts & S3C_GINTSTS_USBSusp) {  
  126.         dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n");  
  127.         writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);  
  128.   
  129.         call_gadget(hsotg, suspend);  
  130.     }  
  131.   
  132.     if (gintsts & S3C_GINTSTS_WkUpInt) {  
  133.         dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n");  
  134.         writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS);  
  135.   
  136.         call_gadget(hsotg, resume);  
  137.     }  
  138.   
  139.     if (gintsts & S3C_GINTSTS_ErlySusp) {  
  140.         dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");  
  141.         writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);  
  142.     }  
  143.   
  144.     /* these next two seem to crop-up occasionally causing the core  
  145.      * to shutdown the USB transfer, so try clearing them and logging  
  146.      * the occurrence. */  
  147.   
  148.     if (gintsts & S3C_GINTSTS_GOUTNakEff) {  
  149.         dev_info(hsotg->dev, "GOUTNakEff triggered\n");  
  150.   
  151.         writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);  
  152.   
  153.         s3c_hsotg_dump(hsotg);  
  154.     }  
  155.   
  156.     if (gintsts & S3C_GINTSTS_GINNakEff) {  
  157.         dev_info(hsotg->dev, "GINNakEff triggered\n");  
  158.   
  159.         writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);  
  160.   
  161.         s3c_hsotg_dump(hsotg);  
  162.     }  
  163.   
  164.     /* if we've had fifo events, we should try and go around the  
  165.      * loop again to see if there's any point in returning yet. */  
  166.   
  167.     if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)  
  168.             goto irq_retry;  
  169.   
  170.     return IRQ_HANDLED;  
  171. }  

s3c_hsotg_irq通過讀取中斷狀態寄存器來確定發生什麼中斷,再通過中斷使能寄存器來確定那些中斷那是中斷是合法的,然後清除中斷的狀態位,重新使能中斷,最後根據不同中斷源進行不同處理。

在這裏有兩個類型中斷最爲重要,端口中斷和接收中斷,如果發生了端口中斷,則需要進一步去讀取端口中斷狀態寄存器,來確定產生中斷的端口及產生中斷原因;如果產生了接收中斷,則去FIFO裏讀取數據,如果當前幀接收完成,則會調用註冊request時確定的回調函數通知request請求者;

51-68行,產生了端口中斷,先去設備端口中斷寄存器裏讀取產生中斷端口,設備端口中斷寄存器是一個32位寄存器,高16位對應out的16個端口,bit16對應out endpoint0 ,bit31對應out endpoint 15,而低16位對應in的16個端口,bit0對應in endpoint 0,bit15對應in endpoint15. 在確定產生中斷的端口後,調用s3c_hsotg_epint()分別對out和in中產生中斷的各端口進行處理。

[html] view plaincopy
  1. static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,  
  2.                 int dir_in)  
  3. {  
  4.     struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];  
  5.     u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);  
  6.     u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);  
  7.     u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);  
  8.     u32 ints;  
  9.   
  10.     ints = readl(hsotg->regs + epint_reg);  
  11.   
  12.     /* Clear endpoint interrupts */  
  13.     writel(ints, hsotg->regs + epint_reg);  
  14.   
  15.     dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",  
  16.         __func__, idx, dir_in ? "in" : "out", ints);  
  17.   
  18.     if (ints & DxEPINT_XferCompl) {  
  19.         dev_dbg(hsotg->dev,  
  20.             "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n",  
  21.             __func__, readl(hsotg->regs + epctl_reg),  
  22.             readl(hsotg->regs + epsiz_reg));  
  23.   
  24.         /*  
  25.          * we get OutDone from the FIFO, so we only need to look  
  26.          * at completing IN requests here  
  27.          */  
  28.         if (dir_in) {  
  29.             s3c_hsotg_complete_in(hsotg, hs_ep);  
  30.   
  31.             if (idx == 0 && !hs_ep->req)  
  32.                 s3c_hsotg_enqueue_setup(hsotg);  
  33.         } else if (using_dma(hsotg)) {  
  34.             /*  
  35.              * We're using DMA, we need to fire an OutDone here  
  36.              * as we ignore the RXFIFO.  
  37.              */  
  38.   
  39.             s3c_hsotg_handle_outdone(hsotg, idx, false);  
  40.         }  
  41.     }  
  42.   
  43.     if (ints & DxEPINT_EPDisbld) {  
  44.         dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);  
  45.   
  46.         if (dir_in) {  
  47.             int epctl = readl(hsotg->regs + epctl_reg);  
  48.   
  49.             s3c_hsotg_txfifo_flush(hsotg, idx);  
  50.   
  51.             if ((epctl & DxEPCTL_Stall) &&  
  52.                 (epctl & DxEPCTL_EPType_Bulk)) {  
  53.                 int dctl = readl(hsotg->regs + DCTL);  
  54.   
  55.                 dctl |= DCTL_CGNPInNAK;  
  56.                 writel(dctl, hsotg->regs + DCTL);  
  57.             }  
  58.         }  
  59.     }  
  60.   
  61.     if (ints & DxEPINT_AHBErr)  
  62.         dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);  
  63.   
  64.     if (ints & DxEPINT_Setup) {  /* Setup or Timeout */  
  65.         dev_dbg(hsotg->dev, "%s: Setup/Timeout\n",  __func__);  
  66.   
  67.         if (using_dma(hsotg) && idx == 0) {  
  68.             /*  
  69.              * this is the notification we've received a  
  70.              * setup packet. In non-DMA mode we'd get this  
  71.              * from the RXFIFO, instead we need to process  
  72.              * the setup here.  
  73.              */  
  74.   
  75.             if (dir_in)  
  76.                 WARN_ON_ONCE(1);  
  77.             else  
  78.                 s3c_hsotg_handle_outdone(hsotg, 0, true);  
  79.         }  
  80.     }  
  81.   
  82.     if (ints & DxEPINT_Back2BackSetup)  
  83.         dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);  
  84.   
  85.     if (dir_in) {  
  86.         /* not sure if this is important, but we'll clear it anyway */  
  87.         if (ints & DIEPMSK_INTknTXFEmpMsk) {  
  88.             dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",  
  89.                 __func__, idx);  
  90.         }  
  91.   
  92.         /* this probably means something bad is happening */  
  93.         if (ints & DIEPMSK_INTknEPMisMsk) {  
  94.             dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",  
  95.                  __func__, idx);  
  96.         }  
  97.   
  98.         /* FIFO has space or is empty (see GAHBCFG) */  
  99.         if (hsotg->dedicated_fifos &&  
  100.             ints & DIEPMSK_TxFIFOEmpty) {  
  101.             dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",  
  102.                 __func__, idx);  
  103.             if (!using_dma(hsotg))  
  104.                 s3c_hsotg_trytx(hsotg, hs_ep);  
  105.         }  
  106.     }  
  107. }  
s3c_hsotg_epint會根據產生中斷的不同方向和中斷類型做出不同處理。

18-41行,表示端口產生了傳輸完成中斷,它即可對應輸入in類型,也可以對應輸出out類型。如裏是輸入類型傳輸完成中斷,即完成device->host傳輸,則會調用s3c_hsotg_complete_in對發送長度等信息進行統計,如需要發送0長數據做爲發送結束,則向host傳輸0長度數據幀,如已發送數據長度,少於期望長度則繼續開始發送請求,否則調用request的回調函數通知上層;對於out類型傳輸,即對應接收中斷,usb設備會專門產生接收中斷,它不在這裏處理。

64-80表示,表示端口產生setup傳輸完成或超時中斷。

回到s3c_hsotg_irq 的112-118行,這裏表示RXFIFO非空,有數據需要讀取,通過s3c_hsotg_handle_rx去處理。

[html] view plaincopy
  1. static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)  
  2. {  
  3.     u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);  
  4.     u32 epnum, status, size;  
  5.   
  6.     WARN_ON(using_dma(hsotg));  
  7.   
  8.     epnum = grxstsr & S3C_GRXSTS_EPNum_MASK;  
  9.     status = grxstsr & S3C_GRXSTS_PktSts_MASK;  
  10.   
  11.     size = grxstsr & S3C_GRXSTS_ByteCnt_MASK;  
  12.     size >>= S3C_GRXSTS_ByteCnt_SHIFT;  
  13.   
  14.     if (1)  
  15.         dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",  
  16.             __func__, grxstsr, size, epnum);  
  17.   
  18. #define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT)  
  19.   
  20.     switch (status >> S3C_GRXSTS_PktSts_SHIFT) {  
  21.     case __status(S3C_GRXSTS_PktSts_GlobalOutNAK):  
  22.         dev_dbg(hsotg->dev, "GlobalOutNAK\n");  
  23.         break;  
  24.   
  25.     case __status(S3C_GRXSTS_PktSts_OutDone):  
  26.         dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",  
  27.             s3c_hsotg_read_frameno(hsotg));  
  28.   
  29.         if (!using_dma(hsotg))  
  30.             s3c_hsotg_handle_outdone(hsotg, epnum, false);  
  31.         break;  
  32.   
  33.     case __status(S3C_GRXSTS_PktSts_SetupDone):  
  34.         dev_dbg(hsotg->dev,  
  35.             "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",  
  36.             s3c_hsotg_read_frameno(hsotg),  
  37.             readl(hsotg->regs + S3C_DOEPCTL(0)));  
  38.   
  39.         s3c_hsotg_handle_outdone(hsotg, epnum, true);  
  40.         break;  
  41.   
  42.     case __status(S3C_GRXSTS_PktSts_OutRX):  
  43.         s3c_hsotg_rx_data(hsotg, epnum, size);  
  44.         break;  
  45.   
  46.     case __status(S3C_GRXSTS_PktSts_SetupRX):  
  47.         dev_dbg(hsotg->dev,  
  48.             "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",  
  49.             s3c_hsotg_read_frameno(hsotg),  
  50.             readl(hsotg->regs + S3C_DOEPCTL(0)));  
  51.   
  52.         s3c_hsotg_rx_data(hsotg, epnum, size);  
  53.         break;  
  54.   
  55.     default:  
  56.         dev_warn(hsotg->dev, "%s: unknown status %08x\n",  
  57.              __func__, grxstsr);  
  58.   
  59.         s3c_hsotg_dump(hsotg);  
  60.         break;  
  61.     }  
  62. }  
當RXFIFO中數據不爲空時,表示有接收到數據,需要進行處理,s3c_hsotg_handle_rx,它會先確定產生中斷的endpoint及數據包狀態,然後再根據不同的狀態做處不同處理。

08-18行,用來確定產生中斷的endpoint端口號和接收到數據長度及數據包狀態,共有5種數據包狀態:OUT NAK, 收到OUT數據包,OUT數據包傳輸完成(設備側接收完成),SETUP包傳輸完成,收到SETUP數據包;

21-23行,out nak中斷,表示接收者不能接收數據;

不管是正常數據包還是SETUP包,收到數據都是通過s3c_hsotg_rx_data從FIFO讀取數據,而如果當前的數據幀接收完成,則會通過s3c_hsotg_handle_outdone函數調用s3c_hsotg_complete_request來通知上層;

[html] view plaincopy
  1. static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,  
  2.                        struct s3c_hsotg_ep *hs_ep,  
  3.                        struct s3c_hsotg_req *hs_req,  
  4.                        int result)  
  5. {  
  6.     bool restart;  
  7.   
  8.     if (!hs_req) {  
  9.         dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__);  
  10.         return;  
  11.     }  
  12.   
  13.     dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n",  
  14.         hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete);  
  15.   
  16.     /*  
  17.      * only replace the status if we've not already set an error  
  18.      * from a previous transaction  
  19.      */  
  20.   
  21.     if (hs_req->req.status == -EINPROGRESS)  
  22.         hs_req->req.status = result;  
  23.   
  24.     hs_ep->req = NULL;  
  25.     list_del_init(&hs_req->queue);  
  26.   
  27.     if (using_dma(hsotg))  
  28.         s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req);  
  29.   
  30.     /*  
  31.      * call the complete request with the locks off, just in case the  
  32.      * request tries to queue more work for this endpoint.  
  33.      */  
  34.   
  35.     if (hs_req->req.complete) {  
  36.         spin_unlock(&hsotg->lock);  
  37.         hs_req->req.complete(&hs_ep->ep, &hs_req->req);  
  38.         spin_lock(&hsotg->lock);  
  39.     }  
  40.   
  41.     /*  
  42.      * Look to see if there is anything else to do. Note, the completion  
  43.      * of the previous request may have caused a new request to be started  
  44.      * so be careful when doing this.  
  45.      */  
  46.   
  47.     if (!hs_ep->req && result >= 0) {  
  48.         restart = !list_empty(&hs_ep->queue);  
  49.         if (restart) {  
  50.             hs_req = get_ep_head(hs_ep);  
  51.             s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false);  
  52.         }  
  53.     }  
  54. }  

s3c_hsotg_complete_request首先會把req本身從endpoint的request隊列裏刪除,然後再調用request的回調函數req->complete通知request請求者,在這裏對應的回調函數爲s3c_hsotg_complete_setup,最後會根據result的值來確定是否繼續開始當前endpoint的其它request;

[html] view plaincopy
  1. static void s3c_hsotg_complete_setup(struct usb_ep *ep,  
  2.                      struct usb_request *req)  
  3. {  
  4.     struct s3c_hsotg_ep *hs_ep = our_ep(ep);  
  5.     struct s3c_hsotg *hsotg = hs_ep->parent;  
  6.   
  7.     if (req->status < 0) {  
  8.         dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status);  
  9.         return;  
  10.     }  
  11.   
  12.     if (req->actual == 0)  
  13.         s3c_hsotg_enqueue_setup(hsotg);  
  14.     else  
  15.         s3c_hsotg_process_control(hsotg, req->buf);  
  16. }  
s3c_hsotg_complete_setup它會調用s3c_hsotg_process_control對來自host的請求做出相應的處理;

[html] view plaincopy
  1. static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,  
  2.                       struct usb_ctrlrequest *ctrl)  
  3. {  
  4.     struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];  
  5.     int ret = 0;  
  6.     u32 dcfg;  
  7.   
  8.     ep0->sent_zlp = 0;  
  9.   
  10.     dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n",  
  11.          ctrl->bRequest, ctrl->bRequestType,  
  12.          ctrl->wValue, ctrl->wLength);  
  13.   
  14.     /*  
  15.      * record the direction of the request, for later use when enquing  
  16.      * packets onto EP0.  
  17.      */  
  18.   
  19.     ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;  
  20.     dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);  
  21.   
  22.     /*  
  23.      * if we've no data with this request, then the last part of the  
  24.      * transaction is going to implicitly be IN.  
  25.      */  
  26.     if (ctrl->wLength == 0)  
  27.         ep0->dir_in = 1;  
  28.   
  29.     if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {  
  30.         switch (ctrl->bRequest) {  
  31.         case USB_REQ_SET_ADDRESS:  
  32.             dcfg = readl(hsotg->regs + DCFG);  
  33.             dcfg &= ~DCFG_DevAddr_MASK;  
  34.             dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT;  
  35.             writel(dcfg, hsotg->regs + DCFG);  
  36.   
  37.             dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);  
  38.   
  39.             ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);  
  40.             return;  
  41.   
  42.         case USB_REQ_GET_STATUS:  
  43.             ret = s3c_hsotg_process_req_status(hsotg, ctrl);  
  44.             break;  
  45.   
  46.         case USB_REQ_CLEAR_FEATURE:  
  47.         case USB_REQ_SET_FEATURE:  
  48.             ret = s3c_hsotg_process_req_feature(hsotg, ctrl);  
  49.             break;  
  50.         }  
  51.     }  
  52.   
  53.     /* as a fallback, try delivering it to the driver to deal with */  
  54.   
  55.     if (ret == 0 && hsotg->driver) {  
  56.         ret = hsotg->driver->setup(&hsotg->gadget, ctrl);  
  57.         if (ret < 0)  
  58.             dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);  
  59.     }  
  60.   
  61.     /*  
  62.      * the request is either unhandlable, or is not formatted correctly  
  63.      * so respond with a STALL for the status stage to indicate failure.  
  64.      */  
  65.   
  66.     if (ret < 0) {  
  67.         u32 reg;  
  68.         u32 ctrl;  
  69.   
  70.         dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);  
  71.         reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;  
  72.   
  73.         /*  
  74.          * DxEPCTL_Stall will be cleared by EP once it has  
  75.          * taken effect, so no need to clear later.  
  76.          */  
  77.   
  78.         ctrl = readl(hsotg->regs + reg);  
  79.         ctrl |= DxEPCTL_Stall;  
  80.         ctrl |= DxEPCTL_CNAK;  
  81.         writel(ctrl, hsotg->regs + reg);  
  82.   
  83.         dev_dbg(hsotg->dev,  
  84.             "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",  
  85.             ctrl, reg, readl(hsotg->regs + reg));  
  86.   
  87.         /*  
  88.          * don't believe we need to anything more to get the EP  
  89.          * to reply with a STALL packet  
  90.          */  
  91.     }  
  92. }  
s3c_hsotg_process_control實現了一些和低層usb device controller相關的操作,如枚舉時的設置地址請求,就是從這裏開始的。

31-41行,對應USB枚舉過程中的設備地址請求,在收到HOST的設備地址請求後,根據地址值會配置相應的地址寄存器,並通過s3c_hsotg_send_reply向HOST回覆一個0長度的數據幀表示控制傳輸中的status傳輸。

42-44行,表示host請求獲取設備,接口和端口狀態,在收到請求後通過s3c_hsotg_send_reply回覆host請求的狀態;

47-49行,表示設置或清除設備的DEVICE_REMOTE_WAKEUP,端口的ENDPOINT_HALT等特徵,這裏實現了端口endpoint_halt設置和清除功能,在設置或清除後,向HOST回覆0長度的數據幀。

55-59行,如果host發送了獲取設備描述符,設置配置等和usb功能相關的請求,這些請求是和設備的功能相關,但和具體硬件無關,它一般在gadget driver裏實現,這裏會調用gadget driver 中的composite_setup函數,它實現了除和硬件相關之外的其它usb請求。

[html] view plaincopy
  1. static int  
  2. composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  
  3. {  
  4.     struct usb_composite_dev    *cdev = get_gadget_data(gadget);  
  5.     struct usb_request      *req = cdev->req;  
  6.     int             value = -EOPNOTSUPP;  
  7.     int             status = 0;  
  8.     u16             w_index = le16_to_cpu(ctrl->wIndex);  
  9.     u8              intf = w_index & 0xFF;  
  10.     u16             w_value = le16_to_cpu(ctrl->wValue);  
  11.     u16             w_length = le16_to_cpu(ctrl->wLength);  
  12.     struct usb_function     *f = NULL;  
  13.     u8              endp;  
  14.   
  15.     /* partial re-init of the response message; the function or the  
  16.      * gadget might need to intercept e.g. a control-OUT completion  
  17.      * when we delegate to it.  
  18.      */  
  19.     req->zero = 0;  
  20.     req->complete = composite_setup_complete;  
  21.     req->length = 0;  
  22.     gadget->ep0->driver_data = cdev;  
  23.   
  24.     switch (ctrl->bRequest) {  
  25.   
  26.     /* we handle all standard USB descriptors */  
  27.     case USB_REQ_GET_DESCRIPTOR:  
  28.         if (ctrl->bRequestType != USB_DIR_IN)  
  29.             goto unknown;  
  30.         switch (w_value >> 8) {  
  31.   
  32.         case USB_DT_DEVICE:  
  33.             cdev->desc.bNumConfigurations =  
  34.                 count_configs(cdev, USB_DT_DEVICE);  
  35.             cdev->desc.bMaxPacketSize0 =  
  36.                 cdev->gadget->ep0->maxpacket;  
  37.             if (gadget_is_superspeed(gadget)) {  
  38.                 if (gadget->speed >= USB_SPEED_SUPER) {  
  39.                     cdev->desc.bcdUSB = cpu_to_le16(0x0300);  
  40.                     cdev->desc.bMaxPacketSize0 = 9;  
  41.                 } else {  
  42.                     cdev->desc.bcdUSB = cpu_to_le16(0x0210);  
  43.                 }  
  44.             }  
  45.   
  46.             value = min(w_length, (u16) sizeof cdev->desc);  
  47.             memcpy(req->buf, &cdev->desc, value);  
  48.             break;  
  49.         case USB_DT_DEVICE_QUALIFIER:  
  50.             if (!gadget_is_dualspeed(gadget) ||  
  51.                 gadget->speed >= USB_SPEED_SUPER)  
  52.                 break;  
  53.             device_qual(cdev);  
  54.             value = min_t(int, w_length,  
  55.                 sizeof(struct usb_qualifier_descriptor));  
  56.             break;  
  57.         case USB_DT_OTHER_SPEED_CONFIG:  
  58.             if (!gadget_is_dualspeed(gadget) ||  
  59.                 gadget->speed >= USB_SPEED_SUPER)  
  60.                 break;  
  61.             /* FALLTHROUGH */  
  62.         case USB_DT_CONFIG:  
  63.             value = config_desc(cdev, w_value);  
  64.             if (value >= 0)  
  65.                 value = min(w_length, (u16) value);  
  66.             break;  
  67.         case USB_DT_STRING:  
  68.             value = get_string(cdev, req->buf,  
  69.                     w_index, w_value & 0xff);  
  70.             if (value >= 0)  
  71.                 value = min(w_length, (u16) value);  
  72.             break;  
  73.         case USB_DT_BOS:  
  74.             if (gadget_is_superspeed(gadget)) {  
  75.                 value = bos_desc(cdev);  
  76.                 value = min(w_length, (u16) value);  
  77.             }  
  78.             break;  
  79.         }  
  80.         break;  
  81.   
  82.     /* any number of configs can work */  
  83.     case USB_REQ_SET_CONFIGURATION:  
  84.         if (ctrl->bRequestType != 0)  
  85.             goto unknown;  
  86.         if (gadget_is_otg(gadget)) {  
  87.             if (gadget->a_hnp_support)  
  88.                 DBG(cdev, "HNP available\n");  
  89.             else if (gadget->a_alt_hnp_support)  
  90.                 DBG(cdev, "HNP on another port\n");  
  91.             else  
  92.                 VDBG(cdev, "HNP inactive\n");  
  93.         }  
  94.         spin_lock(&cdev->lock);  
  95.         value = set_config(cdev, ctrl, w_value);  
  96.         spin_unlock(&cdev->lock);  
  97.         break;  
  98.     case USB_REQ_GET_CONFIGURATION:  
  99.         if (ctrl->bRequestType != USB_DIR_IN)  
  100.             goto unknown;  
  101.         if (cdev->config)  
  102.             *(u8 *)req->buf = cdev->config->bConfigurationValue;  
  103.         else  
  104.             *(u8 *)req->buf = 0;  
  105.         value = min(w_length, (u16) 1);  
  106.         break;  
  107.   
  108.     /* function drivers must handle get/set altsetting; if there's  
  109.      * no get() method, we know only altsetting zero works.  
  110.      */  
  111.     case USB_REQ_SET_INTERFACE:  
  112.         if (ctrl->bRequestType != USB_RECIP_INTERFACE)  
  113.             goto unknown;  
  114.         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)  
  115.             break;  
  116.         f = cdev->config->interface[intf];  
  117.         if (!f)  
  118.             break;  
  119.         if (w_value && !f->set_alt)  
  120.             break;  
  121.         value = f->set_alt(f, w_index, w_value);  
  122.         if (value == USB_GADGET_DELAYED_STATUS) {  
  123.             DBG(cdev,  
  124.              "%s: interface %d (%s) requested delayed status\n",  
  125.                     __func__, intf, f->name);  
  126.             cdev->delayed_status++;  
  127.             DBG(cdev, "delayed_status count %d\n",  
  128.                     cdev->delayed_status);  
  129.         }  
  130.         break;  
  131.     case USB_REQ_GET_INTERFACE:  
  132.         if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))  
  133.             goto unknown;  
  134.         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)  
  135.             break;  
  136.         f = cdev->config->interface[intf];  
  137.         if (!f)  
  138.             break;  
  139.         /* lots of interfaces only need altsetting zero... */  
  140.         value = f->get_alt ? f->get_alt(f, w_index) : 0;  
  141.         if (value < 0)  
  142.             break;  
  143.         *((u8 *)req->buf) = value;  
  144.         value = min(w_length, (u16) 1);  
  145.         break;  
  146.   
  147.     /*  
  148.      * USB 3.0 additions:  
  149.      * Function driver should handle get_status request. If such cb  
  150.      * wasn't supplied we respond with default value = 0  
  151.      * Note: function driver should supply such cb only for the first  
  152.      * interface of the function  
  153.      */  
  154.     case USB_REQ_GET_STATUS:  
  155.         if (!gadget_is_superspeed(gadget))  
  156.             goto unknown;  
  157.         if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))  
  158.             goto unknown;  
  159.         value = 2;  /* This is the length of the get_status reply */  
  160.         put_unaligned_le16(0, req->buf);  
  161.         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)  
  162.             break;  
  163.         f = cdev->config->interface[intf];  
  164.         if (!f)  
  165.             break;  
  166.         status = f->get_status ? f->get_status(f) : 0;  
  167.         if (status < 0)  
  168.             break;  
  169.         put_unaligned_le16(status & 0x0000ffff, req->buf);  
  170.         break;  
  171.     /*  
  172.      * Function drivers should handle SetFeature/ClearFeature  
  173.      * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied  
  174.      * only for the first interface of the function  
  175.      */  
  176.     case USB_REQ_CLEAR_FEATURE:  
  177.     case USB_REQ_SET_FEATURE:  
  178.         if (!gadget_is_superspeed(gadget))  
  179.             goto unknown;  
  180.         if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))  
  181.             goto unknown;  
  182.         switch (w_value) {  
  183.         case USB_INTRF_FUNC_SUSPEND:  
  184.             if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)  
  185.                 break;  
  186.             f = cdev->config->interface[intf];  
  187.             if (!f)  
  188.                 break;  
  189.             value = 0;  
  190.             if (f->func_suspend)  
  191.                 value = f->func_suspend(f, w_index >> 8);  
  192.             if (value < 0) {  
  193.                 ERROR(cdev,  
  194.                       "func_suspend() returned error %d\n",  
  195.                       value);  
  196.                 value = 0;  
  197.             }  
  198.             break;  
  199.         }  
  200.         break;  
  201.     default:  
  202. unknown:  
  203.         VDBG(cdev,  
  204.             "non-core control req%02x.%02x v%04x i%04x l%d\n",  
  205.             ctrl->bRequestType, ctrl->bRequest,  
  206.             w_value, w_index, w_length);  
  207.   
  208.         /* functions always handle their interfaces and endpoints...  
  209.          * punt other recipients (other, WUSB, ...) to the current  
  210.          * configuration code.  
  211.          *  
  212.          * REVISIT it could make sense to let the composite device  
  213.          * take such requests too, if that's ever needed:  to work  
  214.          * in config 0, etc.  
  215.          */  
  216.         switch (ctrl->bRequestType & USB_RECIP_MASK) {  
  217.         case USB_RECIP_INTERFACE:  
  218.             if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)  
  219.                 break;  
  220.             f = cdev->config->interface[intf];  
  221.             break;  
  222.   
  223.         case USB_RECIP_ENDPOINT:  
  224.             endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);  
  225.             list_for_each_entry(f, &cdev->config->functions, list) {  
  226.                 if (test_bit(endp, f->endpoints))  
  227.                     break;  
  228.             }  
  229.             if (&f->list == &cdev->config->functions)  
  230.                 f = NULL;  
  231.             break;  
  232.         }  
  233.   
  234.         if (f && f->setup)  
  235.             value = f->setup(f, ctrl);  
  236.         else {  
  237.             struct usb_configuration    *c;  
  238.   
  239.             c = cdev->config;  
  240.             if (c && c->setup)  
  241.                 value = c->setup(c, ctrl);  
  242.         }  
  243.   
  244.         goto done;  
  245.     }  
  246.   
  247.     /* respond with data transfer before status phase? */  
  248.     if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {  
  249.         req->length = value;  
  250.         req->zero = value < w_length;  
  251.         value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);  
  252.         if (value < 0) {  
  253.             DBG(cdev, "ep_queue --> %d\n", value);  
  254.             req->status = 0;  
  255.             composite_setup_complete(gadget->ep0, req);  
  256.         }  
  257.     } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {  
  258.         WARN(cdev,  
  259.             "%s: Delayed status not supported for w_length != 0",  
  260.             __func__);  
  261.     }  
  262.   
  263. done:  
  264.     /* device either stalls (value < 0) or reports success */  
  265.     return value;  
  266. }  

composite_setup會根據host的不同請求做出不同處理,這裏主要包含獲取設備,配置及字符串描述符請求、設置和獲取usb配置請求、設備和獲取usb接口請求、獲取usb狀態請求、設置和清除usb feature請求。

19-22行,初始化用於傳輸設備描述符等信息的request結構;

32-48表示獲取設備描述符請求,將保存於composite_dev裏的device desc拷貝到用來存放request發送數據的buf裏。

57-61表示用來獲取配置描述符請求,一個USB設備它有可能有多個配置,在枚舉的時候,HOST端會遍歷每個配置,獲取相應的配置描述符。對於獲取配置描述符這個請求,device端不僅僅會將配置描述符拷貝到用於存放request數據的buf裏, 還會把這個配置裏的接口,再對應接口裏的端口描述符一起拷貝到有buf裏,所以在host發送獲取配置描述符後,它就得到了這個配置下面的接口和端口信息,如果它是OTG設備,它還會包含OTG的信息。

67-72,它用來獲取USB設備的字符串描述符。

83-97表示收到設置配置請求,它會調用set_config函數去設置USB配置。

[html] view plaincopy
  1. static int set_config(struct usb_composite_dev *cdev,  
  2.         const struct usb_ctrlrequest *ctrl, unsigned number)  
  3. {  
  4.     struct usb_gadget   *gadget = cdev->gadget;  
  5.     struct usb_configuration *c = NULL;  
  6.     int         result = -EINVAL;  
  7.     unsigned        power = gadget_is_otg(gadget) ? 8 : 100;  
  8.     int         tmp;  
  9.   
  10.     if (number) {  
  11.         list_for_each_entry(c, &cdev->configs, list) {  
  12.             if (c->bConfigurationValue == number) {  
  13.                 /*  
  14.                  * We disable the FDs of the previous  
  15.                  * configuration only if the new configuration  
  16.                  * is a valid one  
  17.                  */  
  18.                 if (cdev->config)  
  19.                     reset_config(cdev);  
  20.                 result = 0;  
  21.                 break;  
  22.             }  
  23.         }  
  24.         if (result < 0)  
  25.             goto done;  
  26.     } else { /* Zero configuration value - need to reset the config */  
  27.         if (cdev->config)  
  28.             reset_config(cdev);  
  29.         result = 0;  
  30.     }  
  31.   
  32.     INFO(cdev, "%s speed config #%d: %s\n",  
  33.         ({ char *speed;  
  34.         switch (gadget->speed) {  
  35.         case USB_SPEED_LOW:  
  36.             speed = "low";  
  37.             break;  
  38.         case USB_SPEED_FULL:  
  39.             speed = "full";  
  40.             break;  
  41.         case USB_SPEED_HIGH:  
  42.             speed = "high";  
  43.             break;  
  44.         case USB_SPEED_SUPER:  
  45.             speed = "super";  
  46.             break;  
  47.         default:  
  48.             speed = "?";  
  49.             break;  
  50.         } ; speed; }), number, c ? c->label : "unconfigured");  
  51.   
  52.     if (!c)  
  53.         goto done;  
  54.   
  55.     cdev->config = c;  
  56.   
  57.     /* Initialize all interfaces by setting them to altsetting zero. */  
  58.     for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {  
  59.         struct usb_function *f = c->interface[tmp];  
  60.         struct usb_descriptor_header **descriptors;  
  61.   
  62.         if (!f)  
  63.             break;  
  64.   
  65.         /*  
  66.          * Record which endpoints are used by the function. This is used  
  67.          * to dispatch control requests targeted at that endpoint to the  
  68.          * function's setup callback instead of the current  
  69.          * configuration's setup callback.  
  70.          */  
  71.         switch (gadget->speed) {  
  72.         case USB_SPEED_SUPER:  
  73.             descriptors = f->ss_descriptors;  
  74.             break;  
  75.         case USB_SPEED_HIGH:  
  76.             descriptors = f->hs_descriptors;  
  77.             break;  
  78.         default:  
  79.             descriptors = f->descriptors;  
  80.         }  
  81.   
  82.         for (; *descriptors; ++descriptors) {  
  83.             struct usb_endpoint_descriptor *ep;  
  84.             int addr;  
  85.   
  86.             if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)  
  87.                 continue;  
  88.   
  89.             ep = (struct usb_endpoint_descriptor *)*descriptors;  
  90.             addr = ((ep->bEndpointAddress & 0x80) >> 3)  
  91.                  |  (ep->bEndpointAddress & 0x0f);  
  92.             set_bit(addr, f->endpoints);  
  93.         }  
  94.   
  95.         result = f->set_alt(f, tmp, 0);  
  96.         if (result < 0) {  
  97.             DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",  
  98.                     tmp, f->name, f, result);  
  99.   
  100.             reset_config(cdev);  
  101.             goto done;  
  102.         }  
  103.   
  104.         if (result == USB_GADGET_DELAYED_STATUS) {  
  105.             DBG(cdev,  
  106.              "%s: interface %d (%s) requested delayed status\n",  
  107.                     __func__, tmp, f->name);  
  108.             cdev->delayed_status++;  
  109.             DBG(cdev, "delayed_status count %d\n",  
  110.                     cdev->delayed_status);  
  111.         }  
  112.     }  
  113.   
  114.     /* when we return, be sure our power usage is valid */  
  115.     power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;  
  116. done:  
  117.     usb_gadget_vbus_draw(gadget, power);  
  118.     if (result >= 0 && cdev->delayed_status)  
  119.         result = USB_GADGET_DELAYED_STATUS;  
  120.     return result;  
  121. }  

對於一個複合型USB設備, 它的當前配置保存在cdev->config裏,在設置設備的配置時,它會根據配置的值先將與配置值相對應的配置初始化,然後將所需的配置保存到cdev->config裏,一個配置裏包含多個接口,一個接口下包含多個接口設置,一個接口設置裏包含多個端口,在把指定配置保存到cdev->config後,調用usb配置中的set_alt函數將接口下的接口設置設置成0,這裏通過sourcesink_set_alt來說明,set_alt的具體工作。

[html] view plaincopy
  1. static int sourcesink_set_alt(struct usb_function *f,  
  2.         unsigned intf, unsigned alt)  
  3. {  
  4.     struct f_sourcesink     *ss = func_to_ss(f);  
  5.     struct usb_composite_dev    *cdev = f->config->cdev;  
  6.   
  7.     if (ss->in_ep->driver_data)  
  8.         disable_source_sink(ss);  
  9.     return enable_source_sink(cdev, ss, alt);  
  10. }  

sourcesink_set_alt中有三個參數,一個是接口功能usb_function,

通過配置得到f_sourcesink和cdev ,然後判斷端口中driver_data是不是已經賦值,如果已經賦值則把相應的端口disable,最後調用enable_source_sink函數;

[html] view plaincopy
  1. static int  
  2. enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)  
  3. {  
  4.     int                 result = 0;  
  5.     struct usb_ep               *ep;  
  6.   
  7.     /* one endpoint writes (sources) zeroes IN (to the host) */  
  8.     ep = ss->in_ep;  
  9.     result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);  
  10.     if (result)  
  11.         return result;  
  12.     result = usb_ep_enable(ep);  
  13.     if (result < 0)  
  14.         return result;  
  15.     ep->driver_data = ss;  
  16.   
  17.     result = source_sink_start_ep(ss, true);  
  18.     if (result < 0) {  
  19. fail:  
  20.         ep = ss->in_ep;  
  21.         usb_ep_disable(ep);  
  22.         ep->driver_data = NULL;  
  23.         return result;  
  24.     }  
  25.   
  26.     /* one endpoint reads (sinks) anything OUT (from the host) */  
  27.     ep = ss->out_ep;  
  28.     result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);  
  29.     if (result)  
  30.         goto fail;  
  31.     result = usb_ep_enable(ep);  
  32.     if (result < 0)  
  33.         goto fail;  
  34.     ep->driver_data = ss;  
  35.   
  36.     result = source_sink_start_ep(ss, false);  
  37.     if (result < 0) {  
  38.         usb_ep_disable(ep);  
  39.         ep->driver_data = NULL;  
  40.         goto fail;  
  41.     }  
  42.   
  43.     DBG(cdev, "%s enabled\n", ss->function.name);  
  44.     return result;  
  45. }  

usb接口功能usb_function數據結構中有專門用來保存不同速度情況下接口和端口描述符頭指針數組,descriptors用來存放全速描述符頭指針,hs_descriptors用來存放高速描述符頭指針,ss_descriptors用來存放超速描述符頭指針,雖然usb端口可以在不同速度下工作,但是對於一個gadget device它的速度是固定的, 所以對一個USB端口進行配置時要根據gadget的速度來確定端口,在10-13行中,enable_source_sink會根據gadget所支持的速度來完成usb_ep配置。

[html] view plaincopy
  1. int config_ep_by_speed(struct usb_gadget *g,  
  2.             struct usb_function *f,  
  3.             struct usb_ep *_ep)  
  4. {  
  5.     struct usb_endpoint_descriptor *chosen_desc = NULL;  
  6.     struct usb_descriptor_header **speed_desc = NULL;  
  7.   
  8.     struct usb_ss_ep_comp_descriptor *comp_desc = NULL;  
  9.     int want_comp_desc = 0;  
  10.   
  11.     struct usb_descriptor_header **d_spd; /* cursor for speed desc */  
  12.   
  13.     if (!g || !f || !_ep)  
  14.         return -EIO;  
  15.   
  16.     /* select desired speed */  
  17.     switch (g->speed) {  
  18.     case USB_SPEED_SUPER:  
  19.         if (gadget_is_superspeed(g)) {  
  20.             speed_desc = f->ss_descriptors;  
  21.             want_comp_desc = 1;  
  22.             break;  
  23.         }  
  24.         /* else: Fall trough */  
  25.     case USB_SPEED_HIGH:  
  26.         if (gadget_is_dualspeed(g)) {  
  27.             speed_desc = f->hs_descriptors;  
  28.             break;  
  29.         }  
  30.         /* else: fall through */  
  31.     default:  
  32.         speed_desc = f->descriptors;  
  33.     }  
  34.     /* find descriptors */  
  35.     for_each_ep_desc(speed_desc, d_spd) {  
  36.         chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;  
  37.         if (chosen_desc->bEndpointAddress == _ep->address)  
  38.             goto ep_found;  
  39.     }  
  40.     return -EIO;  
  41.   
  42. ep_found:  
  43.     /* commit results */  
  44.     _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);  
  45.     _ep->desc = chosen_desc;  
  46.     _ep->comp_desc = NULL;  
  47.     _ep->maxburst = 0;  
  48.     _ep->mult = 0;  
  49.     if (!want_comp_desc)  
  50.         return 0;  
  51.   
  52.     /*  
  53.      * Companion descriptor should follow EP descriptor  
  54.      * USB 3.0 spec, #9.6.7  
  55.      */  
  56.     comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);  
  57.     if (!comp_desc ||  
  58.         (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))  
  59.         return -EIO;  
  60.     _ep->comp_desc = comp_desc;  
  61.     if (g->speed == USB_SPEED_SUPER) {  
  62.         switch (usb_endpoint_type(_ep->desc)) {  
  63.         case USB_ENDPOINT_XFER_BULK:  
  64.         case USB_ENDPOINT_XFER_INT:  
  65.             _ep->maxburst = comp_desc->bMaxBurst;  
  66.             break;  
  67.         case USB_ENDPOINT_XFER_ISOC:  
  68.             /* mult: bits 1:0 of bmAttributes */  
  69.             _ep->mult = comp_desc->bmAttributes & 0x3;  
  70.             break;  
  71.         default:  
  72.             /* Do nothing for control endpoints */  
  73.             break;  
  74.         }  
  75.     }  
  76.     return 0;  
  77. }  

17-33行,根據gadget的速度來獲取端口描述符頭指針,並保存在chose_desc裏;

35-39行,從端口描述符頭指針裏獲取端口描述符,並於給定的ep的地址比較,如果相同,表示找到相應端口,找到端口後補全usb_ep結構中的最大傳輸長度和端口描述符,如果是超速USB設備,則還需要補全用於描述高速端口的描述符。

由config_ep_by_speed找到相匹配的端口後,通過usb_ep_enable使能端口,usb_ep_enable裏調用了和硬件相關的usb_ep_ops中的enable函數,這裏是s3c_hsotg_ep_enable,接着賦值ep的driver_data.

在使能端口後,就要爲這個端口申請用於request的資源,回調函數,並將request加入到端口的請求隊列裏,這個工作由38行的source_sink_start_ep完成。

[html] view plaincopy
  1. static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)  
  2. {  
  3.     struct usb_ep       *ep;  
  4.     struct usb_request  *req;  
  5.     int         status;  
  6.   
  7.     ep = is_in ? ss->in_ep : ss->out_ep;  
  8.     req = alloc_ep_req(ep);  
  9.     if (!req)  
  10.         return -ENOMEM;  
  11.   
  12.     req->complete = source_sink_complete;  
  13.     if (is_in)  
  14.         reinit_write_data(ep, req);  
  15.     else  
  16.         memset(req->buf, 0x55, req->length);  
  17.   
  18.     status = usb_ep_queue(ep, req, GFP_ATOMIC);  
  19.     if (status) {  
  20.         struct usb_composite_dev    *cdev;  
  21.   
  22.         cdev = ss->function.config->cdev;  
  23.         ERROR(cdev, "start %s %s --> %d\n",  
  24.                 is_in ? "IN" : "OUT",  
  25.                 ep->name, status);  
  26.         free_ep_req(ep, req);  
  27.     }  
  28.   
  29.     return status;  
  30. }  
08行,調用alloc_ep_req爲endpoint申請request請求數據結構,併爲request分配用於存放傳輸數據的buf。

12行,將request的回調函數賦值給req->complete,當這個端口傳輸完成後通過這個回調函數來通知上層,實現source_sink功能;

13行,如果是in類型傳輸,即從device->host則根據pattern來初始化傳輸的數據。

18行,將當前端口的request加入到端口的request隊列中,這個功能通過調用與硬件相關的queue函數實現,這裏是調用s3c_hsotg_ep_queue。
對於source_sink配置,它有兩個端口,即in和out,一個用於接收來自HOST的數據,一個用於向host發送數據,所以配置完in端口後,還需要配置out端口,到這裏爲止就算設置完成 配置了。

由此可見,對於來自host的設置配置請求,對於複合型的設備,它將配置值對應的配置保存在複合型結構cdev的config中,用來表示當前配置,再將這個配置下的接口和端口使能,併爲各個端口申請請求資源,將其加入到端口的請求隊列中,等待事件處發。

講完了usb設備的設置配置請求後,回到composite_bind。

98-106行,獲取usb當前配置值,把它保存在用於存放request傳輸數據的buf裏。

111-129行,配置當前配置接口設置請求,通過調用sourcesink_set_alt函數來爲當前usb配置下由usb請求中中的index指定的接口配置由w_value指定的接口設置。

131-146,獲取當前配置下某個接口的接口設置。

對於接下來的獲取某個狀態和設置、清除feature這裏就不深入研究了。

其實到這裏爲止,USB的枚舉已經算是完成了,與枚舉有關的USB請求主要有設置USB地址,獲取設備,配置描述符,然後是設置配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章