Driving HD4470-compatible LCD modules via USB

Everybody loves Liquid Crystal Displays. They're cheap, reliable, power efficient, and even today they add a touch of seductive futurism to any incorporating device. For ease of use the fragile glass panels are often packaged as a module, mounted to a PCB with a suitable chipset for interfacing to the outside world. LCD modules can be found in telephones, fax machines and many other products; they are ubiquitous. The vast majority of dot-matrix character-based LCD modules use the venerable Hitachi HD44780 controller chip, or a compatible knockoff. These modules can be driven directly from a PC printer port or other parallel bus, and are ideal for the experimenter.

When I first learned about LCD modules I had a lot of fun wiring them to my desktop PC's parallel port and using software like LCDproc to read out various data that were presumably beneath the capability of my vastly superior video display. Eventually I moved my computing environment to a fancy laptop, which raised two problems with the LCD project: 1) The parallel port is not terribly robust, and hooking up untested, homemade devices is a good way to fry it; 2) The laptop has only one parallel port, and I usually have a printer connected to it. With the desktop PC these weren't serious problems because add-in cards could be installed for more (and disposable) ports, but the laptop didn't have that option.

I toyed with the idea of building an optoisolator interface to protect the port, but this didn't solve the problem of multiple devices. It then occurred to me to use USB-to-parallel converters, which were becoming cheaper and more available by the day. Not only would the converter electrically isolate the LCD device from the host computer, I could theoretically attach as many devices as I wanted, subject to the limits of USB. This also solved another problem: since the parallel port is not designed to source significant current, external devices must have their own power supply or tap into a keyboard, serial or other port for power. USB hosts can generally provide up to 100mA at 5V, so only one physical connection is needed for both data and power.

This seemingly simple idea was very challenging to implement. The details are below, but here's a synopsis of problems and their solutions:

Linux 2.6 (my OS kernel of choice) uses the generic usblp driver for USB Printer Class hardware, including USB-to-parallel converters. This driver enables /dev/lpX and /dev/usblpX line printer character devices which work for printing, but neither lp character devices nor the driver itself allow direct manipulation of the data and status lines to the extent required by LCD modules and other non-printer hardware.

There is one additional USB-to-parallel chip driver in the 2.6 kernel at present time, for the Lucent USS720 chip. From Chapter 2 of the Linux USB sub-system guide:

The USS720 is a USB to Parallel port chip made by Lucent that normally acts like a USB Printer Class device. Indeed you can use a USS720 based bridge and a parallel port printer with the USB Printer driver, (see above). However there is also a mode (known as register mode) which makes the USS720 look like normal parallel port hardware. This driver makes use of that mode.

If you have the opportunity, look at /proc/sys/dev/parport before you load the module or reboot with a kernel with USS720 enabled. You should note the number of parallel ports you have - typically one, under /proc/sys/dev/parport/parport0. After you put USS720 support into your kernel, you should have another port (perhaps /proc/sys/dev/parport1). If you look at the appropriate hardware entry, you should see something like the following:

[bradh@rachel bradh]$ more /proc/sys/dev/parport/parport1/hardware
base:   0x0
irq:    none
dma:    none

Every distribution should have device node entries for parallel ports - typically /dev/lpX or /dev/parX, where the X is some number. If you need to create them, parallel ports device nodes use character major number 6.

You should now be able to use the USS720 for anything that you would normally need a parallel port for, except that certain timing sensitive applications may not work, since the emulation is rather slow. As for a real USB printer, I suggest use of automated tools to generate a /etc/printcap entry if you are connecting up a printer.

If you didn't get to select USS720 support at the configuration stage, you need to turn on Parallel port support support (under General setup if using menuconfig).

The USS720 driver only seems to recognize USB devices that match a list of vendor and product ID combinations which are hardcoded in the driver. It does not appear capable of probing unknown hardware, even when the device is registered for the driver with the Linux hotplug system. There are only four devices in the list; how many products actually use the USS720?

When Apple dropped the parallel port from their products with the introduction of the iMac, demand soared for USB-to-parallel converters to allow use of older printers with new Macs. Evidently Epson even bundled cheap converter cables with their printers for a period of time. The converters tend to outlast the printers and now can be found very cheaply; new converters are also available. Many of the converters I've cracked open use the Lucent USS725 chip, which seems to be fully compatible with the USS720 driver. New vendor/product IDs can be added to the list in the driver, which must then be recompiled (details below).

When a USB Printer Class device is connected, Linux automatically loads the usblp driver. This prevents the USS720 driver from finding compatible devices, so you have to disable usblp (or, if a module, unload it and then load uss720.ko). If you need to use both a USB printer and a USS720 device you can probably juggle the drivers so everything works, but I haven't tried.

