USB Gadget

From linux-sunxi.org
Jump to: navigation, search

We can do all sorts of nifty things with a USB OTG connector. Here are some of them.

Contents

Introduction

The term "USB Gadget" will usually refer to the Linux USB gadget framework. This is relevant for those sunxi devices that offer a "On-The-Go" (OTG) port, allowing this USB connector to act in a "dual role" mode. (TODO: Add those devices to a list/category and link it here?)

The 'gadget' part means we're particularly interested in the slave mode - where the sunxi board will present itself as "device" to another USB host (e.g. a PC), allowing it to 'mimic' a wide variety of USB peripherals.

USB Ethernet support

This allows ethernet emulation over USB, allowing for all sorts of nifty things like SSH and NFS in one go plus charging over the same wire, at higher speeds than most Wifi connections.

Kernel support

Mainline kernel

See http://thread.gmane.org/gmane.comp.hardware.netbook.arm.sunxi/19214/focus=19215

(Instructions below were tested on A20 with kernel 4.4.6.)

For Allwinner SoCs based on the sun4i controller (CONFIG_PHY_SUN4I_USB=y), the "MUSB" (Multipoint Highspeed Dual-Role Controller) driver provides the OTG / gadget functionality. For successful operation, a number of Kconfig options need to be enabled:

CONFIG_USB_MUSB_HDRC=m
CONFIG_USB_MUSB_DUAL_ROLE=y
CONFIG_USB_MUSB_SUNXI=m
CONFIG_MUSB_PIO_ONLY=y
CONFIG_USB_PHY=y
CONFIG_NOP_USB_XCEIV=m

(Substitute "y" for "m" where desired, if you do not wish modules to be built and want the drivers compiled-in instead.)

With menuconfig this looks like

    Device Drivers  --->
        [*] USB support  --->
        <M> Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)
                MUSB Mode Selection (Dual Role mode)  --->
                *** Platform Glue Layer ***
            <M> Allwinner (sunxi)
                *** MUSB DMA mode ***
            [*] Disable DMA (always use PIO)
        USB Physical Layer drivers  --->
            <M> NOP USB Transceiver Driver
Sticky-note-pin.png Note: You need to select both "Inventra Highspeed Dual Role Controller" and "NOP USB Transceiver Driver" before the required "Allwinner (sunxi)" option (CONFIG_USB_MUSB_SUNXI) becomes available.

You'll probably also want to select

        <*> USB Gadget Support

and any desired gadget drivers on top of that.

Proceed with compiling and installing your kernel and its corresponding modules (for assistance check our howto).

MBOX icon information.png If you compiled the MUSB driver as module(s), make sure to load those first - before you attempt to use any of the gadget drivers:
modprobe sunxi

Upon successful initialization the kernel will report something similar to:

[   33.950832] usb_phy_generic.0.auto supply vcc not found, using dummy regulator
[   33.951799] musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, bulk combine, bulk split, HB-ISO Rx, HB-ISO Tx, SoftConn)
[   33.951833] musb-hdrc: MHDRC RTL version 0.0 
[   33.951872] musb-hdrc: 11/11 max ep, 5184/8192 memory
[   33.952312] musb-hdrc musb-hdrc.1.auto: MUSB HDRC host driver
[   33.952355] musb-hdrc musb-hdrc.1.auto: new USB bus registered, assigned bus number 5
[   33.956664] hub 5-0:1.0: USB hub found
[   33.956828] hub 5-0:1.0: 1 port detected

After that, you should be able to use the USB gadget drivers/modules (g_ether, g_mass_storage, ...) as described below.

sunxi-3.4

Currently, the g_ether module is not compiled as part of our kernel configuration.

To enable this, follow the kernel building information of our manual build howto. But then after making defconfig, either run:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

Then trawl down the options and set the "Ethernet Gadget" to "m":

    Device Drivers  --->
        USB support  --->
            <*>    USB Gadget Support  --->
                <m>    Ethernet Gadget (with CDC Ethernet support)
            <*>    NOP USB Transceiver Driver
            [*]    SUNXI USB2.0 Dual Role Controller support --->
                [*]    Sunxi USB2.0 Manager
                       USB0 Controller support (otg support) --->
                           (*) otg support

