Emulate physical USB device Linux

Matt Dorsett picture Matt Dorsett · Jul 13, 2013 · Viewed 19.3k times · Source

I have a Linux application that I would like to automate some tests for, and its state should change depending on the status of certain devices, i.e. USB devices, WLAN devices, WAN devices. However, we no longer have physical USB, WLAN, WAN, etc devices at our disposal, so I need to figure out a way to test this program without actually plugging in physical devices, turning them on/off, etc.

I am starting off by simply creating a virtual USB device that I can control from user space, but there is a fundamental lack of knowledge on my part preventing me from taking any of the similar topics on these forums and applying them to my project. I feel like I will need to create some kind of virtual USB driver, and then have it communicate with some user-level program rather than usbfs. However, even if I create this virtual driver, how do I "plug in" this device from user-space and get my program registered with this particular driver? Is what I'm trying to do even possible?

Answer

BraveNewCurrency picture BraveNewCurrency · Jul 14, 2013

The best way is to use the Linux Gadget Drivers and hardware that allows you to be a USB device. The gadget driver allow a computer to "pretend" to be any kind of device. Then your system under test has a single USB OTG cable to the gadget box. You don't even need to unplug the cable if your gadget box has the right hardware. The "gadget box" could be your desktop/laptop running Linux (if it supports USB OTG), or even an Android phone or Raspberry Pi. (Beware that USB cables suck. Just because the cable fits doesn't mean it's wired correctly for USB OTG.)

Once you have the right USB OTG hardware, your gadget box is all software:

1) If your device under test supports OTG, make sure your gadget box does NOT try and become a USB host. (Then your device under test will become a USB client.) I.e. make sure things like usb_storage are not automatically loaded.

2) Out of the box, the kernel supports gadgets for USB Hubs, USB Ethernet, USB Serial ports and USB sticks. Just load the right modules on your gadget box and it "just works". For example, to create a USB stick, do something like this: "insmod g_file_storage.ko file=/dev/ram0". The far side will think that you plugged in a USB stick.

For serial devices, your gadget can run user-space code that "picks up the phone" on /dev/USBx" and talks to your device under test. (Presumably emulating a 4G modem or whatever.)

Tons of devices are really "USB serial" under the hood because the manufacturer was too lazy to understand USB.

3) With a little re-compiling or configuring, you can have those generic Gadget Devices pretend to be various USB IDs or return various vendor strings, etc. This won't be the same as "testing against real hardware", but at least you are testing with generic version of these devices.

4) For device types that aren't already in the kernel (i.e WiFi or something), you're on your own. With enough blood sweat and tears, you can use write your own gadget type. (Ideally, keep as much as possible in user space, and only handle the performance critical parts in the kernel..)

Beware: it is impossible to simultaneously understand and appreciate USB.