Software which talks directly to the parallel port's hardware address (0x378, 0x278) will not work; it must be able to interact with ppdev character devices. This rules out a lot of software, including many homebrew EPROM programmers and, sadly, LCDproc.

Fortunately an alternative to LCDproc exists in the form of LCD4Linux, which does include the option to use ppdev.

A step-by-step guide to connecting your display via USB:

Note: All examples in this guide refer to Linux kernel version 2.6.9 because that's what I used. They should be apply to other 2.4-2.6 kernel versions as well, but your mileage may vary.

1: Obtain a USB-to-parallel converter based on the USS720 or USS725

Here's a table of devices I've found which work. If you're not sure which chip your device uses, open the case and see! If you're purchasing a new converter specifically for this purpose, it's a good idea to avoid those with opaque injection-molded shells.

USB-to-parallel converters based on the USS720/USS725
ManufacturerModelUSB VendorUSB ProdIDChipNotes
Infowave Wireless Messaging901-0030047e1001USS720appears as Agere Systems, Inc. (Lucent)
Seiko Epson Corp.ISD-10104b80003USS725
Belkin ComponentsF5U120-PC050d1202USS720 USB DockStation multifunction device
Infowave Software Inc.ISD-10306c60100USS725P/N 901-0060

2: Determine the converter's USB Vendor and Product IDs

After the device is inserted, the vendor and product ID can be found in /proc/bus/usb/devices. Here's the relevant section for the Infowave ISD-103 USB to parallel cable, with the IDs in bold:

T:  Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  3 Spd=12  MxCh= 0
D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=06c6 ProdID=0100 Rev= 2.00
S:  Manufacturer=Infowave Software Inc.
S:  Product=USB to Parallel Cable
S:  SerialNumber=1bf77250-ac7c-11d3-b5cd-d10c74989546
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr= 96mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=07(print) Sub=01 Prot=01 Driver=uss720
E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:  If#= 0 Alt= 1 #EPs= 2 Cls=07(print) Sub=01 Prot=02 Driver=uss720
E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:  If#= 0 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=ff Driver=uss720
E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
This information can also be retrieved in a more concise form using lsusb, from the usbutils package:
Bus 002 Device 003: ID 06c6:0100 Infowave Software, Inc.
If no manufacturer's information is visible you can check the Linux USB Project's list of USB IDs.

2: Modify the USS720 kernel module

Add the product IDs to the table of valid hardware at line 627 of /usr/src/linux/drivers/usb/misc/uss720.c like so:

/* table of cables that work through this driver */
static struct usb_device_id uss720_table [] = {
        { USB_DEVICE(0x047e, 0x1001) },
        { USB_DEVICE(0x04b8, 0x0003) },			/* Added by Rab */
        { USB_DEVICE(0x050d, 0x1202) },			/* Added by Rab */
        { USB_DEVICE(0x0557, 0x2001) },
        { USB_DEVICE(0x06c6, 0x0100) },			/* Added by Rab */
        { USB_DEVICE(0x0729, 0x1284) },
        { USB_DEVICE(0x1293, 0x0002) },
        { }						/* Terminating entry */
(Re)compile and install the module. Run depmod -a. You can confirm support for your devices by checking the /lib/modules/2.6.9/modules.usbmap file generated by depmod:
uss720               0x0003      0x06c6   0x0100    0x0000       0x0000       0x00         0x00            0x00            0x00            0x00               0x00               0x0

Apr 24 00:10:01 rabbisu kernel: usb 1-1: new full speed USB device using address 2
Apr 24 00:10:02 rabbisu kernel: usb 1-1: new full speed USB device using address 3
Apr 24 00:10:02 rabbisu kernel: uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>
Apr 24 00:10:03 rabbisu kernel: lp1: using parport1 (polling).
Apr 24 00:10:03 rabbisu kernel: usbcore: registered new driver uss720
Apr 24 00:10:03 rabbisu kernel: drivers/usb/misc/uss720.c: v0.5:USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip
Apr 24 00:10:08 rabbisu wait_for_sysfs[2995]: error: wait_for_sysfs needs an update to handle the device '/class/ppdev/parport1' properly, please report to <linux-hotplug-devel@lists.sourceforge.net>
Apr 24 00:10:08 rabbisu udev: creating device node '/dev/parport1'
Apr 24 00:10:08 rabbisu udev: creating device node '/dev/lp1'
Not finished yet; check back later.
Contact: reboots at g-cipher.net
HTML compliant