通過configfs配置的Linux USB gadget


概述

USB Linux Gadget是一種具有UDC (USB設備控制器)的設備,可以連接到USB主機,以擴展其附加功能,如串口或大容量存儲能力。

一個gadget被它的主機視為一組配置,每個配置都包含一些接口,從gadget的角度來看,這些接口被稱為功能,每個功能代表一個串行連接或一個SCSI磁盤。

Linux提供了許多gadget可以使用的功能。

創建一個gadget意味着決定將有哪些配置以及每個配置將提供哪些功能。

Configfs(請參閱Configfs—用戶空間驅動的內核對象配置)非常適合告訴內核上述決定。本文檔是關於如何實現這一點的。它還描述了如何將configfs集成到gadget中。

要求

為了使其工作,配置文件必須可用,因此CONFIGFS_FS必須為 'y' 或 'm' 在.config中。在撰寫本文時,USB_LIBCOMPOSITE選擇CONFIGFS_FS。

用法

(描述configfs提供的第一個功能的原始帖子可以在這里看到:http://www.spinics.net/lists/linux-usb/msg76388.html)

$ modprobe libcomposite
$ mount none $CONFIGFS_HOME -t configfs

其中CONFIGFS_HOME是configfs的掛載點。

1. 創建gadget

對於每個要創建的gadget,必須創建相應的目錄:

$ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>

例如:

$ mkdir $CONFIGFS_HOME/usb_gadget/g1
$ cd $CONFIGFS_HOME/usb_gadget/g1

每個gadget需要指定其vendor id <VID>和product id <PID>:

$ echo <VID> > idVendor
$ echo <PID> > idProduct

gadget還需要它的序列號、制造商和產品字符串。為了有一個地方存儲它們,必須為每種語言創建一個字符串子目錄,例如:

$ mkdir strings/0x409

然后可以指定字符串:

$ echo <serial number> > strings/0x409/serialnumber
$ echo <manufacturer> > strings/0x409/manufacturer
$ echo <product> > strings/0x409/product

2. 創建配置

每個 gadget 將由許多配置組成,必須創建相應的目錄:

$ mkdir configs/<name>.<number>

<name>可以是文件系統中合法的任意字符串,而<number>是配置的編號,例如:

$ mkdir configs/c.1

每個配置也需要它的字符串,所以必須為每種語言創建一個子目錄,例如:

$ mkdir configs/c.1/strings/0x409

然后可以指定配置字符串:

$ echo <configuration> > configs/c.1/strings/0x409/configuration

也可以為配置設置一些屬性,例如:

$ echo 120 > configs/c.1/MaxPower

3. 創建功能

gadget將提供一些功能,對於每個功能,必須創建相應的目錄:

$ mkdir functions/<name>.<instance name>

其中<name>對應於一個允許的功能名稱,<instance name>是文件系統中允許的任意字符串,例如:

$ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()

每個函數都提供其特定的屬性集,具有只讀或讀寫訪問權限。如適用,需要酌情寫入。更多信息請參考Documentation/ABI/testing/configfs-usb-gadget。

4. 關聯功能及其配置

此時,許多gadget被創建出來,每個gadget都有一些指定的配置和一些可用的功能。剩下的就是指定哪個功能在哪個配置中可用(同一個功能可以在多個配置中使用)。這是通過創建符號鏈接來實現的:

$ ln -s functions/<name>.<instance name> configs/<name>.<number>

例如:

$ ln -s functions/ncm.usb0 configs/c.1

5. 啟用gadget

以上所有步驟的目的是組成gadget的配置和功能。

示例目錄結構可能看起來像這樣:

  .
  ./strings
  ./strings/0x409
  ./strings/0x409/serialnumber
  ./strings/0x409/product
  ./strings/0x409/manufacturer
  ./configs
  ./configs/c.1
  ./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0
  ./configs/c.1/strings
  ./configs/c.1/strings/0x409
  ./configs/c.1/strings/0x409/configuration
  ./configs/c.1/bmAttributes
  ./configs/c.1/MaxPower
  ./functions
  ./functions/ncm.usb0
  ./functions/ncm.usb0/ifname
  ./functions/ncm.usb0/qmult
  ./functions/ncm.usb0/host_addr
  ./functions/ncm.usb0/dev_addr
  ./UDC
  ./bcdUSB
  ./bcdDevice
  ./idProduct
  ./idVendor
  ./bMaxPacketSize0
  ./bDeviceProtocol
  ./bDeviceSubClass
  ./bDeviceClass

這樣的gadget必須最終啟用,以便USB主機能夠枚舉它。

為了啟用gadget,它必須綁定到UDC (USB設備控制器):

$ echo <udc name> > UDC

其中<udc name>是在/sys/class/udc/*,例如:

$ echo s3c-hsotg > UDC

6. 禁用gadget

$ echo "" > UDC

7. 清理

從配置中刪除功能:

$ rm configs/<config name>.<number>/<function>

 <config name >.<number>指定配置,<function>是指向從配置中刪除的功能的符號鏈接,例如:

$ rm configs/c.1/ncm.usb0

刪除配置中的字符串目錄:

$ rmdir configs/<config name>.<number>/strings/<lang>

例如:

$ rmdir configs/c.1/strings/0x409

並刪除配置:

$ rmdir configs/<config name>.<number>

例如:

rmdir configs/c.1

刪除功能(功能模塊不會被卸載):

$ rmdir functions/<name>.<instance name>

例如:

$ rmdir functions/ncm.usb0

刪除gadget中的字符串目錄:

$ rmdir strings/<lang>

例如:

$ rmdir strings/0x409

最后移除gadget:

$ cd ..
$ rmdir <gadget name>

例如:

$ rmdir g1

實施設計

下面介紹configfs的工作原理。在configfs中有項目和組,它們都表示為目錄。項和組之間的區別在於,組可以包含其他組。下圖中只顯示了一個項目。項和組都可以具有屬性,這些屬性表示為文件。用戶可以創建和刪除目錄,但不能刪除文件,文件可以是只讀的或讀寫的,這取決於它們所代表的內容。

configfs的文件系統部分操作config_items/groups和configfs_attributes,它們是通用的,對所有配置的元素具有相同的類型。但是,它們被嵌入到特定於使用的更大的結構中。下面的圖片中有一個“cs”,它包含一個config_item和一個“sa”,它包含一個configfs_attribute。

文件系統視圖是這樣的:

  ./
  ./cs        (directory)
     |
     +--sa    (file)
     |
     .
     .
     .

每當用戶讀取/寫入“sa”文件時,都會調用一個函數,該函數接受一個struct config_item和一個struct configfs_attribute。在上述函數中,使用眾所周知的container_of技術檢索“cs”和“sa”,並調用適當的sa函數(show或store)並傳遞“cs”和字符緩沖區。“show”用於顯示文件的內容(將數據從cs復制到緩沖區),而“store”用於修改文件的內容(將數據從緩沖區復制到cs),但這取決於兩個函數的實現者來決定它們的操作。

typedef struct configured_structure cs;
typedef struct specific_attribute sa;

                                       sa
                       +----------------------------------+
        cs             |  (*show)(cs *, buffer);          |
+-----------------+    |  (*store)(cs *, buffer, length); |
|                 |    |                                  |
| +-------------+ |    |       +------------------+       |
| | struct      |-|----|------>|struct            |       |
| | config_item | |    |       |configfs_attribute|       |
| +-------------+ |    |       +------------------+       |
|                 |    +----------------------------------+
| data to be set  |                .
|                 |                .
+-----------------+                .

文件名由配置項/組設計器決定,而目錄通常可以隨意命名。一個組可以有許多自動創建的默認子組。

有關configfs的更多信息,請參見`Documentation/filesystems/configfs.rst`。

上面描述的概念轉化為USB gadget如下:

1. 一個小工具有它的配置組,它有一些屬性(idVendor, idProduct等)和默認子組(configs, functions, strings)。寫入屬性將導致信息存儲在適當的位置。在配置、函數和字符串子組中,用戶可以創建它們的子組來表示給定語言中的配置、函數和字符串組。

2. 用戶創建配置和函數,在配置中創建到函數的符號鏈接。當將gadget的UDC屬性寫入時使用此信息,這意味着將gadget綁定到UDC。驅動程序/usb/gadget/configfs.c中的代碼遍歷所有配置,並且在每個配置中遍歷所有函數並綁定它們。這樣整個gadget就被綁定了。

3. 文件驅動程序/usb/gadget/configfs.c包含以下代碼:

  • gadget's config_group
  • gadget's default groups (configs, functions, strings)
  • associating functions with configurations (symlinks)

4. 個USB函數自然都有自己想要配置的視圖,所以特定函數的config_groups定義在函數實現文件drivers/ USB /gadget/f_*.c中。

5. 函數的代碼是以它所使用的方式編寫的。

 

Usb_get_function_instance(),它反過來調用request_module。因此,只要modprobe工作正常,特定函數的模塊就會自動加載。請注意,相反的情況是不正確的: 在 gadget 被禁用和卸載后,模塊仍然是加載的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM