Using the USB port (as device)

When working as USB device, the embedded platform may connect to a development computer and work as any previously loaded profile such as a serial port, network card, or mass-storage device. The USB device driver exposes the connected devices through the file system at /dev/bus/usb/. The interface can expose different USB device gadgets.

Serial gadget

The serial gadget exposes a TTY-style serial line interface, usable with minicom and similar tools. Most Linux hosts can talk to this interface using the generic usb-serial driver. The latest versions of this driver implement the CDC ACM class. This driver works with MS-Windows usbser.sys driver, the Linux cdc-acm driver, and many other USB host systems.

For detailed information on how to set up the driver on both Windows and Linux systems, see Documentation/usb/gadget_serial.txt. Follow the instructions in this file for exposing your target as a serial port to the eyes of a USB host.

Loading the serial gadget

Load the serial gadget driver module (full details at Documentation/usb/gadget_serial.txt):

Target device
# modprobe g_serial

Connect the target platform to a Linux host computer via the USB cable. Linux will create a device node called /dev/ttyGS0 on the target side and a device node called /dev/ttyACM0 on the host side. (Node names may vary in different distributions.)

The USB connection between target and host now works as a serial line.

Testing the serial gadget

You can verify the serial connection of the two ports:

Host PC
$ stty -F /dev/ttyACM0 raw -echo -echoe -echok -echoctl -echoke
Target device
# stty -F /dev/ttyGS0 raw -echo -echoe -echok -echoctl -echoke
Host PC
$ cat /dev/ttyACM0
Target device
# echo "Hello from target side" > /dev/ttyGS0

You will see the text line arrive at the host computer.

Opening a console shell via USB serial

The following instructions describe how to open a console shell via the USB serial port.

Target device
# setsid getty -L -l /bin/sh -n 115200 /dev/ttyGS0

The setsid command avoids permission problems when running getty from an interactive shell.

Note Settings like speed or parity for the serial terminal session (and for the getty command) are irrelevant, as the communication takes place at USB speed. The serial communication settings are emulated.

Unloading the serial gadget

To unload the USB serial gadget from the system:

Target device
# rmmod g_serial
# rmmod usb_f_acm
# rmmod libcomposite

Ethernet gadget

With the Ethernet gadget, the target platform enumerates to the host computer as an Ethernet device. It uses the usbnet driver on Linux hosts or Microsoft's RNDIS driver on Windows hosts.

Loading the Ethernet gadget

To load the Ethernet gadget:

Target device
# modprobe g_ether
using random self ethernet address
using random host ethernet address
usb0: HOST MAC 4a:94:3b:db:4a:1b
usb0: MAC 7a:2d:fe:26:3f:a1
using random self ethernet address
using random host ethernet address
g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
g_ether gadget: g_ether ready
g_ether gadget: high-speed config #1: CDC Ethernet (ECM)

Linux creates an Ethernet interface in the target called usb0 and assigns random MAC addresses to the target and the host.

The last line appears when you connect the USB cable between the target and the host. Connect it now if you haven't done so already.

Configuring the Ethernet interface on the target

Give the network interface usb0 an IP address, for example:

Target device
# ifconfig usb0 192.168.44.30 netmask 255.255.255.0

Configure the Ethernet interface on the host computer

Linux hosts

Load the usbnet driver on the host:

Host PC
$ sudo modprobe usbnet

Linux creates an Ethernet interface on the host side, also called usb0.

Give this new Ethernet interface an IP address in the same subnet as the target's IP address. (The following command requires root permissions:)

Host PC
$ sudo ifconfig usb0 192.168.44.1 netmask 255.255.255.0

Now the target can be accessed via the USB cable as if it was an Ethernet port. You can send a ping or open a telnet session from the host to the target, or vice versa.

Windows hosts

Connect the USB cable from the target to an MS-Windows host computer. MS-Windows detects a new USB RNDIS/Ethernet Gadget, installs the appropriate driver, and creates a new network adapter on the system.

