How to use USB CDC ACM and MS composite Linux gadget driver

From RidgeRun Developer Wiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.


Introduction

This document explains the Communications Device Class (CDC) Abstract Control Model (ACM) + Mass Storage (MS) composite Linux gadget driver and how to use it with a Linux host PC and a Windows host PC.

CDC ACM + MS Linux gadget driver

The CDC ACM + Linux gadget MS driver is a USB composite gadget driver which implements the serial communication and mass storage functions. This allows the device to be registered on a host computer as a seral port (e.g. /dev/ttyACM0 or COM1:) and as a USB thumb drive (e.g. /dev/sdf or E:). The composite driver allows for simultaneous use of the serial and mass storage functions.

Driver support

The CDC ACM only driver that comes with the Linux kernel is supported on both Linux and Windows. For Windows it is necessary the use of the following INF file:

http://www.kernel.org/doc/Documentation/usb/linux-cdc-acm.inf

Our experience shows the CDC ACM + MS composite USB driver is not well supported on Windows with this INF file. We have tested with a propretary solutions from Thesycon, with a demo version available at

Linux host computers have full support for the CDC ACM + MS composite USB drivert without the need of additional files.

Using CDC ACM + MS device with Linux host

Linux host device file identification

The following description is based on the host computer running Linux Ubuntu 10.04 LTS.

Once you attached the device, inspect the log to obtain the device file names used on the host.


dmesg | tail -n 20

Jan 31 14:19:34 mmadrigal kernel: [109059.420096] usb 1-3: new high speed USB device using ehci_hcd and address 16
Jan 31 14:19:34 mmadrigal kernel: [109059.553321] usb 1-3: configuration #1 chosen from 1 choice
Jan 31 14:19:34 mmadrigal kernel: [109059.562570] cdc_acm 1-3:1.0: ttyACM0: USB ACM device
Jan 31 14:19:34 mmadrigal kernel: [109059.567214] scsi8 : SCSI emulation for USB Mass Storage devices
Jan 31 14:19:35 mmadrigal kernel: [109060.604592] usb 1-3: USB disconnect, address 16
Jan 31 14:22:58 mmadrigal kernel: [109262.944049] usb 1-3: new high speed USB device using ehci_hcd and address 17
Jan 31 14:22:58 mmadrigal kernel: [109263.077362] usb 1-3: configuration #1 chosen from 1 choice
Jan 31 14:22:58 mmadrigal kernel: [109263.088675] cdc_acm 1-3:1.0: ttyACM0: USB ACM device
Jan 31 14:22:58 mmadrigal kernel: [109263.123308] scsi9 : SCSI emulation for USB Mass Storage devices
Jan 31 14:23:13 mmadrigal kernel: [109278.133699] scsi 9:0:0:0: Direct-Access     Linux    File-CD Gadget   0316 PQ: 0 ANSI: 2
Jan 31 14:23:13 mmadrigal kernel: [109278.142902] sd 9:0:0:0: Attached scsi generic sg6 type 0
Jan 31 14:23:13 mmadrigal kernel: [109278.150041] sd 9:0:0:0: [sdf] Attached SCSI removable disk

The serial communication port has been registed as 'ttACM0', meaning it will show up as '/dev/ttyACM0'. The mass storage device have been registered as 'sdf', meaning it will show up as '/dev/sdf'.

How to test the serial driver in Linux

In order to test the serial function on Linux you should need to install picocom

sudo apt-get install picocom

and use the picocom terminal emulator to display data received over the USB serial connection:

picocom /dev/ttyACM0

In order to send data from the target device we need to use the USB serial gadget driver device file '/dev/ttyGS0'. We can echo command to send data from the device to the Ubuntu host computer:

echo foo > /dev/ttyGS0

After that you should see the text foo on picocom's output.

In a similar way, if we want to send data from the host computer to the device we should first send the data on the host by running

echo hello > /dev/ttyACM0

and read it on the device

cat /dev/ttyGS0

How to use the mass storage function in Linux

