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 using your target as a USB serial port.
Loading the serial gadget
Load the serial gadget driver module (full details at Documentation/usb/gadget_serial.txt):
~# 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:
-
Configure the serial port of the host computer:
~# stty -F /dev/ttyACM0 raw -echo -echoe -echok -echoctl -echoke
-
Configure the serial port of the target platform:
~# stty -F /dev/ttyGS0 raw -echo -echoe -echok -echoctl -echoke
-
On the host, read the contents arriving at the new serial port:
~$ cat /dev/ttyACM0
-
On the target, write a text line to the serial port:
~# 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.
-
On the target side, execute a console on the serial gadget with the getty command (baudrate is mandatory but irrelevant):
~# setsid getty -L -l /bin/sh -n 115200 /dev/ttyGS0
The setsid command avoids permission problems when running getty from an interactive shell.
-
On the host side, open a minicom or putty session on the USB serial port /dev/ttyACM0 to access the shell.
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:
~# 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:
~# 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:
~# 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:
~$ 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:)
~$ 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 32 MiB in the root directory of the target:
~# dd bs=1M count=32 if=/dev/zero of=/backing_file
32+0 records in
32+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 32 MiB storage file, we can use values of:
Cylinders = 32
Heads = 16
Sectors = 128
So that 512*32*16*128 = 32 MiB
On the target we run fdisk with the CHS values over the backing file:
~# fdisk -C 32 -H 16 -S 128 /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:
-
Press n for "new".
-
Press p for "primary".
-
Press 1 for partition number 1.
-
Press INTRO to accept default values for any remaining parameters.
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-65, default 1): Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-65, default 65): Using default value 65
The new partition is created by default as a Linux (ext4 file system) partition. To change the partition type to FAT32:
-
Press t for "type".
-
Press b to select Win95 FAT32 file system.
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:
Command (m for help): p
Disk backing_file: 33 MB, 33554432 bytes
16 heads, 63 sectors/track, 65 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
Device Boot Start End Blocks Id System
backing_file1 1 65 32728+ b Win95 FAT32
Press w to write out the partition table to the backing storage:
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:
~# 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:
~$ 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] 65536 512-byte logical blocks: (33.5 MB/32.0 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):
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.
~$ mkfs.vfat /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):
~$ 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 32 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:
~$ 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 32 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:
~# 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:
~# 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:
~# 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