Device Solution

In the Linux protocol stack, USB devices are referred to as Gadgets.

In Gadget mode, the USB OTG controller can be enumerated by a USB host and respond to transfer requests.

The Gadget driver supports two configuration methods:

Configfs mode: Dynamically configure Gadget functions through a user-space file system interface. Legacy mode: Use preset configurations by loading specific kernel modules.

This section primarily covers usage in Configfs mode.

For more details on device classes, refer to the kernel documentation usb support v5.4 or usb support v6.18.

How to Activate and Deactivate Gadget

After completing the ConfigFS gadget configuration, the gadget must be bound to the UDC (USB Device Controller) to make the device visible to a USB host. This step is called activating the gadget.

List Available UDCs

ls /sys/class/udc/

The UDC name for RTL8730E is 40080000.usb.

Activate Gadget

echo 40080000.usb > /sys/kernel/config/usb_gadget/<gadget_name>/UDC

After binding, the UDC begins enumeration with the USB host, which will recognize the USB device.

Check Current State

cat /sys/class/udc/40080000.usb/state

Common state values:

  • not-attached: No gadget is bound.

  • configured: Successfully enumerated; device is operating normally.

  • suspended: Enumerated but currently suspended.

Deactivate Gadget (Disconnect Without Losing Configuration)

echo "" > /sys/kernel/config/usb_gadget/<gadget_name>/UDC

After unbinding, the device disconnects from the host, but the ConfigFS gadget configuration is retained and can be activated again.

Note

The ConfigFS examples in each sub-section use cd /mnt/config/usb_gadget/<gadget_name> as the working directory, so the UDC binding step in each example is written as echo 40080000.usb > UDC (relative path), which is equivalent to the absolute path used in this section.

How to Configure ConfigFS

Every ConfigFS gadget shares the same directory layout. The following steps create the gadget directory and set up the common entries; the function-specific entries are described in each sub-section.

mkdir -p /mnt/config
mount none /mnt/config -t configfs
cd /mnt/config/usb_gadget
mkdir <gadget_name> && cd <gadget_name>

echo 0x0200 > bcdUSB
echo 0x0BDA > idVendor
echo 0x8731 > idProduct

mkdir strings/0x409
echo "Realtek" > strings/0x409/manufacturer
echo "Ameba Gadget" > strings/0x409/product
cat /proc/realtek/uuid > strings/0x409/serialnumber

mkdir configs/c.1
echo 120 > configs/c.1/MaxPower
mkdir configs/c.1/strings/0x409
echo "config1" > configs/c.1/strings/0x409/configuration

The meaning of each common entry is as follows:

  • bcdUSB — USB specification release number in BCD (e.g. 0x0200 for USB 2.0), reported in the device descriptor.

  • bDeviceClass / bDeviceSubClass / bDeviceProtocol — Device-level class code. Kept at 0x00 for a single-function gadget (class defined at interface level); a composite device using an IAD must set bDeviceClass to 0xEF (Miscellaneous), bDeviceSubClass to 0x02 and bDeviceProtocol to 0x01.

  • bMaxPacketSize0 — Maximum packet size for endpoint 0. Typically 64 for full/high-speed.

  • idVendor / idProduct — Vendor ID and Product ID that identify the device to the host. Set these to your assigned VID/PID.

  • strings/0x409 — String descriptors for language 0x409 (English, US). manufacturer, product and serialnumber are shown by the host when enumerating.

  • configs/c.1 — A configuration directory (the .1 suffix is the configuration number). Each function to be enabled is symlinked under this directory.

  • configs/c.1/MaxPower — Maximum current the device draws from the bus, in mA.

  • configs/c.1/strings/0x409/configuration — Description string of this configuration.

  • functions/<func>.<inst> — A function instance directory (e.g. acm.ttyS1, hid.usb0). It is created per function and then linked into configs/c.1 with ln -sf to add the function to the configuration.

After the common entries and the function instances are set up, bind the gadget to the UDC as described in How to Activate and Deactivate Gadget.

CDC ACM Device Solution

Configuration

