Skip to main content
Version: BSP 7.x.y

USB Device Mode (Linux)

Introduction

The USB (Universal Serial Bus) standard specifies two possible roles for a device:

  • USB Host: The device controls the USB bus, provides power, and manages communication with the peripherals. A USB Bus can only have one host connected to it. In most cases, a host PC or controlling embedded device acts in Host Mode.
  • USB Peripheral/Device/Function: The device acts as a peripheral, and responds to commands from the host. A USB Bus can have multiple peripherals connected to it. Some examples are boards emulating a USB flash drive, or a network adapter.

You can connect a Toradex SoM as a Peripheral to an external USB Bus through the carrier board's USB DRP (Dual Role Port) or OTG (On-The-Go) connectors. Through these ports, the USB Controller in your SoM will initiate a negotiation protocol with the other devices connected to the bus, which will determine the host.

This article shows how to use the Gadget API to configure Toradex System-on-Modules (SoMs) as USB Peripherals. It allows you to choose a pre-defined role for your device through sysfs (e.g. mass storage, ethernet control, HID), and after a reboot, the device will operate according to the chosen role when connected to a USB Bus. For information on using Toradex SoMs in Host Mode, refer to USB Host Mode (Linux).

Linux

Our BSP Reference Images use the USB Gadget ConfigFS to configure the USB peripheral port. It allows you to configure USB functions by using file system commands, such as creating/writing files and directories. For further information, refer to the USB Gadget ConfigFS Kernel Documentation.

The library libusbgx (or its predecessor libusbg) allows you to use the USB Gadget ConfigFS through a C API. libusbgx also provides two utilities called gadget-import and gadget-export, that allow you to easily save and load a USB configuration from a configuration file called 'schema' (you can find an example schema file in your SoM at /etc/usbgx/g1.schema).

To customize how your device behaves as a USB Peripheral, you can alter the existing g1.schema or create your own. The following example shows you how to create a completely new configuration for your device.

Example Configuration: Mass Storage Device

This section will guide you on how to configure your SoM to act as a Mass Storage Device, similar to a flash drive or SD card, to illustrate the Gadget API usage. For information on the configuration files for other gadget functions, refer to the Gadget API Functions table. For further information on USB Gadget functions, refer to Documentation/usb/gadget-testing.txt.

  1. Mount the /sys/kernel/config directory:

    # mount -t configfs none /sys/kernel/config
    # cd /sys/kernel/config/usb_gadget/
    warning

    If /sys/kernel/config/usb_gadget/ does not exist you need to load the libcomposite module: modprobe libcomposite

  2. Create a new gadget:

    # mkdir g2
    # cd g2
  3. Define a vendor ID and a product ID. Toradex has its own vendor ID (0x1b67) and assigns a product ID for each Colibri and Apalis product which you as a customer can use too. The USB Product ID is the sum of an offset of 0x4000 and the hexadecimal representation of the product identifier, e.g. 0x4000 + 12 = 0x400c (the product identifier is the first 4 digits of the Toradex Product Number, e.g. 0012 for Colibri VF61 256MB IT V1.1B).

    • Vendor ID: Toradex's Vendor ID is 0x1b67.
    • Product ID: The Product ID is the sum of 0x4000 and the hexadecimal representation of the PID4 of your module. For example, the Verdin iMX8M Plus Quad 4GB WB IT has 0058 as the PID4; thus, its product ID is 0x4058 = 0x4000 + 0x0058.
    # echo 0x1b67 > idVendor
    # echo 0x4058 > idProduct
  4. Fill out USB descriptive information. These values will be readable from the host machine, and can help identifying the device when it's connected.

    # mkdir strings/0x409
    # cat /proc/device-tree/serial-number > strings/0x409/serialnumber
    # echo "Toradex" > strings/0x409/manufacturer
    # cat /proc/device-tree/model > strings/0x409/product
  5. Create a configuration directory for the gadget:

    You can asign one or more configurations to the gadget, but be aware that this can cause issues (see Documentation/usb/gadget_multi.txt).

    # mkdir configs/c.1
    # mkdir configs/c.1/strings/0x409
    # echo "USB CDC Ethernet config" > configs/c.1/strings/0x409/configuration
  6. Define the function of the gadget. For this example, we define it as a Mass Storage Device.

    # mkdir functions/mass_storage.1
    # ln -s functions/mass_storage.1 configs/c.1
  7. Create an image file to store the mass storage data, format it as a FAT filesystem.

    # dd if=/dev/zero of=/mass.img bs=4k count=2k
    # mkfs.vfat /mass.img
  8. Configure the gadget to use the image file for storage

    # echo /mass.img > functions/mass_storage.1/lun.0/file
  9. Create a storage device

    # mkdir functions/ecm.usb0
    # ln -s functions/ecm.usb0 configs/c.1
  10. Obtain the name of the USB controller. In the example below, the controller is named 38100000.usb.

    # ls /sys/class/udc/
    38100000.usb
  11. Disable the current USB gadget being used by the UDC, if any.

    # cd /sys/kernel/config/usb_gadget/
    # echo "" > g1/UDC
  12. Enable your custom gadget the USB controller. After this step, you should be able to connect to your device to a host and see it as a storage block.

    # echo "38100000.usb" > g2/UDC
  13. Store the configuration. The g2.schema file will store your configuration so you can rebuild the gadget later with a single command.

    # gadget-export g2 /etc/usbgx/g2.schema

