Chapter 55: USB gadget¶
What: the USB gadget framework, turning the i.MX6ULL’s USB OTG controller into a USB device (instead of a host). The mainline ConfigFS gadget interface lets user-space compose USB devices from “functions” (mass storage, serial, Ethernet, HID) without writing kernel code.
Why: USB gadget runs on Android phones, Raspberry Pi Zero in USB-Pi mode, smart meters that expose data over USB-serial, and many other devices. For embedded products: USB-as-device is how your board talks to a PC for debug, firmware update, or as a remote sensor.
Focus: functions composed into a configuration. A gadget has one configuration with one or more functions. ConfigFS exposes this as a filesystem:
mkdira function,echosettings into its files, then bind to a UDC. No kernel code.
55.1 USB roles on i.MX6ULL¶
i.MX6ULL has 2× USB OTG controllers. Each can be:
Host: Linux runs the USB host stack. Devices plug into it.
Device (gadget), the SoC is a USB device that gets plugged into something else.
OTG: auto-detect host/device via the ID pin.
Configure in DT:
&usbotg1 {
dr_mode = "peripheral"; /* device-only */
/* or "host", or "otg" */
vbus-supply = <®_usb_otg1_vbus>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usbotg1>;
status = "okay";
};
For “otg” mode you also wire the ID pin to a GPIO.
MCU bridge: Think of Linux GPIO like the same pin set/reset block you used on STM32, but accessed through a kernel subsystem that owns numbering, direction, interrupts, and user-space exposure. GPIO: General-Purpose Input/Output, a pin controlled as a digital input, output, or interrupt source.
55.2 ConfigFS gadget overview¶
ConfigFS is the current way to compose a USB gadget. From userspace:
# Mount configfs
mount -t configfs none /sys/kernel/config
# Create gadget
cd /sys/kernel/config/usb_gadget
mkdir mygadget
cd mygadget
# Device descriptor
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB # USB 2.0
# Strings
mkdir strings/0x409 # English (US)
echo "Linuxlearn" > strings/0x409/manufacturer
echo "MyGadget" > strings/0x409/product
echo "ABCD1234" > strings/0x409/serialnumber
# Functions: a serial port, a network interface, mass storage
mkdir functions/acm.GS0
mkdir functions/ecm.usb0
mkdir functions/mass_storage.0
echo /dev/loop0 > functions/mass_storage.0/lun.0/file
# Configuration
mkdir configs/c.1
ln -s functions/acm.GS0 configs/c.1/
ln -s functions/ecm.usb0 configs/c.1/
ln -s functions/mass_storage.0 configs/c.1/
mkdir configs/c.1/strings/0x409
echo "Conf 1" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower
# Bind to a UDC (USB Device Controller)
ls /sys/class/udc/ # find the udc name
echo 2184000.usb > UDC
The last line binds the gadget by writing the UDC name. Plug a USB cable from the i.MX6ULL’s OTG port into a PC. The PC sees a composite USB device with serial, Ethernet, and mass storage.
55.3 Common function types¶
Function |
Description |
Linux usage |
|---|---|---|
|
CDC-ACM serial port |
|
|
CDC Ethernet |
|
|
NCM Ethernet (faster) |
same |
|
RNDIS Ethernet (Windows-compatible) |
same |
|
USB mass storage |
block device on host |
|
HID device (keyboard, mouse, custom) |
input device on host |
|
UVC webcam |
webcam on host |
|
USB MIDI |
midi device on host |
Each is a kernel module: g_acm.ko, usb_f_ecm.ko, etc. Built-in or modular.
55.4 Real-world examples¶
USB-serial console for a headless device¶
mkdir -p /sys/kernel/config/usb_gadget/console
cd $_
echo 0x1d6b > idVendor
echo 0x0104 > idProduct
mkdir strings/0x409
echo "Linuxlearn" > strings/0x409/manufacturer
echo "Headless" > strings/0x409/product
mkdir functions/acm.0
mkdir configs/c.1
ln -s functions/acm.0 configs/c.1/
echo 2184000.usb > UDC
Now from the host PC: /dev/ttyACM0 is the i.MX6ULL’s UART/console.
USB Ethernet for SSH¶
mkdir -p /sys/kernel/config/usb_gadget/ssh
cd $_
echo 0x1d6b > idVendor; echo 0x0104 > idProduct
mkdir functions/ecm.usb0
echo aa:bb:cc:dd:ee:01 > functions/ecm.usb0/host_addr
echo aa:bb:cc:dd:ee:02 > functions/ecm.usb0/dev_addr
mkdir configs/c.1; ln -s functions/ecm.usb0 configs/c.1/
echo 2184000.usb > UDC
usb0 appears on both sides. Assign IPs:
# On i.MX6ULL:
ip addr add 192.168.10.2/24 dev usb0
ip link set usb0 up
# On host PC:
ip addr add 192.168.10.1/24 dev usb0
ip link set usb0 up
ssh root@192.168.10.2
USB mass storage from a file¶
dd if=/dev/zero of=/tmp/disk.img bs=1M count=64
mkfs.vfat /tmp/disk.img
losetup /dev/loop0 /tmp/disk.img
mkdir -p /sys/kernel/config/usb_gadget/ms
cd $_
echo 0x1d6b > idVendor; echo 0x0104 > idProduct
mkdir functions/mass_storage.0
echo /tmp/disk.img > functions/mass_storage.0/lun.0/file
mkdir configs/c.1; ln -s functions/mass_storage.0 configs/c.1/
echo 2184000.usb > UDC
The host PC sees a 64 MB USB stick.
55.5 Writing a custom function¶
For specialised use cases (e.g., a custom protocol over USB), you can write a kernel function driver. But before doing so, check whether FunctionFS (a userspace-driven generic function) fits your needs. With FunctionFS, your gadget function lives in user space, the kernel just relays bytes between endpoints and your daemon. Much less work than a kernel function.
55.6 Lab¶
Compose a USB serial gadget. Use ConfigFS as in §55.4. Plug into a host PC, see
/dev/ttyACM0.USB Ethernet over OTG. Set up
ecmfunction, assign IPs both sides, SSH into the i.MX6ULL.Mass storage from a backing file. Expose a virtual disk. Mount it on the host. Copy files.
HID keyboard. Use
g_hidto make the i.MX6ULL appear as a USB keyboard. “type” characters by writing report descriptors.Hot re-bind. Write to
UDCwith empty string to disconnect. Then re-bind. Useful for changing config without reboot.Composite gadget. Stack ACM + ECM + mass storage in one configuration. Verify all three function on the host.
55.7 Pitfalls¶
Forgetting
vbus-supply. USB device mode still needs VBUS sensing. Without it, the controller never detects a “plugged” event.dr_mode = "host"when you want device. Symptom: nothing plugs in on the host. Always check.Wrong VID/PID. Windows binds drivers based on these. Wrong values → host loads wrong driver → device fails to enumerate.
mass_storagebacking file is too small / wrong format. Host complains about corrupted filesystem.Two gadgets bound to one UDC. Only one bind per UDC at a time. Disconnect first.
ACM not appearing on Windows. Windows needs a
.infdriver file before it will bind to CDC-ACM. Linux/macOS hosts are fine.
55.8 Going deeper¶
Documentation/usb/gadget_configfs.rst: the canonical ConfigFS gadget doc.drivers/usb/gadget/: gadget framework and functions.drivers/usb/gadget/function/: individual function drivers (one per.cfile).Documentation/usb/functionfs.rst: FunctionFS for user-space-driven gadgets.Documentation/devicetree/bindings/usb/: USB controller bindings.
Next chapter: Chapter 55A: Kernel timers + hrtimers. Beyond
mdelay/msleep, the kernel offers precise timers for scheduling delayed work and periodic actions.