Enabling the CDC ACM class requires additional settings on top of the basic USB configuration. Users can configure it as a kernel built-in feature or as a separate module.

Built-in Configuration:

Enter the USB Gadget Support menu and press Y to select:

Device Drivers  --->
    USB support  --->
        USB Gadget Support  --->
            [*] USB Gadget functions configurable through configfs
            [*] Serial gadget console support
            [*] Abstract Control Model (CDC ACM)

Application APIs

Refer to usb guide.

Usage Example

This example demonstrates how to configure the development board as a CDC ACM device.

  1. Use rtk_usb_test.sh to quickly start the USB ACM device mode:

    sh /bin/rtk_usb_test.sh -r usbd_acm
    
  2. Use a USB cable to connect the development board to the PC.

  3. Perform a loopback test on the development board terminal:

    Enter the send command on the development board terminal:

    echo 122 > /dev/ttyACM0
    

    Then execute the read command:

    cat /dev/ttyACM0
    

    122 should be displayed, indicating normal data transmission and reception.

  4. Pass criterion: The data sent from the board can be read back from /dev/ttyACM0, and the output matches the sent content.

Note

Windows 7 does not support CDC ACM devices. You need to install a specific driver: <sdk>/tools/image_tool/RtkUsbCdcAcmSetup.INF. The PID and VID in this driver must match the CDC ACM device descriptor.

Note

If the PC COM port cannot be opened, comment out the following code in <linux>/drivers/usb/gadget/function/f_acm.c as a temporary workaround:

static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
void *data, unsigned length)
{
/* ep_queue() can complete immediately if it fills the fifo... */
spin_unlock(&acm->lock);
//status = usb_ep_queue(ep, req, GFP_ATOMIC);
spin_lock(&acm->lock);
}

HID Device Solution

Configuration

Beyond Basic USB Configuration, to enable the HID class, ensure the kernel has selected HID bus support and Generic HID driver.

Device Drivers  --->
    HID support  --->
        [*] HID bus support
        [*] Generic HID driver

The above configurations are enabled by default in the SDK to support ADB.

Built-in Configuration:
  1. Enter the USB Gadget Support menu and select Y:

    Device Drivers  --->
        USB support  --->
            USB Gadget Support  --->
                [*] USB Gadget functions configurable through configfs
                [*] Serial gadget console support
                [*] HID function
    

Application APIs

Please refer to usb guide x498.

Usage Example

This example demonstrates how to configure the development board as an HID keyboard device.

  1. Use rtk_usb_test.sh to quickly start the USB HID device mode:

    sh /bin/rtk_usb_test.sh -r usbd_hid
    
  2. Use a USB cable to connect the development board to the PC.

  3. After connecting to the host, communicate with the host via the device node /dev/hidg0. The following commands send the keyboard report for the ‘a’ key to the host and then release the key:

    echo -ne "\x00\x00\x04\x00\x00\x00\x00\x00" > /dev/hidg0
    sleep 1
    echo -ne "\x00\x00\x00\x00\x00\x00\x00\x00" > /dev/hidg0
    

    The character ‘a’ should be observed on the PC side. On Linux, you can use evtest to verify HID events.

  4. Pass criterion: After sending the HID keyboard report, the character ‘a’ appears on the PC.

Note

Keyboard report format (8 bytes):

BYTE0: Modifier keys (Ctrl/Shift/Alt/GUI bitmask)
BYTE1: Reserved (always 0x00)
BYTE2~BYTE7: Keycode[0]~Keycode[5] (HID Usage ID)
Common key Usage IDs: a=0x04, b=0x05, Enter=0x28, Space=0x2C

ADB Device Solution

Configuration

In addition to Basic USB Configuration, enabling ADB requires enabling the ACC gadget function and the HID function in the kernel, as well as support for the Input/HID subsystem:

Built-in Configuration:
  1. Enter the USB Gadget Support menu and select Y:

    Device Drivers  --->
       Input device support  --->
          [*] Generic input layer
       HID support  --->
          [*] HID bus support
          [*] Generic HID driver
       USB support  --->
          USB Gadget Support  --->
                [*] USB Gadget functions configurable through configfs
                [*] Accessory gadget
                [*] HID function
    

