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:
0x1100
(VirTouch Ltd.
)0x0001
(VTPlayer VTP-1
)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:
ioctl()
calls or through an API available for C
(and maybe for Java in the future).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.
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/ make
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.
This driver is two-pronged:
/dev/input/mice
device. This part
is based on the usbmouse
driver by Vojtech Pavlik,ioctl()
calls on the
special file /dev/vtplayer0
. This part is based on the
usb-skeleton
driver by Greg Kroah-Hartman.
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.
open
int open(const char *pathname, int flags);
Opens the device, and returns a handle.
ioctl
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.
close
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™.
VTPLAYER
typeIt is a handle to the VTPlayer™'s device descriptor.
vtplayer_open
VTPLAYER vtplayer_open(char *device)
Opens the VTPlayer™, and returns a descriptor.
vtplayer_buffer_set
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.
vtplayer_set
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.
vtplayer_close
int vtplayer_close(VTPLAYER handle)
Closes the VTPlayer™ descriptor.
Pin positions are sent to the mouse in USB control URBs set up as follows:
Field | Value |
---|---|
bmRequestType | 0x21 ,
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: 21.09.00.02.00.00.04.00
.
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:
Then, the each subpad corresponds to one nibble in the 4-byte packet,
in the following order: 01.23.45.67
.
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:
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:
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:
66.88.46.A2
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:
99.77.B9.5D
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!
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:
$Id: index.html,v 1.7 2008/07/16 20:14:32 jacquet Exp $