Or just run:

./scripts/config -m CONFIG_USB_ETH -e CONFIG_USB_ETH_RNDIS -e CONFIG_USB_OTG_UTILS -e CONFIG_NOP_USB_XCEIV 
 -e CONFIG_USB_SW_SUNXI_USB -e CONFIG_USB_SW_SUNXI_USB_MANAGER -e CONFIG_USB_SW_SUNXI_USB0_OTG

You can now continue following our manual build howto to continue kernel compilation and installation.

Note that for sun4i devices (A10), you also need to enable SoftWinner SUNXI USB peripheral controller in order to enable high-speed operation for gadget- otherwise it will be limited to full-speed only.

    Device Drivers  --->
        USB support  --->
            <*>     USB Gadget Support --->
                <m> SoftWinner SUNXI USB Peripheral Controller 

Loading the driver (on the device)

We should now be able to run:

modprobe g_ether

successfully. We can then make this module autoload by adding it to /etc/modules.

Now, so that g_ether doesn't randomly generate a new id every reboot, stick the following in /etc/modprobe.d/g_ether.conf:

options g_ether host_addr=00:11:22:33:44:55

g_ether should've just generated a pair of addresses for you, so replace 00:11:22:33:44:55 with the outcome of:

 dmesg | grep "HOST MAC"

We can also use dev_addr option to set device MAC address.

Configuring the device's networking

Ubuntu/Debian

Without network manager

Stop networkmanager:

 stop network-manager 

To prevent network-manager from starting, run:

echo "manual" > /etc/init/network-manager.override

Now add the following to /etc/network/interfaces:

auto usb0
iface usb0 inet static
	address 192.168.0.2
	netmask 255.255.255.0

To manually activate the interface and set an IP (NOTE: if configured with ip from iproute2 it will not work):

 ifconfig usb0 up
ifconfig usb0 192.168.0.2

Setting up the host

You can convince networkmanager to connect automatically to a specific MAC address, and then you need to hardcode the address to 192.168.0.1 for this connection.

If all goes well, you should now be able to just plug in the USB cable.

USB storage support

This allows your devices act as a USB mass storage like external hard drive or thumb drive.

Kernel support

Currently, the g_mass_storage module is not compiled as part of default kernel configuration.

To enable this, follow same kernel building information as previous section USB Ethernet support but instead of compiling "Ethernet Gadget", select the following to "m":

Device Drivers  --->
	USB support  --->
		USB Gadget Support  --->
			<M>     Mass Storage Gadget

You can now continue following manual build howto to continue kernel compilation and installation.


Preparing shared storage device

See "Backing Storage for the Mass Storage Gadget" for full instructions and recommendations.

Be aware that shared storage cannot be used in "read write" mode if both systems (device and host) are using it at same time except if you accept to corrupt your data...

An existing physical partition or a logical volume can be used as shared storage device; another option is to use a flat file as shared storage.

Creating a sparse file

Use "dd" command's "count" and "seek" options to create a 1GB file that will not use storage until it is used:

# dd if=/dev/zero of=/mass_storage bs=1M seek=1024 count=0
# ls -l /mass_storage 
-rw-r--r-- 1 root root 1073741824 Feb 15 16:40 /mass_storage
# du -hs /mass_storage 
0       /mass_storage

Partitioning and formatting sparse file

To be recognized by most Operating Systems, create a single FAT type partition and format it as DOS filesystem using Linux loop device driver.

Create a single partition

# cat <<EOT | sfdisk --in-order -L -uM /mass_storage 
,,c
EOT

Find partition offset

# fdisk -lu /mass_storage 

Disk /mass_storage: 1073 MB, 1073741824 bytes
139 heads, 8 sectors/track, 1885 cylinders, total 2097152 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

	Device Boot      Start         End      Blocks   Id  System
/mass_storage1               1     2097151     1048575+   c  W95 FAT32 (LBA)

First partition starts at first sector: offset = 1 * 512 = 512 bytes

Set up loop device