Once the Linux gadget driver has been installed correctly we just need to mount the SD card on the device in order to get the mass storage device ready. In order to do that we just need to run the following commands on the target device:

  • Mount the MMC partition
echo /dev/mmcblk0p2 >  /sys/devices/platform/musb_hdrc/gadget/lun0/file
  • On the Ubuntu PC open the external media device, now you have access to the MMC card on your device.


Using CDC ACM + MS device with Windows 7 host

When using the device on Windows, you need to use a INF file in order to load the appropriate driver. There is an INI file avaiable (see above), but it didn't work for use on Windows 7 with a CDC ACM + MS device. Instead we used the proprietary driver from Thesycon.

Thesycon provides a demo version of the driver [1] that can be installed on Windows. By default it creates a directory on C:\Thesycon\CdcAcm\V1.96.0_Demo\. There is an INI file and a SYS driver in the idisk sub-directory you can use to exchange USB serial data with the target device.

In order use the INF file provided it is necessary to add the VID (Vendor ID) and PID (Product ID) of the target device to the file; look for the following piece of code into the file:

[_Devices.ntamd64]
; enter your VID (VVVV) and PID (PPPP) here
%S_DeviceDesc1%=Install,USB\VID_VVVV&PID_PPPP

Replace the USB\VID_VVVV&PID_PPPP string with the corresponding VID and PID. In addition we need to specify the interface on which the serial function is located since it is a composite device. For example, the following uses the Linux Foundation (VID = 0x1D6B) device with a PID = 0x0104 (Multifunction Composite Gadget). We assume the serial interface is located in the interface 1, so the piece of code shown above should be replaced by:

[_Devices.ntamd64]
; enter your VID (VVVV) and PID (PPPP) here
%S_DeviceDesc1%=Install,USB\VID_1D6B&PID_0104&MI_01

where MI_01 means the serial interface is on interface 1.

Once the edited INF file is read, just plug the device to the Windows host computer. Windows will try to locate a usable driver. When it asks for the driver just point it to the folder where the modified INF file resides and Windows will do the rest.


If Windows doesn't ask for it but still fails on the installation you can install the driver by:

  1. Go to Start -> Control panel -> Devices and printers"
  2. Right click on the composite device.
  3. Properties -> Hardware.
  4. Select the CDC ACM Data function.
  5. Properties
  6. Change configuration
  7. Update firmware
  8. Point it to the folder containing the INF file and then wait to the driver to be installed.

Once Windows announces the driver was installed correctly, the device is ready to use.

Using the Windows 7 serial port

In order to use the serial function you can install TeraTerm on your Windows machine and launch the TeraTerm application. On first dialog TeraTerm will ask for the connection properties as is shown on figure 1, be sure to select Serial and the port corresponding to your composite device.

Figure 1. TeraTerm initial screen.

After selecting the appropriated port, TeraTerm will open the connection with the device.

To send data from the device to your host PC run the following command on the target device:

echo foo > /dev/ttyACM0

You should be able to see the text foo in the TeraTerm window.

To send data from Windows to the device write any word on your TeraTerm's window and press ENTER and then run the following command on the device:

cat /dev/ttyACM0

You should be able to see the string on your target device console.

How to use the mass storage function in Windows 7

Once the Linux gadget driver has been installed correctly we just need to mount the SD card on the device in order to get the mass storage device ready. In order to do that we just need to run the following commands on the target device:

  • Mount the MMC partition
echo /dev/mmcblk0p2 >  /sys/devices/platform/musb_hdrc/gadget/lun0/file
  • On the Windows PC open the external media device, now you have access to the MMC card on your device.

Mass Storage Performance Test

A 4GB file was created on the LeopardeBoard using "dd". The file was transmitted from a LeopardBoard to a Ubuntu PC using the USB composite driver. The transmitted file and the file at the LeopardBoard where compared using the sha1sum, both numbers where the same indicating that the USB file transfer didn't corrupted the data.

The average LeopardBoard-to-host transmission speed was approximately 3.5MB/s.

Mass storage endurance test

