Quantcast
Channel: CodeSection,代码区,Linux操作系统:Ubuntu_Centos_Debian - CodeSec
Viewing all articles
Browse latest Browse all 11063

Raspberry Pi Zero as Multiple USB Gadgets

$
0
0

In case you haven’t heard, the Raspberry Pi Zero is the smallest, most low-cost device in the Raspberry Pi family, but it’s also the hardest to find. It has two Micro-B USB ports, one for power and another functions as a dual-role USB OTG port.


Raspberry Pi Zero as Multiple USB Gadgets

One of the more interesting uses for the Raspberry Pi Zero is to get it to behave as a USB device, just like your USB flash drive, for example.

There have been several guides written already, such as the Adafruit one , but most of them were based on the old kernel gadget drivers , like g_serial and g_ether . It still works, but not as flexible and likely to be deprecated in future.

Newer guides like this one on iSticktoit and another one by Andrew Nicolaou explain how to use ConfigFS to create various type of gadgets. The same approach is used to setup the USB Armory , which was designed to be a USB device stick.

What’s with all this FS?

A short history on USB gadget support in the linux kernel:

2003: USB gadget framework: monolithic kernel modules like g_ether 2003: GadgetFS 2008: composite framework: multi-function (composite) gadget drivers 2010: FunctionFS 2013: ConfigFS for USB gadgets we are here

For a better introduction of the USB gadgets history, refer to Matt Porter’s presentation on “Kernel USB Gadget Configfs Interface” .

ConfigFS is a pseudo filesystem, not unlike procfs and sysfs, that allows for userspace to create and configure kernel objects. The USB gadget framework decided to make use of ConfigFS to allow gadgets to be created and composed from userspace.

The USB gadget framework has evolved a fair bit since its inception. I would think its due to contributions from Android device manufacturers, since that’s a common use case for Android phones & tablets. These devices primarily act as USB devices when plugged in, to provide functions such as MTP , PTP and ADB to the host computer.

Setting it Up

You can do all of this without a serial cable, but having one really helps because it’s a low-level (and bi-directional) means of communicating with the Pi Zero. Here, I’ve wired up the UART pins to connect to an FTDI serial cable. This is what I used to get a shell on the Pi Zero for debugging before I got the USB gadgets working.

Remember that the serial voltage levels must be 3.3V instead of 5V. You don’t want to fry your Pi.


Raspberry Pi Zero as Multiple USB Gadgets

We want the Pi Zero to enumerate as a USB device with (at least) 2 functions:

Serial port , so we don’t need to use the GPIO headers Network “Ethernet” device , so we can update the OS conveniently

The way to do this has been described so many times in various guides, so I’ll just go through this quickly. For more details, you can refer to the new ConfigFS style guides mentioned above.

Basically you need to…

load the dwc2 device tree overlay by editing config.txt , load the libcomposite kernel module, create a script that sets up the USB gadgets via ConfigFS, start that script at boot up using a systemd unit file.

With a very minimal script such as the one below, placed in /usr/bin/myusbgadget , a composite USB gadget can be created to our specifications:

#!/bin/bash -e modprobe libcomposite cd /sys/kernel/config/usb_gadget/ mkdir g && cd g echo 0x1d6b > idVendor # Linux Foundation echo 0x0104 > idProduct # Multifunction Composite Gadget echo 0x0100 > bcdDevice # v1.0.0 echo 0x0200 > bcdUSB # USB 2.0 mkdir -p strings/0x409 echo "deadbeef00115599" > strings/0x409/serialnumber echo "irq5 labs" > strings/0x409/manufacturer echo "Pi Zero Gadget" > strings/0x409/product mkdir -p functions/acm.usb0 # serial mkdir -p functions/rndis.usb0 # network mkdir -p configs/c.1 echo 250 > configs/c.1/MaxPower ln -s functions/rndis.usb0 configs/c.1/ ln -s functions/acm.usb0 configs/c.1/ udevadm settle -t 5 || : ls /sys/class/udc/ > UDC

This gadget configuration will create a network interface, usually called usb0 , where 0 is a sequential number. You will then need to configure that device separately, but that’s left as an exercise for the reader. Similarly, the serial port will be named ttyGS0 and you will also need to configure a getty to start on it.

Create a systemd service unit for the USB gadget script and use systemctl enable myusbgadget to automatically start it on boot:

# /usr/lib/systemd/system/myusbgadget.service [Unit] Description=My USB gadget After=systemd-modules-load.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/myusbgadget [Install] WantedBy=sysinit.target

This configuration works fine without any additional driver installation on Linux and Mac OS X (or macOS), but not windows.

The difficult part is getting it to work seamlessly in Windows (because Windows is really picky).

Making it Work on Windows

Composite USB devices with multiple functions need to indicate this to Windows by using a special class & protocol code. This can be solved easily enough by setting the values in the correct ConfigFS “files”:

echo 0xEF > bDeviceClass echo 0x02 > bDeviceSubClass echo 0x01 > bDeviceProtocol

The document also goes on to mention…

These code values also alert versions of Windows that do not support IADs to install a special-purpose bus driver that correctly enumerates the device. Without these codes in the device descriptor, the system might fail to enumerate the device, or the device might not work properly.

The Linux gadgets already have interface association descriptors (IADs) for some devices since a few years ago, such as the RNDIS gadget and the ECM gadget , so we don’t need to worry about that.

If you plug in your Pi Zero USB gadget into a Windows machine, you will notice that it cannot find the drivers for the device, and it also misiden

Viewing all articles
Browse latest Browse all 11063

Trending Articles