The changes you do in the /sys/kernel/config/ are volatile, they will be erased when you restart your system. You can run the gadget-import command to reload your gadget:

# gadget-import g2 /etc/usbgx/g2.schema

Load Your Gadget Configuration Automatically

The file /etc/default/usbgx defines which gadgets are loaded automatically at system startup, and is used by the /usr/bin/gadget-start script. To make your gadget laoded by default, add it to the IMPORT_SCHEMAS variable:

/etc/default/usbgx
IMPORT_SCHEMAS="g1 g2"
ENABLED_SCHEMAS="$IMPORT_SCHEMAS"

If you wish for your gadget configuration to be active by default at start up, substitute it in the ENABLED_SCHEMAS variable.

/etc/default/usbgx
IMPORT_SCHEMAS="g1 g2"
ENABLED_SCHEMAS="g2"

Gadget API Functions

As shown in the example, you can add a function to your gadget by creating a directory functions/<name>.<instance name>. The following table provides a (incomplete) list of available functions in the Linux kernel. You can find documentation for the configuration files of each of them in Documentation/ABI/testing, under the files configfs-usb-gadget-<function-name>.

NameDriverDescriptionDocumentation
acmAbstract Control Model (CDC ACM)ACM serial link, works with Windows/Linux (use Documentation/usb/linux-cdc-acm.inf)configfs-usb-gadget-acm, Documentation/usb/gadget_serial.txt
gserGeneric serial bulk in/outThe function talks to the Linux-USB generic serial driverconfigfs-usb-gadget-serial
obexObject Exchange Model (CDC OBEX)Needs an user space OBEX serverconfigfs-usb-gadget-obex
rndisRNDISMicrosoft "Remote NDIS" (RNDIS) Ethernet protocol (use Documentation/usb/linux.inf)configfs-usb-gadget-rndis
ecmEthernet Control Model (CDC ECM)Ethernet Control Modelconfigfs-usb-gadget-ecm
eemEthernet Emulation Model (EEM)Newer USB Ethernet standard that is somewhat simpler than CDC ECMconfigfs-usb-gadget-eem
ncmNetwork Control Model (CDC NCM)Advanced protocol for Ethernetconfigfs-usb-gadget-ncm
ffsFunction filesystem (FunctionFS)Allows to implement USB functions from user-space (e.g. for MTP)configfs-usb-gadget-ffs, Documentation/usb/functionfs.txt
mass_storageMass storageExports a regular file or block device as USB Mass Storage disk driveconfigfs-usb-gadget-mass-storage, Documentation/usb/mass-storage.txt
hidHID functionGeneric emulation of USB Human Interface Devices (HID)configfs-usb-gadget-hid, Documentation/usb/gadget_hid.txt

U-Boot

Besides configuring your own USB functions for the device, it can be useful to access your device's file system as a USB Peripheral. This functionality is available in Toradex SoMs via U-Boot.

Inside the U-Boot command line, you can use the command ums (User Mode Storage) to expose your module's file system through the DRP/OTG USB port of the board, so that you can read or modify files from a host device. Note that ums currently can only export the user area of an eMMC, and not its boot areas. This prevents you from updating the bootloader with this mechanism.

Run the commands below to share your module's file system with a host:

  1. First, check which MMC device is the eMMC. In this example, device 2 is the eMMC one.

    > mmc list
    FSL_SDHC: 1
    FSL_SDHC: 2 (eMMC)
  2. Run the ums command. In this example, it will make the USB Controller 0 present the MMC Device 2 as a Mass Storage Device to the host.

    > ums 0 mmc 2

After running the ums command, your module should appear as a USB device in the host machine, such as shown below:

$ lsusb
...
Bus 003 Device 012: ID 1b67:403a Toradex USB download gadget
...

$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
...
sdk 8:32 1 14,8G 0 disk
├─sdk1 8:33 1 48M 0 part /mnt/BOOT
└─sdk2 8:34 1 14,8G 0 part /mnt/RFS

To stop sharing the filesystem, you can either press Ctrl+C or unmount the the partitions from your host machine.

Send Feedback!