Linux VTPlayer™ Driver (GPL)

Download the driver


What is the VTPlayer™?


The VTPlayer™ device is a four-button mouse for the blind developed by the VirTouch company. This mouse has got two 4×4 tactile pads that can display Braille characters as well as any symbol fitting into a 4×4 grid.

The VTPlayer™ is a USB device:

When you order a VTPlayer™ device from VirTouch, you get a whole bunch of drivers and applications that allow blind Windows users to get a tactile experience of their windowing system.

Unfortunately, nothing is provided for Linux users. My driver bridges that gap:

  1. it allows the VTPlayer™ to behave like a regular mouse, for example in the X windowing system;
  2. it allows user-space programs to control VTPlayer™'s tactile pads, either thanks to ioctl() calls or through an API available for C (and maybe for Java in the future).

The Driver


This driver is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License.

However, I would like to be kept informed if you make interesting changes to this driver.


The driver is designed for Linux version 2.6. However, drastic API changes starting from Linux 2.6.15 make it difficult to maintain a version of the driver that is compatible with all kernel versions. In consequence:

Further API changes have occurred in Linux 2.6.19 and 2.6.20. Both earlier and later versions are currently supported by the driver (thanks to conditional compilation). However, support for older kernels is likely to be dropped in the future. It is hence recommended to upgrade to newer kernel versions.

The driver has been tested with UHCI and OHCI host controllers, on IA32 (Intel i386) and Sun UltraSPARC II. The test machines were:

Versions prior to 0.4.1 suffered from a bug on big-endian architectures, which prevented the device to be recognized upon probing. Version 0.4.1 has been tested on an UltraSPARC machine, and should work on other big-endian architectures.

So far, the driver is provided as an external kernel module to be loaded by insmod. I am considering releasing a kernel patch allowing it to be integrated into the kernel.

Download & Installation Instructions

The current version of the VTPlayer™ driver is 0.4.1, and was released on 2007-10-07. You can download it from the project page at Sourceforge.

Just extract the files with either tar xvf or tar zxvf. You'll get a VTPlayer/ directory, with three subdirectories: driver/, lib/ and doc. The latter contains a mere copy of this web page.

To compile the driver just run make in the driver directory:

cd VTPlayer/driver/

You should end up with a file called vtplayer.ko that you can load into the kernel with the insmod command:

insmod vtplayer.ko

Note that usbhid must not be loaded at that time. Otherwise, usbhid will take over the device upon connection. So you possibly have to unload usbhid first (rmmod usbhid), and even prevent the system from automatically loading it (on Ubuntu, you have to add it to /etc/modprobe.d/blacklist).

To avoid these problems, VTPlayer's IDs should be added to usbhid's blacklist of USB devices that must not taken over.

The system log the following in /var/log/messages:

drivers/usb/core/usb.c: registered new driver vtplayer
vtplayer.c: VirTouch VTPlayer Tactile Mouse Driver v0.4.0

When you plug in your VTPlayer™ you should get in the log something like:

hub 2-0:1.0: new USB device on port 1, assigned address 4
HID device not claimed by input or hiddev
hid: probe of 2-1:1.0 failed with error -5
input: VirTouch Ltd. VTPlayer VTP-1 on usb-0000:00:1d.0-1
vtplayer.c: VTPlayer now attached to /dev/usb/vtplayer0 (180,192)

You can already test if your VTPlayer™ behaves like a mouse under X or GPM, by using the device /dev/input/mice. You can even have several mice plugged in at a time.

But to use the pads, you have to use the special device /dev/usb/vtplayer0. It should appear atomatically if you are using devfs, but otherwise you have to create it manually (see below).

For the moment, it uses major 180 and minor 192, but the minor is very likely to change in the future. To create the device file just type in the driver/ directory:

make device
ls -l /dev/vtplayer0

The output should read something like:

crw-r--r--    1 root     root     180, 192 Mar  6 16:56 /dev/vtplayer0

If no file is found, the device may be located somewhere else, for instance in /dev/usb/vtplayer0. This may depend on devfs or udev configuration. In case of problems, you can always create the special file anywhere you like, for instance in /tmp:

mknod /tmp/vtplayer0 c 180 192

You can now use the pads by opening /dev/vtplayer0 and doing some ioctl() calls! Or you can use the wrapper API. To test if everything is OK, just go to the lib/ directory and type:

