USB gadget configfs

yooooooo發表於2024-09-03

概述

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 和product id :

$ 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>

可以是檔案系統中合法的任意字串,而是配置的編號,例如:

$ 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>

其中對應於一個允許的功能名稱,是檔案系統中允許的任意字串,例如:

$ 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

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

$ echo s3c-hsotg > UDC

6. 禁用gadget

$ echo "" > UDC

7. 清理

從配置中刪除功能:

$ rm configs/<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)
  • 個USB函式自然都有自己想要配置的檢視,所以特定函式的config_groups定義在函式實現檔案drivers/ USB /gadget/f_*.c中。
  • 函式的程式碼是以它所使用的方式編寫的。

Usb_get_function_instance(),它反過來呼叫request_module。因此,只要modprobe工作正常,特定函式的模組就會自動載入。請注意,相反的情況是不正確的: 在 gadget 被禁用和解除安裝後,模組仍然是載入的。

相關文章