To keep from wearing out NAND or an SD card, we will use a VFAT file system contained in a file in tmpfs. Change VFAT_FILE to point to a file on NAND or SD card if that is your preference.

On the target, setup a 10Mbyte VFAT file system with some files and allow it to be mounted over USB:

VFAT_FILE=/tmp/vfat.file
VFAT_MNT=/tmp/vfat.fs

dd if=/dev/zero of=$VFAT_FILE bs=4096 count=$(( 10 * 1024 * 1024 / 4096 ))
ls -l $VFAT_FILE
mkfs.vfat $VFAT_FILE

mkdir -p $VFAT_MNT
mount $VFAT_FILE $VFAT_MNT
df -h $VFAT_MNT

dd if=/dev/urandom of=$VFAT_MNT/10k bs=10240 count=1
dd if=/dev/urandom of=$VFAT_MNT/5k bs=5120 count=1
dd if=/dev/urandom of=$VFAT_MNT/1k bs=1024 count=1
ls -l $VFAT_MNT
umount $VFAT_MNT # remember, host cannot mount the file system using USB MS if target has it mounted

modprobe g_cdc_ms removable=y luns=1
echo $VFAT_FILE > /sys/devices/platform/musb_hdrc/gadget/lun0/file

Once the USB cable is connected to the host, your host should automount the VFAT file system and show the 3 files created.

Test host only access to USB mass storage file system with USB cable always connected

On the host, run the following endurance test:

TARGET_DEV=/dev/sdh # USB mass storage device file

TARGET_VFAT=/media/vx2-storage
TEST_FILE=/tmp/testfile5M
TARGET_FILE=$TRAGET_VFAT/`basename $TEST_FILE`

dd iflag=fullblock if=/dev/urandom of=$TEST_FILE.master bs=4096 count=$(( 5 * 1024 * 1024 / 4096 ))
sudo umount $TARGET_DEV
sudo mkdir -p $TARGET_VFAT

# the following command will each each command before executing
#set -x

LOOP_COUNT=0
UPLOAD_ERROR_COUNT=0
DOWNLOAD_ERROR_COUNT=0

while echo "LOOP_COUNT: $LOOP_COUNT ; UPLOAD_ERROR_COUNT: $UPLOAD_ERROR_COUNT ; DOWNLOAD_ERROR_COUNT: $DOWNLOAD_ERROR_COUNT" ; do
	# copy file to target
	sudo mount -t vfat $TARGET_DEV $TARGET_VFAT
	sudo cp $TEST_FILE.master $TARGET_FILE.tmp
	sudo mv $TARGET_FILE.tmp $TARGET_FILE
	sync
	sudo umount $TARGET_DEV
	sleep 2

	# compare file on target 
	sudo mount -t vfat $TARGET_DEV $TARGET_VFAT
	sudo cmp $TEST_FILE.master $TARGET_FILE || ( echo "Failed on comparison copied to target" ; UPLOAD_ERROR_COUNT=$(( $UPLOAD_ERROR_COUNT + 1 )) )
	sudo umount $TARGET_DEV
	sleep 2

	# copy file back to host and compare
	# note: if compare failed on upload, it will fail again on the copy back
	sudo mount -t vfat $TARGET_DEV $TARGET_VFAT
	sudo cp $TARGET_FILE $TEST_FILE
	sudo rm $TARGET_FILE
	sudo cmp $TEST_FILE.master $TEST_FILE || ( echo "Failed on comparison copying back from target" ; DOWNLOAD_ERROR_COUNT=$(( $DOWNLOAD_ERROR_COUNT + 1 )) )
	sudo rm $TEST_FILE
	sudo umount $TARGET_DEV
	sleep 2

	LOOP_COUNT=$(( $LOOP_COUNT + 1 ))
done

Test host and target accessing to USB mass storage file system with USB cable always connected

For this endurance test,

  • the target will create a file and a sha1sum
  • the host will download the file and the sha1sum
  • the host will calculate the sha1sum for the downloaded file and compare it to the sha1sum calculated by the target
  • created files will be delete and the process repeated