make                       # compiles the library, libvtplayer.a
make test                  # compiles the vtp_test program
./vtp_test /dev/vtplayer0 99 77 B9 5D
                           # give actual the path of the special file     
                           # --> performs a test

On your VTPlayer™, the left pad's pins should show something like a "C", and the right pad's pins something like a "J". If this is the case, then everything is working perfectly.

Driver Design

This driver is two-pronged:

Character Device Specifications

The device provides three functions: open(), ioctl() and close().

Basically, refer to the corresponding POSIX man pages for general information about these functions. The following paragraph gives additional information about the return values of the VTPlayer™ driver and the ioctl() commands.


int open(const char *pathname, int flags);

Opens the device, and returns a handle.


int ioctl(int descriptor, int request, ...);

There is only one ioctl request implemented. It is called VTP_CMD_SET_PADS and it sets the pin positions of the pads, as described in the protocol section.

In vtplayer.h, VTP_CMD_SET_PADS is defined to be 1. The precise syntax of the command is:

ioctl(descriptor, VTP_CMD_SET_PADS, pad_positions);

pad_positions is of type unsigned char *. It must be a pointer to a 4-byte buffer describing the positions of the VTPlayer™'s 32 pins. For the meaning of the 4 bytes in the buffer, refer to the protocol section.

If the ioctl() succeeds, it returns 0. Otherwise, it returns a negative value.


int close(int descriptor);

Closes the file descriptor. Returns 0 in case of success, a negative value otherwise.


The C API provides four functions and a data type to control the VTPlayer™.


It is a handle to the VTPlayer™'s device descriptor.


VTPLAYER vtplayer_open(char *device)

Opens the VTPlayer™, and returns a descriptor.


int vtplayer_buffer_set(VTPLAYER handle, BYTE *buffer)

Sets the pad configuration from a 4-byte buffer, that describes the pin positions according to the scheme described in the protocol section.


int vtplayer_set(VTPLAYER handle, BYTE b1, BYTE b2, BYTE b3, BYTE b4)

Same as vtplayer_buffer_set, but takes the four bytes as parameters instead of a pointer to a buffer.


int vtplayer_close(VTPLAYER handle)

Closes the VTPlayer™ descriptor.

VTPlayer™ Protocol

Pin positions are sent to the mouse in USB control URBs set up as follows:

bmRequestType0x21, i.e. direction: host to device; type: class; recipient: interface.
bRequest 0x09, i.e. SET_CONFIGURATION
wValue 0x0200
wIndex 0x0000
wLength 0x0004

Thus, the URB setup packet is:

The data phase contains 4 bytes to describe the positions of the 32 pins.

Each pad is divided into four square 2×2 subpads. The subpads are numbered as follows:

Subpad locations

Then, the each subpad corresponds to one nibble in the 4-byte packet, in the following order:

Now, let us see how bit weights are assigned to pins inside a subpad. Things get a bit more complicated here because weight assignments are not the same for all subpads...

Actually, there are two bit weight assignment: one for subpads with even numbers, and one for subpads with odd numbers:

Pin weights inside
even and odd subpads

A 1 bit means that the corresponding pin is down; a 0 bit means that the corresponding pin is up.

To settle things, let us look at a simple example. We want to represent "C" and "J" letters on the pads, as follows:

CJ Display

The methods consists in looking at each subpad in the order given above, adding the weights of dark squares (bearing in mind that weights depend on the parity of the subpad number), and writing the resulting nibble in hexadecimal. We get:


But remember, a 1 bit means that the corresponding pin will be held down. So if we want our logo to be displayed by up pins, we have to take the bitwise not of this sequence:


We can try to display this logo on the VTPlayer™ using the vtp_test program, as described in the installation instructions:

vtp_test /dev/vtplayer0 99 77 B9 5D

That's it!


Contacting the Author

I have been interested in computer technology in general for 16 years, and in Linux in particular for 10 years. Check out my personal Web site.

I hold an engineering degree from Supélec and a PhD thesis from Université Paris-Sud. I am now Assistant Professor at Supélec. Check out my professional web page.

Feel free to send me any comments about the driver and this page. If you try to use the driver please let me know, whether it fails or succeeds! If it fails, I would be glad to help.


You may find interesting resources about Linux programming and USB at the following locations: Logo
Page maintained by Christophe Jacquet. $Id: index.html,v 1.7 2008/07/16 20:14:32 jacquet Exp $
This page is valid XHTML 1 Strict.