Application APIs

Please refer to Android Open Accessory (AOA) protocol documentation

Usage Example

This example demonstrates how to configure the development board as an ADB device and have it recognized by the adb tool on a Windows PC.

  1. Use rtk_usb_test.sh to quickly start the ADB device mode:

    sh /bin/rtk_usb_test.sh -r usbd_adb
    
  2. Use a USB cable to connect the development board to the PC.

  3. Verify device recognition on the Windows PC command line:

    adb devices
    

    Example output:

    List of devices attached
    1712532505      device
    
  4. Pass criterion: The device status is device in the output of adb devices.

Note

A Windows PC must have the adb tool preinstalled (Android SDK Platform-Tools). The idVendor and idProduct must match the Google Accessory IDs in the ADB protocol (default values 0x18d1/0x4125).

MSC Device Solution

Configuration

In addition to the basic USB configuration, additional configuration is required to support the USB MSC class, which can be configured as a built-in feature or as a separate kernel module.

Built-in Configuration:
  1. Enter the USB Gadget Support menu and press Y to select:

    Device Drivers  --->
        USB support  --->
            USB Gadget Support  --->
                [*] USB Gadget functions configurable through configfs
                [*] Mass storage
    

Application APIs

Refer to usb guide x498.

Usage Example

This example demonstrates configuring the development board as a USB MSC device using an SD card as the storage medium.

Prerequisites:

  • An SD card is inserted and formatted (FAT32 recommended), accessible at /dev/mmcblk0.

  1. Use rtk_usb_test.sh to quickly start USB MSC device mode:

    sh /bin/rtk_usb_test.sh -r usbd_msc
    
  2. Connect the development board to a PC using a USB cable.

  3. After successful configuration, the PC will recognize a new removable disk (UDISK). Verify on the PC:

    Run the following command:

    lsblk
    # Expected: A new block device appears (e.g., /dev/sdb)
    
    mount /dev/sdb1 /mnt/usb
    cat /mnt/usb/test.txt  # Confirm SD card content is accessible
    umount /mnt/usb
    
  4. Test pass criteria: The PC recognizes the development board as a storage device and can read and write

    files on the SD card via the USB connection.

UAC Device Solution

Configuration

Enabling the UAC2 class requires additional settings on top of the basic USB configuration. Users can configure it as a kernel built-in feature or as a separate module.

Built-in Configuration:

Enter the USB Gadget Support menu and press Y to select:

Device Drivers  --->
    USB support  --->
        USB Gadget Support  --->
            [*] USB Gadget functions configurable through configfs
            [*] Audio Class 2.0

Application APIs

UAC Gadget devices expose an ALSA sound card interface. Refer to Linux ALSA documentation for more details.

Usage Example