Configure the IP address of this network adapter by going to Control Panel > Network and Internet > Network Connections. Set, for example, an IP address of 192.168.44.1, subnet mask 255.255.255.0.

Now the target can be accessed via the USB cable as if it was an Ethernet port. You can send a ping or open a telnet session from the host to the target, or vice versa.

Unloading the Ethernet gadget

To unload the USB Device gadget:

# rmmod g_ether
# rmmod usb_f_rndis
# rmmod usb_f_ecm
# rmmod libcomposite

Mass-storage gadget

With the mass-storage gadget, the target platform enumerates to the host computer as a SCSI disk drive. A file or block device can be used as a backing store for the drive.

Using a file as backing storage

Creating a backing storage file

You must prepare the backing storage file before the gadget can use it. The backing storage is a regular file that must be created with its full desired size. This must be done before loading the gadget driver, but it only has to be done once.

The following example shows how to create a backing file of 128 MiB in the root directory of the target:

Target device
# dd bs=1M count=128 if=/dev/zero of=/backing_file
2+0 records in
2+0 records out

Partitioning the backing storage

Creating the backing storage file is like having a raw disk; you still need to create partitions and install a file system before you can use it.

Use the fdisk program to partition the backing file and to specify the values of Cylinders, Heads, and Sectors of the backing file. These values are arbitrary, but since the storage gadget driver uses a sector size of 512 bytes, the formula is:

512 * Cylinders * Heads * Sectors = Total bytes of backing file storage

For our example of 128 MiB storage file, we can use values of:

Cylinders = 32

Heads = 16

Sectors = 512

So that 512*32*16*512 = 128 MiB

On the target we run fdisk with the CHS values over the backing file:

Target device
# fdisk -C 32 -H 16 -S 512 /backing_file
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that the previous content
won't be recoverable.
 
 
Command (m for help):

To create a primary partition that occupies the full size of the backing file:

Target device
Command (m for help): n
Command action
    e   extended
    p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-260, default 1):
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-260, default 260):
Using default value 260

The new partition is created by default as a Linux (ext4 file system) partition. To change the partition type to FAT32:

Target device
Command (m for help): t
Selected partition 1
Hex code (type L to list codes): b
Changed system type of partition 1 to b (Win95 FAT32)

Press p to print the partition table details and verify everything is correct:

Target device
Command (m for help): p
 
Disk backing_file: 134 MB, 134217728 bytes
16 heads, 63 sectors/track, 260 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
 
       Device Boot      Start         End      Blocks  Id System
backing_file1               1          260     131008+  b Win95 FAT32

Press w to write out the partition table to the backing storage:

Target device
Command (m for help): w
The partition table has been
altered!
 
Calling ioctl() to re-read partition table.
fdisk: WARNING:
rereading partition table failed, kernel still uses old table: Inappropriate
ioctl for device

At this point, the partition has been created but it doesn't hold a file system yet.

The easiest way to create a file system in the partition is to load the driver, connect the USB cable to the host PC, and create the file system on the recently created partition from the host computer.

Loading the mass-storage gadget

On the target, load the driver with:

Target device
# modprobe g_mass_storage file=/backing_file stall=no
LUN: removable file: (no medium)
Number of LUNs=1
LUN: file: /backing_file
Number of LUNs=1
g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11
g_mass_storage gadget: userspace failed to provide iSerialNumber
g_mass_storage gadget: g_mass_storage ready
g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage

The last line appears when you connect the USB cable between the target and the host. Connect it now if you haven't done so already.

Creating and mounting the file system

Linux hosts

A Linux host computer recognizes the target as a new SCSI device. Linux assigns a device node in the form sdx, where x is a letter index, and the partition appears as sdx1. To see exactly which device the host assigned, print out the system log messages with:

Host PC
$ dmesg
usb 2-1.1: new high-speed USB device number 10 using ehci_hcd
usb-storage 2-1.1:1.0: Quirks match for vid 0525 pid a4a5: 10000
scsi9 : usb-storage 2-1.1:1.0
usb 2-1.3: USB disconnect, device number 3
scsi 9:0:0:0: Direct-Access     Linux    File-Stor Gadget 0314 PQ: 0 ANSI: 2
sd 9:0:0:0: Attached scsi generic sg2 type 0
sd 9:0:0:0: [sdb] 262144 512-byte logical blocks: (134 MB/128 MiB)
sd 9:0:0:0: [sdb] Write Protect is off
sd 9:0:0:0: [sdb] Mode Sense: 0f 00 00 00
sd 9:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
sdb: sdb1
sd 9:0:0:0: [sdb] Attached SCSI disk

In the example, the host assigned sdb1 as the device node for the partition of our backing file.

On the host, create a VFAT file system into that partition (you might need root permissions):

Host PC
When formatting a device on your Host PC, verify that the device node dev/sdX corresponds to the connected USB device and not to your PC hard disk. Running the mkfs.vfat command on the wrong device node might format your hard disk.

Host PC
$ mkfs.vfat -F 32 /dev/sdb1

Now, mount the device in the host so the host has read/write access to it. If your host PC is prepared to automatically mount devices, you can simply disconnect the USB cable and connect it again. After a few seconds, the PC automatically detects and mounts the device as a USB storage drive, with the size of the partition we created. Initially, the disk is empty.

If the PC doesn't auto mount the device you need to do it by hand (you might need root permissions):

Host PC
$ mkdir /media/usbdisk
$ mount /dev/sdb1 /media/usbdisk -t vfat

In this example we've mounted the device into the folder /media/usbdisk. Now we can create files and folders within this folder.

The placeholder for the files and folders that we create in this folder is the 128 MiB file /backing_file that we created in the first steps.

As with other USB devices, before removing the USB cable you need to unmount this folder:

Host PC
$ umount /media/usbdisk

Windows hosts

An MS-Windows host computer recognizes the target as a new USB mass storage device. A warning message appears to inform you that the disk is not yet formatted. Click Yes to enter the formatting tool.

Select FAT file system and an optional volume label (less than 11 characters). Then click Start.

Once the volume has been formatted with FAT file system you can use it as any other removable media and create folders, copy files, etc.

The placeholder for the files and folders that we create in the unit is the 128 MiB file /backing_file that we created in the first steps.

Using a block device as backing file

An alternative to using a backing file is to use an existing block device like a Compact Flash card, an SD card, a USB stick, or even a Flash partition. For example, if you have plugged in an SD card that contains two partitions, the Linux system on the target will have populated them similar to this:

Target device
# ls -l /dev/mmc*
brw-rw----    1 root     root     179,   8 Jan  7 22:28 /dev/mmcblk1
brw-rw----    1 root     root     179,   9 Jan  7 22:19 /dev/mmcblk1p1
brw-rw----    1 root     root     179,  10 Jan  7 22:19 /dev/mmcblk1p2

where mmcblk1 is the card and mmcblk1p1 and mmcblk1p2 are the partitions.

Unmount the block device on the target

When using a block device for the file storage gadget, we recommended you first unmount the media on the target side. Otherwise, access from the host won't be synchronized with accesses from the target, as the system would behave like having the same media mounted twice in different mount points.

Make sure any partitions of the block device are unmounted, for example:

Target device
# umount /dev/mmcblk1p1
# umount /dev/mmcblk1p2

Load the mass-storage gadget

Load the mass-storage gadget passing the block device node (in the example the SD card device node) as backing file:

Target device
# modprobe g_mass_storage file=/dev/mmcblk1 stall=0
Number of LUNs=8
Mass Storage Function, version: 2009/09/11
LUN: removable file: (no medium)
Number of LUNs=1
LUN: file: /dev/mmcblk1
Number of LUNs=1
g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11
g_mass_storage gadget: userspace failed to provide iSerialNumber
g_mass_storage gadget: g_mass_storage ready
g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage

Now, when you connect the USB cable to a host computer, the two partitions of the SD card will be accessible from the host.

Unloading the mass-storage gadget

To unload the USB mass-storage gadget from the system:

# rmmod g_mass_storage
# rmmod libcomposite