USB gadget configuration

Introduction

This page is mainly about how to configure USB Gadget on Linux kernel.

Problem statement

USB Gadget ConfigFS is an interface that allows definition of arbitrary functions and configurations to define an application specific USB composite device from userspace. The problem with this approach is that the gadget USB stack decides the order in which the endpoints are enabled and most of the time the endpoints are not enabled in the order required by the SoC datasheet (DPRAM Management section - Endpoints can only be allocated in ascending order, from the endpoint 0 to the last endpoint to be allocated. The user shall therefore configure them in the same order.)

To solve this problem two possible solutions are implemented in the driver and are selected by the value of fifo_mode variable as follows:

fifo_mode = 0 is used to let the driver autoconfigure the endpoints. In this case 2 banks are allocated so that they could be used as isochronous endpoints. Only one bank is allocated for the rest of the endpoints.

fifo_mode = value different than 0 means that a predefined user optimized configuration is to be used by loading it form a table. The data structure that defines the table is the following:

struct usba_fifo_cfg {
   u8          hw_ep_num;
   u16         fifo_size;
   u8          nr_banks;
};

hw_ep_num - is the endpoint number as assigned by datashet (its an ascending value starting from 0).

fifo size - is the maximum fifo size that will be used by an application.

nr_banks - is the maximum number of banks used by application. Possible values are 1, 2 and 3 for isochronous endpoints. Having more banks will increase performance of the application but will consume more USBA internal DPRAM memory.

For example for fifo_mode = 3 the following configuration is loaded:

static struct usba_fifo_cfg mode_3_cfg[] = {
{ .hw_ep_num = 0, .fifo_size = 64,     .nr_banks = 1, },
{ .hw_ep_num = 1, .fifo_size = 1024,   .nr_banks = 2, },
{ .hw_ep_num = 2, .fifo_size = 512,    .nr_banks = 2, },
{ .hw_ep_num = 3, .fifo_size = 512,    .nr_banks = 2, },
{ .hw_ep_num = 4, .fifo_size = 512,    .nr_banks = 2, },
{ .hw_ep_num = 5, .fifo_size = 512,    .nr_banks = 2, },
{ .hw_ep_num = 6, .fifo_size = 512,    .nr_banks = 2, },
};

All fifo_mode configurations are declared in atmel_usba_udc.c file. The version used on 4.9 kernel can be accessed at the following link: https://github.com/linux4sam/linux-at91/blob/linux-4.9-at91/drivers/usb/gadget/udc/atmel_usba_udc.c#L348

Please refer to the SoC datasheet for more informations.

Configurations in Kernel

Atmel USBA hardware driver must be enabled in kernel configuration. Entering Linux source directory:
make menuconfig

Device Drivers > USB support > USB Gadget Support > USB Peripheral Controller
    -->   Atmel USBA

Device Drivers > USB support > USB Gadget Support
     -->   USB Gadget Drivers
          -->     USB functions configurable through configfs

The following configs will be enabled in .config

CONFIG_USB_GADGET=y
CONFIG_USB_CONFIGFS=m
CONFIG_USB_CONFIGFS_...=y for various function drivers like:
CONFIG_USB_CONFIGFS_ACM, CONFIG_USB_CONFIGFS_RNDIS, CONFIG_USB_CONFIGFS_MASS_STORAGE, CONFIG_USB_CONFIGFS_F_HID 

Building CONFIG_USB_CONFIGFS as a module will need to load it at run time:
modprobe libcomposite

How to configure fifo_mode parameter

The fifo_mode parameter must be added to the kernel command line. For example if one wants to configure fifo_mode to 3 the following command must be appended to kernel command line.

atmel_usba_udc.fifo_mode=3

One way to accomplish this is by editing the bootargs environment variable from u-boot using editenv command.

=> editenv bootargs
edit: console=ttyS0,115200 root=/dev/mmcblk1p1 rw rootfstype=ext4 rootwait atmel_usba_udc.fifo_mode=3

Applications

Simple USB Gadget script

The following script can be used to initialize a simple USB Gadget composite device (CDC ACM+RNDIS) from user space:
#! /bin/sh
  modprobe libcomposite
  mount -t configfs none /sys/kernel/config
  cd /sys/kernel/config/
  cd usb_gadget
  mkdir g1
  cd g1
  echo "0x04D8" > idVendor
  echo "0x1234" > idProduct
  mkdir strings/0x409
  echo "0123456789" > strings/0x409/serialnumber
  echo "Microchip Technology, Inc." > strings/0x409/manufacturer
  echo "Linux USB Gadget" > strings/0x409/product
  mkdir functions/rndis.usb0
  mkdir functions/acm.usb0
  mkdir configs/c.1
  mkdir configs/c.1/strings/0x409
  echo "CDC ACM+RNDIS" > configs/c.1/strings/0x409/configuration
  ln -s functions/rndis.usb0 configs/c.1
  ln -s functions/acm.usb0 configs/c.1
  echo "300000.gadget" > UDC
WebFaqBaseForm
Boards Sama5d2Xplained, Sama5d4Xplained, Sama5d4ek, Sama5d3Xplained, Sama5d3xek, AT91sam9x5-ek, other AT91SAM9 boards
Components Kernel, linux-4.4-at91, linux-4.9-at91
Summary Configure AT91 USB Gadget on Linux and Endpoint order management (composite USB)
r11 - 04 Jul 2017 - 12:43:43 - NicolasFerre
 
Linux & Open Source related information for AT91 Smart ARM Microcontrollers

Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.

Linux® is the registered trademark of Linus Torvalds in the U.S. and other countries.

Atmel® and others, are registered trademarks or trademarks of Atmel Corporation or its subsidiaries. This site is powered by the TWiki collaboration platform

ARM® and others are registered trademarks or trademarks of ARM Ltd. Other terms and product names may be trademarks of others.

Ideas, requests, contributions ? Connect to LinksToCommunities page.

Syndicate this siteRSS ATOM