This example demonstrates configuring the development board as a UAC device and verifying audio playback from the host PC.

  1. Use rtk_usb_test.sh to quickly start USB UAC2 device mode:

    sh /bin/rtk_usb_test.sh -r usbd_uac2
    
  2. Connect the development board to a PC using a USB cable.

  3. Confirm the ALSA devices on the board:

    cat /proc/asound/cards
    # Expected output:
    #   0 [Amebasnd       ]: Ameba-snd - Ameba-snd
    #   1 [UAC2Gadget     ]: UAC2_Gadget - UAC2_Gadget
    
  4. Start audio loopback (USB capture to codec playback):

    alsaloop -C hw:1,0 -P hw:0,0 -f S16_LE -r 48000 -c 2 </dev/null >/dev/null 2>&1 &
    pidof alsaloop
    

    Note

    alsaloop is provided by the alsa-utils package. Add IMAGE_INSTALL:append = " alsa-utils" to local.conf to include it in the Yocto firmware. After rebuilding the firmware, manually sync the rootfs:

    cp build_xx/tmp/deploy/images/xx/*.rootfs.squashfs images/rootfs.img
    
  5. Verify the USB audio device on the host PC:

    Run the following commands:

    # Confirm USB device
    lsusb | grep 0bda
    # Expected: Bus XXX Device YYY: ID 0bda:8730 Realtek Semiconductor Corp. UAC2 device
    
    # Confirm ALSA device
    aplay -l | grep uac2
    # Expected: card 1: device [UAC2 device], device 0: USB Audio
    
    # Recording test (5 seconds)
    arecord -D plughw:CARD=1,DEV=0 -f S16_LE -r 48000 -c 2 -d 5 /tmp/uac2_test.wav
    

    Parameter description:

    -D plughw:CARD=1,DEV=0: Use the ALSA plugin device, Card 1, Device 0. -f S16_LE: Sample format, 16-bit signed little-endian. -r 48000: Sample rate 48000 Hz. -c 2: Number of channels 2 (stereo). -d 5: Recording duration 5 seconds.

    # Playback test (audio output through the development board 3.5mm jack)
    aplay -D plughw:CARD=1,DEV=0 /tmp/uac2_test.wav
    

    Parameter description:

    -D plughw:CARD=1,DEV=0: Use the ALSA plugin device, Card 1, Device 0.

Note

The c_sync attribute must be set to adaptive. The dwc2 controller does not support async feedback endpoints. Without an audio codec bridge, captured audio data will be all zeros. This is expected behavior. Speaker volume may be too high by default. Use the amixer cset command to adjust the volume.

Vendor Device Solution

Configuration

In addition to the basic USB configuration, additional configuration is required to support the USB Vendor class driver. It can be configured as a built-in feature or as a separate kernel module.

Built-in Configuration:
  1. Enter the USB Gadget Support menu and press Y to select:

    Device Drivers  --->
        USB support  --->
            USB Gadget Support  --->
                [*] USB Gadget functions configurable through configfs
                [*] Loopback and sourcesink function (for testing)
    

Application APIs

None.

Usage Example

This example configures a USB Composite Device via configfs, containing two USB Configurations:

Configuration 1 (configs/c.1) provides the SourceSink test function:

ln -s functions/SourceSink.0 configs/c.1/

Configuration 2 (configs/c.2) provides the Loopback test function:

ln -s functions/Loopback.0 configs/c.2/

After USB enumeration completes, both configurations are presented to the host. If the host does not explicitly select a configuration, it typically defaults to Configuration 1, so the device operates in SourceSink mode by default.

Configuration Switching

To test the Loopback function in Configuration 2, satisfy any of the following conditions:

  • Bind the Loopback function to configs/c.1 before enumeration.

  • Have the host explicitly send SET_CONFIGURATION(2).

  • Re-enumerate the gadget by unbinding/binding the UDC.

For example, in a user-space application, you can switch the configuration via libusb_set_configuration():

libusb_open(dev, &handle);

libusb_set_configuration(handle, 2);  /* Switch to configs/c.2 (Loopback) */

After switching, run testusb to execute the corresponding Loopback test cases.

Note

  • The USB gadget side cannot force a default configuration; the configuration is selected by the host during enumeration.

  • If the host does not explicitly send SET_CONFIGURATION, it typically defaults to Configuration 1.

  • After modifying the configuration or function bindings in configfs, you must re-enumerate the device

    (e.g., unbind/bind the UDC) for the changes to take effect.

  • The term “default mode” in this document refers to the host’s de facto selection of Configuration 1,

    not an active choice by the gadget.

The following steps demonstrate testing the Gadget Vendor-class functionality:

  1. Use rtk_usb_test.sh to quickly start USB Vendor device mode:

    sh /bin/rtk_usb_test.sh -r usbd_vendor
    
  2. Connect the development board to the USB host.

  3. Run host-versus-device Vendor interaction tests (with the testusb tool):

    Function

    sourcesink

    loopback

    Configuration setup

    ln -s functions/Loopback.0 configs/c.1/

    ln -s functions/SourceSink.0 configs/c.2/

    Host console command

    testusb -a -c1 -tx -s256 -g32 -v1

    testusb -a -c1 -t30 -s256 -g32 -v1

    Device console cmd

    Not required

    Not required

Note