# losetup -o512 /dev/loop0 /mass_storage
# losetup -a
/dev/loop0: [b302]:14867 (/mass_storage), offset 512

Format device

# apt-get install dosfstools
# mkdosfs /dev/loop0


Test device

# mount -t vfat /dev/loop0 /mnt/
# df -h /mnt
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop0     1022M  4.0K 1022M   1% /mnt
# mount | grep mnt
/dev/loop0 on /mnt type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=cp437,iocharset=ascii,shortname=mixed,errors=remount-ro)

Release device

# umount  /mnt/
# losetup -d /dev/loop0 
# losetup -a

As we can see below, 1GB sparse file is only using 2.1MB storage (size of filesystem metadata):

# du -sh /mass_storage 
2.1M    /mass_storage
# ls -lh /mass_storage 
-rw-r--r-- 1 root root 1.0G Feb 15 16:54 /mass_storage


Exporting mass storage / Loading the driver (on the device)

It looks like g_mass_storage conflicts with g_ether, remove g_ether first (if previously loaded):

# modprobe -r g_ether

Load g_mass_storage specifying storage to share (can also be a physical partition or a logical volume):

# modprobe g_mass_storage file=/mass_storage

We can now plug device to another host and use it as USB connected storage.

Notes: Surprisingly it works well my Mac OS hosts (device automatically appears in Finder, I can copy and read files) but not with my Linux hosts (device appears and disappears constantly and cannot be mounted). Not tested with Windows hosts.

Emulating a USB CD-ROM

The g_mass_storage module can also present an optical drive to the USB host. For this, your backing storage should be a suitable filesystem image - usually an .ISO file. Pass a "cdrom" module option like this:

# modprobe g_mass_storage file=/path/to/your-image-file.iso cdrom=y

(This can be useful with old PCs where the BIOS may have trouble starting from USB sticks, but supports booting via USB-CDROM.)

Sticky-note-pin.png Note: As of Linux v4.7-rc2, the g_mass_storage driver can only emulate CD-ROM drives, not DVD-ROMs.

That means some restrictions, especially a hardcoded limit on the size of a backing (.iso) file. In case the file size exceeds 1152000 2KiB blocks (approx. 2.36GB / 2.2GiB), the driver will complain "file too big" and limit the usable range (sector count). If the filesystem driver on the USB host requests any sector beyond that, it will encounter I/O errors ("attempt to access beyond end of device").
In order to use larger images and properly emulate DVD media, the g_mass_storage would have to be extended. Some ideas and patches for that have been around for a while, e.g. https://lkml.org/lkml/2015/3/7/388 and http://linuxehacking.blogspot.de/2013/07/how-to-emulatore-dvd-rom-hardware-usb.html.

USB MIDI support

This allows your device to act as a MIDI USB client. The connection is set up as a separate ALSA sound card with MIDI port.

Kernel Configuration

Enable the module in the kernel config (it's not enabled by default):

    Device Drivers  --->
        USB support  --->
            <*>    USB Gadget Support  --->
                <m>    MIDI Gadget (EXPERIMENTAL)

Make sure you also have the ALSA MIDI seqencer support enabled:

    Device Drivers  --->
        Sound Card support  --->
            Advanced Linux Sound Architecture  --->
                <M>   Sequencer support

Loading the driver

Load the midi gadget driver with:

modprobe g_midi

If it responds with a "device or resource busy" message, then you probably already have an ALSA sound card registered with index 0. You can specify the index via the module options, simply choose the next free index:

modprobe g_midi index=1

Known Error Messages

If you see the following message

WRN:L2385(drivers/usb/sunxi_usb/udc/sw_udc.c):ERR: sw_udc_queue: inval 2

it means that you attempted to send a MIDI message via the MIDI gadget without it being connected to a host. Just plug in the USB cable (or unplug and retry if the first registration failed) and the error should go away.

Possible security implications

MBOX icon important.png The ability to act as a wide range of USB peripherals, with device behavior that can be customized to a very large degree, may have security implications for the USB host.

See e.g. https://en.wikipedia.org/wiki/Firmware#Security_risks, or search for "BadUSB".

Personal tools
Namespaces

Variants
Actions
Navigation
Tools