USB Virtual Host Controller Interface

About this project

I started working on this project in the year 2007 as an employee of the company Conemis AG in Karlsruhe.

The primary goal was to share USB devices over ethernet. At this point in time it works fine with Linux, but not Windows, because you need a kernel module providing you the ability to emulate an USB host controller, which i wrote for Linux. I just started to play around with the Windows kernel a few weeks ago.

The user space part is written in C# and runs on Mono and MS.NET. It consists of some libraries and two executables (server and client).

How it works

Look at this file. It contains a self-explaining picture.

vhci.pdf

How it works in detail

Download and read the source code.

How to get it

You can download it here.

Or clone the git repositories:

# linux kernel module:
git clone git://78.47.86.237/pub/scm/git/vhci_hcd.git

# user space tools:
git clone git://78.47.86.237/pub/scm/git/Vhci.git

How to build/install it

Linux kernel module

Requires: binutils, gcc >= ~3.x.x, gnumake, linux kernel sources >= ~2.6.18.x, ... (in short: the ability to build kernel modules)

make
make install

User space tools

Requires: Mono >= 2.0.1 or MS.NET >= 2.0, gnumake or Monodevelop >= 2.0 or MS Visual Studio >= 2005

Build on command line on Linux/Cygwin

./configure
make
make install

Build with an IDE (Visual Studio or Monodevelop)

Open the Solution (Vhci.sln) and just click on the "Build all" button with your preferred pointing device.

How to play with it

Make sure the kernel module is loaded (as root):

modprobe vhci-hcd

udev should create the character device node /dev/vhci-ctrl. You can change its mode to 666 if you like. (If you don't change it you have to run the following commands as root.)

Check if usbfs is mounted on /proc/bus/usb:

cat /proc/mounts

Now, choose the USB device you want to plug into your (not yet created) virtual host controller. Maybe you want to try your mouse if it is connected via USB. Make sure the device is connected. Then enter the following command to list all connected devices:

vhciclient -l

The output should look like this:

5 [RootHub of bus 5]
5.0 [Mass Storage (address: 7)]
5.1 [unconnected port]
5.2 [unconnected port]
5.3 [unconnected port]
5.4 [unconnected port]
5.5 [unconnected port]
5.6 [unconnected port]
5.7 [unconnected port]
4 [RootHub of bus 4]
4.0 [unconnected port]
4.1 [unconnected port]
3 [RootHub of bus 3]
3.0 [unconnected port]
3.1 [unconnected port]
2 [RootHub of bus 2]
2.0 [HID (address: 8)]
2.1 [HID (address: 6)]
1 [RootHub of bus 1]
1.0 [unconnected port]
1.1 [unconnected port]

In this example there are two human interface devices (HID). Actually the first one is my mouse, the other is my keyboard. You can enter 'cat /proc/bus/usb/devices' to get more information about the devices.

Every device is identified by a few numbers (2.0 for the mouse in this example). The first number (2) is the bus number. The second number (0) represents the index of the USB port of the root hub of this bus. If you have a hub connected to your computer there may be devices with three (or even more) numbers in front of them. In such a case the second number is the index of the USB port of the root hub to which the hub is connected. And (you may have figured it out by yourself now) the third number is the index of the USB port of the hub to which the device is connected. (I think you can repeat this for four, five and six numbers on your own.) It is the physical path to the device or one branch in the tree of hubs.

The following command will create a new virtual USB host controller and will plug in the selected device.

vhciclient 2.0  # replace 2.0 with the identifier of your device

This will not do any network stuff. It just forwards packets from the virtual device to the real device. (Both on the same host.)

You can enter 'vhciclient -l' or 'cat /proc/bus/usb/devices' on another terminal to see the virtual host controller with the device attached to it.

Press CTRL-C (on the terminal which runs vhciclient) to remove the virtual hardware. The device (your mouse) will stop working. This is because your OS does not automatically reattach the driver (usbhid) to the device after we've freed it. Just pull the plug and put it in again. Advanched users could try to pipe the sysfs id of the device's interface into /sys/bus/usb/drivers_probe. In this example the command would be 'echo "2-1:1.0" >/sys/bus/usb/drivers_probe'.

If everything worked as expected you can try to forward the device over ethernet now. But first you need to understand the client/server concept behind it.

The server creates the virtual host controller and listens on a tcp port for connections from clients. A client connects to the server and provides a device which is virtually plugged into the servers virtual host controller. Summarized: The device is physically connected to the client but the server speaks with the device.

Let's start the server on the host on which you want to use the device: (If you want you can run both, client and server, on the same machine, of course.)

vhciserver 4 1138

The first argument (4) means we want to create a virtual host controller with four virtual USB ports. Therefore up to four clients can connect to this server and plug in their devices. The second argument (1138) is the tcp port on which this server listens for incoming connection requests. You can enter 'vhciclient -l' or 'cat /proc/bus/usb/devices' on another terminal to see the virtual host controller with no devices attached to it.

Now, start the client on the host to which the device is physically connected:

vhciclient 2.0 bob:1138

I'm sure you can guess the meaning of the arguments. ("Take device 2.0 and give it to bob on port 1138.")