In the host test commands:

  • Case 30 (-t30) is dedicated to Loopback testing.

  • Cases 0~29 (-tx, x=0..29) are used for SourceSink testing; parameters can be adjusted as needed.

  • The -c parameter indicates the number of iterations, not the USB Configuration index.

Composite Device Solution

In the Linux ConfigFS framework, linking multiple function instances to the same configuration (configs/c.1) implements a composite USB device without additional drivers.

Configuration

A composite device reuses the kernel configuration of each function class and requires no additional options. Using a CDC ACM + HID combination as an example:

Built-in Configuration:

Enter the USB Gadget Support menu and press Y to select:

Device Drivers  --->
    USB support  --->
        USB Gadget Support  --->
            [*] USB Gadget functions configurable through configfs
            [*] Serial gadget console support
            [*] Abstract Control Model (CDC ACM)
            [*] HID function

Application APIs

None.

Example

This example configures the board as a composite USB device that simultaneously provides CDC ACM and HID keyboard functions.

  1. Connect the board to a PC with a USB cable.

  2. Run the following commands in the board terminal to configure via ConfigFS:

    mkdir -p /mnt/config
    mount none /mnt/config -t configfs
    cd /mnt/config/usb_gadget
    mkdir composite && cd composite
    
    # IAD 描述符:多功能设备必须将 bDeviceClass 设为 0xEF
    echo 0x0200 > bcdUSB
    echo 0xEF > bDeviceClass
    echo 0x02 > bDeviceSubClass
    echo 0x01 > bDeviceProtocol
    echo 64 > bMaxPacketSize0
    echo 0x0BDA > idVendor
    echo 0x8731 > idProduct
    
    mkdir strings/0x409
    echo "Realtek" > strings/0x409/manufacturer
    echo "Composite ACM+HID" > strings/0x409/product
    cat /proc/realtek/uuid > strings/0x409/serialnumber
    
    mkdir configs/c.1
    echo 120 > configs/c.1/MaxPower
    mkdir configs/c.1/strings/0x409
    echo "composite" > configs/c.1/strings/0x409/configuration
    
    # Function 1:CDC ACM
    mkdir functions/acm.ttyS1
    ln -sf functions/acm.ttyS1 configs/c.1/
    
    # Function 2:HID 键盘
    mkdir functions/hid.usb0
    echo 1 > functions/hid.usb0/subclass
    echo 1 > functions/hid.usb0/protocol
    echo 8 > functions/hid.usb0/report_length
    echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
    ln -sf functions/hid.usb0 configs/c.1/
    
  3. Bind the UDC to activate the gadget (see Activate and Deactivate Gadget):

    echo 40080000.usb > UDC
    
  4. Verify device enumeration on the PC:

    lsusb -d 0x0BDA:0x8731 -v
    

    The output should show two interfaces: Interface 0 is CDC ACM, Interface 2 is HID.

  5. Verify the ACM interface (loopback test on the board):

    In the board terminal, run the send command:

    echo 122 > /dev/ttyACM0
    

    Then run the receive command:

    cat /dev/ttyACM0
    

    The output should show 122, confirming the ACM interface is transmitting and receiving correctly.

  6. Verify the HID interface (simulate a key press on the board):

    In the board terminal, write a key report to the HID device node (using the Enter key as an example):

    echo -ne '\x00\x00\x28\x00\x00\x00\x00\x00' > /dev/hidg0
    echo -ne '\x00\x00\x00\x00\x00\x00\x00\x00' > /dev/hidg0
    

    A Return key input event should be observed on the PC.

  7. Pass criteria: PC lsusb shows a composite device with both ACM and HID interfaces; /dev/ttyACM0 ACM loopback works correctly; writing to /dev/hidg0 triggers an input event on the PC.

Note

A composite device must set bDeviceClass to 0xEF (Miscellaneous), bDeviceSubClass to 0x02, and bDeviceProtocol to 0x01 so that the USB host correctly identifies each function class via IAD (Interface Association Descriptor). Using the bDeviceClass value of a single function class may prevent the host from enumerating all interfaces correctly.

Note

For more details on ConfigFS composite devices, refer to the Linux kernel documentation USB Gadget configfs.