透過 configfs 配置 Linux USB gadget¶
2013年4月25日
概述¶
Linux USB Gadget 是一個具有 UDC(USB 裝置控制器)的裝置,可以連線到 USB 主機,以擴充套件其額外的功能,例如序列埠或大容量儲存功能。
主機將 gadget 視為一組配置,每個配置包含多個介面,從 gadget 的角度來看,這些介面被稱為功能(functions),每個功能代表著例如一個序列連線或一個 SCSI 磁碟。
Linux 為 gadget 提供了許多可用的功能。
建立 gadget 意味著決定將有哪些配置以及每個配置將提供哪些功能。
Configfs(請參閱 Configfs - 使用者空間驅動的核心物件配置)非常適合用於將上述決定告知核心。本文件介紹瞭如何操作。
本文件還描述了 configfs 如何整合到 gadget 中的設計。
要求¶
為了使其正常工作,configfs 必須可用,因此 .config 中的 CONFIGFS_FS 必須為 'y' 或 'm'。截至本文撰寫時,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 都需要指定其供應商 ID <VID> 和產品 ID <PID>
$ echo <VID> > idVendor
$ echo <PID> > idProduct
gadget 還需要其序列號、製造商和產品字串。為了有地方儲存這些字串,必須為每種語言建立一個 strings 子目錄,例如:
$ mkdir strings/0x409
然後可以指定這些字串
$ echo <serial number> > strings/0x409/serialnumber
$ echo <manufacturer> > strings/0x409/manufacturer
$ echo <product> > strings/0x409/product
可以作為目錄在語言目錄下建立進一步的自定義字串描述符,字串文字寫入到該字串目錄內的“s”屬性中
$ mkdir strings/0x409/xu.0 $ echo <string text> > strings/0x409/xu.0/s
如果功能驅動程式支援,功能可能允許符號連結到這些自定義字串描述符,以將這些字串與類描述符關聯起來。
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> 對應於允許的功能名稱之一,而例項名稱是檔案系統中允許的任意字串,例如:
$ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()
...
...
...
每個功能都提供其特定的屬性集,具有隻讀或讀寫訪問許可權。在適用情況下,需要適當地寫入它們。請參閱 ABI 檔案測試/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 中有專案(items)和組(groups),兩者都表示為目錄。專案和組之間的區別在於組可以包含其他組。下圖只顯示了一個專案。專案和組都可以擁有屬性,這些屬性表示為檔案。使用者可以建立和刪除目錄,但不能刪除檔案,這些檔案可以是隻讀或讀寫的,取決於它們所代表的內容。
檔案系統檢視將是這樣的
每當使用者讀寫“sa”檔案時,就會呼叫一個接受 struct config_item 和 struct configfs_attribute 的函式。在該函式中,使用眾所周知的 container_of 技術檢索“cs”和“sa”,並呼叫適當的 sa 函式(show 或 store),並傳入“cs”和一個字元緩衝區。“show”用於顯示檔案內容(將資料從 cs 複製到緩衝區),而“store”用於修改檔案內容(將資料從緩衝區複製到 cs),但這兩個函式的實際作用由實現者決定。
./
./cs (directory)
|
+--sa (file)
|
.
.
.
檔名由 config item/group 設計者決定,而目錄通常可以隨意命名。一個組可以自動建立一些預設子組。
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 的更多資訊,請參閱 Configfs - 使用者空間驅動的核心物件配置。
上述概念轉換為 USB gadget 如下
1. gadget 擁有其配置組(config group),其中包含一些屬性(如 idVendor、idProduct 等)和預設子組(configs、functions、strings)。寫入這些屬性會導致資訊儲存在適當的位置。在 configs、functions 和 strings 子組中,使用者可以建立自己的子組來表示給定語言的配置、功能和字串組。
2. 使用者建立配置和功能,並在配置中建立指向功能的符號連結。當 gadget 的 UDC 屬性被寫入時,此資訊會被使用,這意味著將 gadget 繫結到 UDC。drivers/usb/gadget/configfs.c 中的程式碼會遍歷所有配置,並在每個配置中遍歷所有功能並繫結它們。透過這種方式,整個 gadget 都被綁定了。
檔案 drivers/usb/gadget/configfs.c 包含以下程式碼:
gadget 的 config_group
gadget 的預設組(configs、functions、strings)
將功能與配置關聯(符號連結)
4. 每個 USB 功能自然都有其自己的配置檢視,因此特定功能的 config_groups 定義在功能實現檔案 drivers/usb/gadget/f_*.c 中。
功能程式碼的編寫方式使其使用
usb_get_function_instance(),它又會呼叫 request_module。因此,只要 modprobe 正常工作,特定功能的模組就會自動載入。請注意,反之則不然:在 gadget 被停用並拆除後,模組仍然保持載入狀態。
© 核心開發社群。 | 由 Sphinx 5.3.0 和 Alabaster 0.7.16 提供技術支援 | 頁面源