Linux usb file storage gadget

Linux USB gadget configured through configfs¶

A USB Linux Gadget is a device which has a UDC (USB Device Controller) and can be connected to a USB Host to extend it with additional functions like a serial port or a mass storage capability.

A gadget is seen by its host as a set of configurations, each of which contains a number of interfaces which, from the gadget’s perspective, are known as functions, each function representing e.g. a serial connection or a SCSI disk.

Linux provides a number of functions for gadgets to use.

Creating a gadget means deciding what configurations there will be and which functions each configuration will provide.

Configfs (please see Configfs — Userspace-driven Kernel Object Configuration ) lends itself nicely for the purpose of telling the kernel about the above mentioned decision. This document is about how to do it.

It also describes how configfs integration into gadget is designed.

Requirements¶

In order for this to work configfs must be available, so CONFIGFS_FS must be ‘y’ or ‘m’ in .config. As of this writing USB_LIBCOMPOSITE selects CONFIGFS_FS.

Usage¶

(The original post describing the first function made available through configfs can be seen here: http://www.spinics.net/lists/linux-usb/msg76388.html)

$ modprobe libcomposite $ mount none $CONFIGFS_HOME -t configfs

where CONFIGFS_HOME is the mount point for configfs

1. Creating the gadgets¶

For each gadget to be created its corresponding directory must be created:

$ mkdir $CONFIGFS_HOME/usb_gadget/

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

Each gadget needs to have its vendor id and product id specified:

$ echo > idVendor $ echo > idProduct

A gadget also needs its serial number, manufacturer and product strings. In order to have a place to store them, a strings subdirectory must be created for each language, e.g.:

Then the strings can be specified:

$ echo > strings/0x409/serialnumber $ echo > strings/0x409/manufacturer $ echo > strings/0x409/product

Further custom string descriptors can be created as directories within the language’s directory, with the string text being written to the «s» attribute within the string’s directory:

$ mkdir strings/0x409/xu.0 $ echo > strings/0x409/xu.0/s

Where function drivers support it, functions may allow symlinks to these custom string descriptors to associate those strings with class descriptors.

2. Creating the configurations¶

Each gadget will consist of a number of configurations, their corresponding directories must be created:

where can be any string which is legal in a filesystem and the is the configuration’s number, e.g.:

Each configuration also needs its strings, so a subdirectory must be created for each language, e.g.:

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

Then the configuration string can be specified:

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

Some attributes can also be set for a configuration, e.g.:

$ echo 120 > configs/c.1/MaxPower

3. Creating the functions¶

The gadget will provide some functions, for each function its corresponding directory must be created:

Читайте также:  Linux установка пакетов apt

where corresponds to one of allowed function names and instance name is an arbitrary string allowed in a filesystem, e.g.:

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

Each function provides its specific set of attributes, with either read-only or read-write access. Where applicable they need to be written to as appropriate. Please refer to Documentation/ABI/testing/configfs-usb-gadget for more information.

4. Associating the functions with their configurations¶

At this moment a number of gadgets is created, each of which has a number of configurations specified and a number of functions available. What remains is specifying which function is available in which configuration (the same function can be used in multiple configurations). This is achieved with creating symbolic links:

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

5. Enabling the gadget¶

All the above steps serve the purpose of composing the gadget of configurations and functions.

An example directory structure might look like this:

. ./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

Such a gadget must be finally enabled so that the USB host can enumerate it.

In order to enable the gadget it must be bound to a UDC (USB Device Controller):

where is one of those found in /sys/class/udc/* e.g.:

6. Disabling the gadget¶

7. Cleaning up¶

Remove functions from configurations:

where . specify the configuration and is a symlink to a function being removed from the configuration, e.g.:

Remove strings directories in configurations:

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

and remove the configurations:

Remove functions (function modules are not unloaded, though):

Remove strings directories in the gadget:

and finally remove the gadget:

Implementation design¶

Below the idea of how configfs works is presented. In configfs there are items and groups, both represented as directories. The difference between an item and a group is that a group can contain other groups. In the picture below only an item is shown. Both items and groups can have attributes, which are represented as files. The user can create and remove directories, but cannot remove files, which can be read-only or read-write, depending on what they represent.

The filesystem part of configfs operates on config_items/groups and configfs_attributes which are generic and of the same type for all configured elements. However, they are embedded in usage-specific larger structures. In the picture below there is a «cs» which contains a config_item and an «sa» which contains a configfs_attribute.

Читайте также:  Linux вырезать вставить файл

The filesystem view would be like this:

Whenever a user reads/writes the «sa» file, a function is called which accepts a struct config_item and a struct configfs_attribute. In the said function the «cs» and «sa» are retrieved using the well known container_of technique and an appropriate sa’s function (show or store) is called and passed the «cs» and a character buffer. The «show» is for displaying the file’s contents (copy data from the cs to the buffer), while the «store» is for modifying the file’s contents (copy data from the buffer to the cs), but it is up to the implementer of the two functions to decide what they actually do.

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 | . | | . +-----------------+ .

The file names are decided by the config item/group designer, while the directories in general can be named at will. A group can have a number of its default sub-groups created automatically.

The concepts described above translate to USB gadgets like this:

1. A gadget has its config group, which has some attributes (idVendor, idProduct etc) and default sub-groups (configs, functions, strings). Writing to the attributes causes the information to be stored in appropriate locations. In the configs, functions and strings sub-groups a user can create their sub-groups to represent configurations, functions, and groups of strings in a given language.

2. The user creates configurations and functions, in the configurations creates symbolic links to functions. This information is used when the gadget’s UDC attribute is written to, which means binding the gadget to the UDC. The code in drivers/usb/gadget/configfs.c iterates over all configurations, and in each configuration it iterates over all functions and binds them. This way the whole gadget is bound.

    The file drivers/usb/gadget/configfs.c contains code for

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

4. Each USB function naturally has its own view of what it wants configured, so config_groups for particular functions are defined in the functions implementation files drivers/usb/gadget/f_*.c.

usb_get_function_instance(), which, in turn, calls request_module. So, provided that modprobe works, modules for particular functions are loaded automatically. Please note that the converse is not true: after a gadget is disabled and torn down, the modules remain loaded.

Источник

Working with Linux

Today I have enabled the USB gadget support for file storage. The intention is to be able to export files via the USB device interface to a PC.

Читайте также:  Huawei matebook 13 amd linux

The file storage gadget must be enabled at the kernel config menu:
USB support -> Support for USB gadgets -> File-backed storage gadget

Note that only one USB gadget may be enabled at the same time. If multiple gadgets must be supported, all of them must be configured as modules, so I had to remove built-in support for ethernet gadget from the kernel. Switching the USB function requires removing and installing the proper modules.

The module for file storage is g_file_storage.o and is installed this way:
insmod g_file_storage.o file=/results.bin stall=0

The ‘stall’ argument is necessary for the USB disk to be properly detected by windows. Linux does not require this argument and the drive can be mounted without problem. If ‘stall’ is not set to zero and the gadget is connected to a windows PC, the following messages appear:
g_file_storage pxa2xx_udc: full speed config #1
udc: pxa2xx_ep_disable, ep1in-bulk not enabled
udc: pxa2xx_ep_disable, ep2out-bulk not enabled
udc: USB reset
udc: USB reset

repeating every few seconds.

For the ‘stall’ option to be available, it is necessary to enable the ‘file-backed storage gadget in test mode’ option in the kernel configuration.

Multiple files may be specified when the gadget module is installed, thus creating multiple drives visible to the remote host.

Any volume size may be created but it seems that Windows assigns floppy drive letters if the volume size is similar to a floppy device size. I have tested 720KB and 1440KB only.

The volume may be declared as read-only by using the «ro=1» parameter at the insmod.

The backend file may be either a disk partition or a file image.
An initial filesystem image can be created this way:

# dd if=/dev/zero of=results.bin bs=512 count=2880
# mkdosfs results.bin

Then, loop-mount the image file and populate the filsystem. Here is where problems came: if a process writes a new file to the loop filesystem, the host side of the USB connection (where the file browser runs) does not see the new file, even if the file browser is refreshed. The only workaround is to unplug/plug again the USB cable. This happens even if a ‘sync’ command is run on the tester device.

Also, some inconsistences happen if the USB host side writes to the device. The device doesn’t see the new files, and vice-versa.

In conclusion, it is quite a good method to export only file from a Linux device, but with some limitations on «live» filesystems.

Источник

Оцените статью
Adblock
detector