Make sure you stop any applications running on the target that will interfere with USB serial communication. On target, update inittab and then have init reread the modified file to allow a shell to exist on USB ACM serial port.

modprobe g_cdc_ms removable=y luns=1
echo 'ttyGS0::askfirst:-/bin/sh' >> /etc/inittab
kill -HUP 1 # causes init to reload /etc/inittab

On the host side setup so it is easy to send commands the run on the target. To keep USB ACM from sending open / close indications to the shell running on ttyGS0, I just run picocom in another window. We can still send commands to the target using /dev/ttyACM0.

sudo chmod ugo+rw /dev/ttyACM0
picocom /dev/ttyACM0 

Now open another terminal and send some commands to the shell running on the target. The responses to your commands will be displayed in picocom:

echo "ls" >> /dev/ttyACM0

# make our life easy make a target sh command tsh
function tsh() { echo "$*" >>  /dev/ttyACM0 ; }

tsh ls

# create vfat file system on target

Create the file with the VFAT file system:

tsh dd if=/dev/zero of=/tmp/vfat.file bs=4096 count=$(( 10 * 1024 * 1024 / 4096 ))
tsh mkfs.vfat /tmp/vfat.file
tsh mkdir -p /tmp/vfat.fs

A /bin/redirect helper script is needed on the target (there may be more elegant solutions)

#!/bin/sh
$1 $2 > 3

and allow the script to be executed

chmod ugo+x /bin/redirect

Now we have the pieces in place to write the test.

TARGET_DEV=/dev/sdh # USB mass storage device file
TARGET_VFAT=/media/vx2-storage

COUNT=0
ERROR_COUNT=0
while echo COUNT $COUNT ERROR_COUNT $ERROR_COUNT ; do
	# on the target will create a file and a sha1sum
	tsh mount -t vfat /tmp/vfat.file /tmp/vfat.fs
	tsh dd iflag=fullblock if=/dev/urandom of=/tmp/vfat.fs/random.5M bs=4096 count=$(( 5 * 1024 * 1024 / 4096 ))
	sleep 15 # takes a while to make the file
	tsh redirect sha1sum /tmp/vfat.fs/random.5M /tmp/vfat.fs/random.5M.sha1sum
	sleep 5
	tsh umount /tmp/vfat.fs
	sleep 5
	tsh redirect echo /tmp/vfat.file /sys/devices/platform/musb_hdrc/gadget/lun0/file
		
	# the host will download the file and the sha1sum
	sudo mount -t vfat $TARGET_DEV $TARGET_VFAT
	mkdir -p /tmp/vfat.fs
	cp $TARGET_VFAT/random.5M $TARGET_VFAT/random.5M.sha1sum /tmp/vfat.fs

	# the host will calculate the sha1sum for the downloaded file and compare it to the sha1sum calculated by the target
	sha1sum -c /tmp/vfat.fs/random.5M.sha1sum  || ( echo "Failed on comparison" ; ERROR_COUNT=$(( $ERROR_COUNT + 1 )) )

	# created files will be delete and the process repeated
	rm $TARGET_VFAT/random.5M $TARGET_VFAT/random.5M.sha1sum
	rm -rf /tmp/vfat.fs
	sudo umount $TARGET_DEV 
	COUNT=$(( $COUNT + 1 ))
done


RidgeRun Resources

Quick Start Client Engagement Process RidgeRun Blog Homepage
Technical and Sales Support RidgeRun Online Store RidgeRun Videos Contact Us
RidgeRun.ai: Artificial Intelligence | Generative AI | Machine Learning

Contact Us

Visit our Main Website for the RidgeRun Products and Online Store. RidgeRun Engineering informations are available in RidgeRun Professional Services, RidgeRun Subscription Model and Client Engagement Process wiki pages. Please email to support@ridgerun.com for technical questions and contactus@ridgerun.com for other queries. Contact details for sponsoring the RidgeRun GStreamer projects are available in Sponsor Projects page.