USB gadget configuration
This page is mainly about how to configure USB Gadget on Linux kernel. There are two ways to configure the USB Gadget framework: from within Linux kernel or from user space using ConfigFS.
For both options, the 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. If unsure use this option as
default.
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 (it’s 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.
How to configure fifo_mode parameter
The
default fifo_mode=0 should be fine for most configurations. If needed, the fifo_mode parameter can be changed by adding it 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
This option configures the gadget directly from the kernel config using precomposed configuration. The are multiple options here from simple devices like CDC ACM, Mass storgae, RNDIS, etc. to composite devices like Ethernet + ACM.
In this section we will present how to configure a composite Ethernet + ACM device.
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 precomposed configurations (<choice> [=m])
The following configs will be enabled in .config
CONFIG_USB_GADGET=y
CONFIG_USB_CDC_COMPOSITE=m
The following will be selected automatically:
CONFIG_USB_LIBCOMPSITE[=m], USB_U_SERIAL[=m], USB_U_ETHER[=m], USB_F_ACM[=m], USB_F_ECM[=m]
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
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
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
The string that needs to be written in the UDC is dependent on the address at which the usb device is mapped . Different SoC have different addresses. The address is described in the device tree of the SoC / Board or in the datasheet.
|
|
SoC |
UDC |
at91sam9x5 |
500000.gadget |
sam9x60 |
500000.gadget |
sama5d3 |
500000.gadget |
sama5d4 |
400000.gadget |
sama5d2 |
300000.gadget |
|
|
|