[Lcdproc] Mini-Box.com picoLCD (M300) LCD driver

Gatewood Green woody@nitrosecurity.com
Thu Mar 1 19:24:02 2007


This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--------------enig6960741B81A7F841F99764F4
Content-Type: multipart/mixed;
 boundary="------------060505070305030803050501"

This is a multi-part message in MIME format.
--------------060505070305030803050501
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Attached is a patch to support to the Mini-Box.com USB LCD (picoLCD) as
shipped in the M300.

http://www.mini-box.com/picoLCD-20x2-OEM
http://www.mini-box.com/Mini-Box-M300-LCD

Comments and feedback welcome.

Thanks,

     Woody
--=20

-----------------------------------------------------------------
Gatewood Green                     Software Engineer/System Admin
Email:                             woody@nitrosecurity.com
http://www.nitrosecurity.com/      NitroSecurity
-----------------------------------------------------------------

Imagine, if you will, a world in which there are no hypothetical
situations...

--------------060505070305030803050501
Content-Type: text/plain;
 name="lcdproc-picolcd.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline;
 filename="lcdproc-picolcd.patch"

diff -uNrp lcdproc-0.5-orig/LCDd.conf lcdproc-0.5-picolcd/LCDd.conf
--- lcdproc-0.5-orig/LCDd.conf	2007-02-23 13:45:24.000000000 -0700
+++ lcdproc-0.5-picolcd/LCDd.conf	2007-02-28 13:43:58.000000000 -0700
@@ -40,6 +40,7 @@ Driver=3DCFontz633
 #Driver=3DCwLnx
 #Driver=3Dglcdlib
 #Driver=3Dimon
+#Driver=3Dpicolcd
=20
 # Tells the driver to bind to the given interface
 Bind=3D127.0.0.1
@@ -497,6 +498,38 @@ keypad_test_mode=3Dno
=20
=20
=20
+## Mini-box.com picoLCD (usblcd) driver ##
+[picolcd]
+# This is for the Mini-Box.com usblcd device that ships with the M300.  =
It can=20
+# also be purchased separately but this driver has only been tested on t=
he M300=20
+# setup.
+
+# KeyTimeout is the time that LCDd spends waiting for a key press before=
 cycling=20
+# through other duties.  Higher values make LCDd use less CPU time and m=
ake=20
+# key presses more detectable.  Lower values make LCDd more responsive b=
ut a=20
+# little prone to missing key presses.  500 (.5 second) is the default a=
nd a
+# balanced value.
+KeyTimeout=3D500
+
+# Contrast: 0 - 1000.  0 seems to work best and is the default.
+Contrast=3D0
+
+# Light the keys? 1 (on) / 0 (off).  Default is 1 (on).
+Keylights=3D1
+
+# If Keylights =3D 1, the you can unlight specific keys below: 1 (on) / =
0 (off)
+# Key0 is the directional pad.  Key1 - Key5 correspond to the F1 - F5 ke=
ys. =20
+# There is no LED for the +/- keys.  This is a handy way to indicate to =
users=20
+# which keys are disabled.  Defaults are 1 (on).
+Key0Light=3D1
+Key1Light=3D1
+Key2Light=3D1
+Key3Light=3D1
+Key4Light=3D1
+Key5Light=3D1
+
+
+
 ## Seiko Epson 1330 driver ##
 [sed1330]
=20
diff -uNrp lcdproc-0.5-orig/acinclude.m4 lcdproc-0.5-picolcd/acinclude.m4=

--- lcdproc-0.5-orig/acinclude.m4	2005-07-04 01:00:33.000000000 -0600
+++ lcdproc-0.5-picolcd/acinclude.m4	2007-02-27 10:49:51.000000000 -0700
@@ -9,12 +9,13 @@ AC_ARG_ENABLE(drivers,
  	[                    hd44780,joy,irman,lirc,bayrad,glk,mtc_s16209x]
  	[                    stv5730,sed1330,sed1520,svga,lcdm001,t6963]
 	[                    lcterm,icp_a106,ms6931,iowarrior,glcdlib,imon]
+	[                    picolcd]
 	[                  \"all\" compiles all drivers],
   	drivers=3D"$enableval",
   	drivers=3D[lcdm001,mtxorb,cfontz,cfontz633,curses,cwlnx,text,lb216,ba=
yrad,glk])
=20
 if test "$drivers" =3D "all"; then
-	drivers=3D[mtxorb,cfontz,cfontz633,curses,cwlnx,text,lb216,mtc_s16209x,=
hd44780,joy,irman,lirc,bayrad,glk,stv5730,sed1330,sed1520,svga,lcdm001,t6=
963,lcterm,icp_a106,ms6931,iowarrior,glcdlib,imon]
+	drivers=3D[mtxorb,cfontz,cfontz633,curses,cwlnx,text,lb216,mtc_s16209x,=
hd44780,joy,irman,lirc,bayrad,glk,stv5730,sed1330,sed1520,svga,lcdm001,t6=
963,lcterm,icp_a106,ms6931,iowarrior,glcdlib,imon,picolcd]
 fi
=20
   	drivers=3D`echo $drivers | sed 's/,/ /g'`
@@ -256,6 +257,23 @@ dnl			else
 			DRIVERS=3D"$DRIVERS imon${SO}"
 			actdrivers=3D["$actdrivers imon"]
 			;;		=09
+		picolcd)
+			AC_CHECK_HEADERS([usblcd.h],[
+				AC_CHECK_LIB(usblcd, main,[
+					LIBUSBLCD=3D"-lusblcd"
+					DRIVERS=3D"$DRIVERS picolcd${SO}"
+					actdrivers=3D["$actdrivers picolcd"]
+				],[
+dnl				else
+					AC_MSG_WARN([The picolcd driver needs the usblcd library])
+				],
+				[-lusblcd]
+				)
+			],[
+dnl			else		=09
+				AC_MSG_WARN([The picolcd driver needs widgets.h, usblcd.h and usblcd=
_util.h from the usblcd package])
+			])		=09
+			;;		=09
 		*)
 			AC_MSG_ERROR([Unknown driver $driver])
 			;;
@@ -272,6 +290,7 @@ AC_SUBST(LIBSVGA)
 AC_SUBST(DRIVERS)
 AC_SUBST(HD44780_DRIVERS)
 AC_SUBST(LIBGLCD)
+AC_SUBST(LIBUSBLCD)
 ])
=20
=20
diff -uNrp lcdproc-0.5-orig/docs/LCDd.8 lcdproc-0.5-picolcd/docs/LCDd.8
--- lcdproc-0.5-orig/docs/LCDd.8	2005-05-30 01:00:19.000000000 -0600
+++ lcdproc-0.5-picolcd/docs/LCDd.8	2007-03-01 11:56:40.000000000 -0700
@@ -107,6 +107,9 @@ LB216 LCD display
 .B lcdm001 (or LCDM001)
 kernelconcepts.de 20x4 serial LCD displays
 .TP
+.B picolcd
+Mini-box.com USB LCD (picoLCD 20x2)
+.TP
 .B text
 Standard "hard-copy" text display
 .TP
diff -uNrp lcdproc-0.5-orig/docs/lcdproc-user/drivers/picolcd.docbook lcd=
proc-0.5-picolcd/docs/lcdproc-user/drivers/picolcd.docbook
--- lcdproc-0.5-orig/docs/lcdproc-user/drivers/picolcd.docbook	1969-12-31=
 17:00:00.000000000 -0700
+++ lcdproc-0.5-picolcd/docs/lcdproc-user/drivers/picolcd.docbook	2007-03=
-01 11:52:56.000000000 -0700
@@ -0,0 +1,139 @@
+<sect1 id=3D"picolcd">
+	<title>The Mini-Box USB LCD (picoLCD 20x2) Driver (picolcd)</title>
+
+	<para>
+		This section covers the installation and use of the Mini-Box USB LCD (=
picoLCD=20
+		20x2) display.
+	</para>
+	<para>
+		The picoLCD page indicates that the device can be connected via I2C or=
 USART. =20
+		This lcdproc driver, however, is limited to the USB connected model.=20
+	</para>
+	<sect2 id=3D"picolcd-setup">
+		<title>Setting up the picoLCD</title>
+
+		<para>
+			The picoLCD device as used by this driver is USB connected and may be=
 purchased=20
+			with an internal USB header connector (5-pin to 5-pin) or an external=
 cable=20
+			(Type-A to 5-pin).  See: http://www.mini-box.com/picoLCD-20x2-OEM.  I=
t may also
+			come pre-installed on systems like the Mini-Box M300:=20
+			http://www.mini-box.com/Mini-Box-M300-LCD.
+		</para>
+		<para>
+			Using the USB LCD with this driver requires the usblcd library from M=
ini-box.com
+			(avaiable at http://www.mini-box.com/picoLCD-20x2-OEM).  The usblcd l=
ibrary=20
+			requires libusb and libhcd.  Your distribution may or may not already=
 provide=20
+			these libraries.  The only kernel driver required is the USB host con=
troller=20
+			driver (uhci_hcd on the M300) required to fire up the usb bus to whic=
h the LCD is=20
+			attached.
+		</para>
+		<para>
+			Lastly, the usbfs file system must be mounted on /proc/bus/usb.
+			<code>mount -t usbfs usbfs /proc/bus/usb</code>
+		</para>
+		<para>
+			Once connected and with libusblcd, libusb and libhid installed, testi=
ng the USB LCD=20
+			can be done with the "usblcd" program that comes with the usblcd libr=
ary.  You can=20
+			also change the USB LCD's initial display (what it shows when you ini=
tialize the=20
+			device) by using the usblcd binary's "splash" command.
+		</para>
+		<para>
+			To use the picolcd with lcdproc, add picolcd to the lcdproc configure=
 drivers option=20
+			(or use all) and then start LCDd with the "-d picolcd" option.  The d=
river has=20
+			sane default options and the options that are user configurable are l=
imited to mostly=20
+			simple items, like contrast and which keys to lights up.
+		</para>
+	</sect2>
+	<sect2 id=3D"picolcd-options">
+		<para>
+			Contrast: 0-1000.  0 is visible, and 1000 is not on my M300.  Default=
 is 0.		=09
+		</para>
+		<para>
+			Keylights: 0/1.  0 turns off the key LEDs and 1 turns them on.  Defau=
lt is 1.		=09
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			Key0Light: if Keylights is set to 1, you can disable the directional =
pad LED by=20
+			setting this value to 0.  Default is 1.
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			Key1Light: if Keylights is set to 1, you can disable the F1 LED by se=
tting this value=20
+			to 0.  Default is 1.
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			Key2Light: if Keylights is set to 1, you can disable the F2 LED by se=
tting this value=20
+			to 0.  Default is 1.
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			Key3Light: if Keylights is set to 1, you can disable the F3 LED by se=
tting this value=20
+			to 0.  Default is 1.
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			Key4Light: if Keylights is set to 1, you can disable the F4 LED by se=
tting this value=20
+			to 0.  Default is 1.
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			Key5Light: if Keylights is set to 1, you can disable the F5 LED by se=
tting this value=20
+			to 0.  Default is 1.
+		</para>
+	</sect2>
+	<sect2>
+		<para>
+			KeyTimeout: (Advanced) This value controls how long LCDd waits for a =
key press when=20
+			get_key is called.  The value represents microseconds and the default=
 is 500 or .5=20
+			seconds.  Lowering this value will make LCDd more responsive but also=
 causes LCDd to use=20
+			more CPU time and, as the timeout grows shorter, key presses become h=
arder to detect. =20
+			Larger values make key presses more reliable if somewhat slow to take=
 effect.
+		</para>
+	</sect2>
+	<sect2 id=3D"picolcd-status">
+		<title>picolcd driver status</title>
+
+		<para>
+			The lcdproc picolcd driver relies upon Mini-Box's usblcd library to s=
etup the USB/HID=20
+			interface.  Unfortunately the usblcd library is very thin and tends t=
o put function=20
+			results on stdout/stderr instead of in return values.  They (Mini-Box=
) really had=20
+			scripting interfaces in mind.
+		</para>
+		<para>
+			The primary example of this is that I had to write a replacement (get=
_key_events) for=20
+			usblcd's read_events so that I could get the key presses back to the =
calling function=20
+			instead of on stdout.  usblcd also has a large number of function she=
lls for which no=20
+			code exists yet.  I am not an expert on HID and USB coding, but if an=
d as time permits=20
+			and hardware is available I will try and improve this drivers access =
to the hardware in=20
+			order to get back data (get_contrast for example) and to potentially =
drive multiple=20
+			pcioLCDs at once (or pick the one we want out of many).
+		</para>
+		<para>
+			To sum up, this driver right now stabs and hopes since response data =
is lacking.
+		</para>
+		<para>
+			The hardware also reports key-up events.  Normally this would be of n=
o issue (they are=20
+			usually a 0 or 'no key') except that when keys are used in combonatio=
n, the key-up=20
+			event may actually come back as multiple events depending on how the =
user released the=20
+			keys.  If the key-up event for a multiple key press comes back as two=
 events, the first=20
+			up event will actually look like a new key press.  The algorithm in g=
et_key tries to=20
+			deal with this in a sane way and toss out all key-up events for now. =
 The hardware is=20
+			touchy and both combo key-down and key-up actions may be reported as =
mutiple events if=20
+			the user is more than a tenth of a second (maybe less?) off in motion=
s.
+		</para>
+	</sect2>
+	<sect2 id=3D"picolcd-copy">
+		<title>Copyright</title>
+		<para>
+			The lcdproc picolcd driver was written by Gatewood Green (woody@nitro=
security.com)=20
+			or (woody@linif.org) and paid for by NitroSecurity, Inc (nitrosecurit=
y.com).
+		</para>
+	</sect2>
+</sect1>
diff -uNrp lcdproc-0.5-orig/docs/lcdproc-user/drivers.docbook lcdproc-0.5=
-picolcd/docs/lcdproc-user/drivers.docbook
--- lcdproc-0.5-orig/docs/lcdproc-user/drivers.docbook	2002-10-25 19:45:2=
0.000000000 -0600
+++ lcdproc-0.5-picolcd/docs/lcdproc-user/drivers.docbook	2007-03-01 10:1=
7:36.000000000 -0700
@@ -12,5 +12,6 @@ well as the configuration of LCDd.
 &ppttrouble;
 &mtxorb;
 &lircin;
+&picolcd;
=20
 </chapter>
diff -uNrp lcdproc-0.5-orig/server/drivers/Makefile.am lcdproc-0.5-picolc=
d/server/drivers/Makefile.am
--- lcdproc-0.5-orig/server/drivers/Makefile.am	2005-06-05 01:00:25.00000=
0000 -0600
+++ lcdproc-0.5-picolcd/server/drivers/Makefile.am	2007-02-27 09:57:51.00=
0000000 -0700
@@ -18,7 +18,7 @@ AM_LDFLAGS =3D @LDSHARED@
 LIBS =3D
=20
 pkglib_PROGRAMS =3D @DRIVERS@
-EXTRA_PROGRAMS =3D bayrad CFontz CFontz633 curses CwLnx glk hd44780 irma=
n icp_a106 joy lb216 mtc_s16209x lcdm001 lcterm lirc MtxOrb sed1330 sed15=
20 stv5730 svga t6963 text wirz_sli ms6931 IOWarrior glcdlib imon
+EXTRA_PROGRAMS =3D bayrad CFontz CFontz633 curses CwLnx glk hd44780 irma=
n icp_a106 joy lb216 mtc_s16209x lcdm001 lcterm lirc MtxOrb sed1330 sed15=
20 stv5730 svga t6963 text wirz_sli ms6931 IOWarrior glcdlib imon picolcd=

 noinst_LIBRARIES =3D libLCD.a
=20
 IOWarrior_CFLAGS =3D   @libusb_cflags@
@@ -40,6 +40,7 @@ svga_LDADD =3D         @LIBSVGA@
 t6963_LDADD =3D        libLCD.a
 glcdlib_LDADD =3D      libLCD.a @LIBGLCD@
 imon_LDADD =3D         libLCD.a
+picolcd_LDADD =3D      libLCD.a @LIBUSBLCD@
=20
 libLCD_a_SOURCES =3D   lcd_lib.h lcd_lib.c
=20
@@ -71,5 +72,6 @@ wirz_sli_SOURCES =3D   lcd.h wirz-sli.h wi
 ms6931_SOURCES =3D     lcd.h ms6931.h ms6931.c report.h
 glcdlib_SOURCES =3D    lcd.h glcdlib.h glcdlib.c report.h
 imon_SOURCES =3D       lcd.h imon.h imon.c report.h
+picolcd_SOURCES =3D    lcd.h picolcd.h picolcd.c report.h
=20
 INCLUDES =3D -I$(top_srcdir)
diff -uNrp lcdproc-0.5-orig/server/drivers/picolcd.c lcdproc-0.5-picolcd/=
server/drivers/picolcd.c
--- lcdproc-0.5-orig/server/drivers/picolcd.c	1969-12-31 17:00:00.0000000=
00 -0700
+++ lcdproc-0.5-picolcd/server/drivers/picolcd.c	2007-03-01 10:08:39.0000=
00000 -0700
@@ -0,0 +1,518 @@
+/*
+ * picoLCD driver for lcdPROC
+ *
+ * (c) 2007 NitroSecurity, Inc.
+ * Written by Gatewood Green <woody@nitrosecurity.com> or <woody@linif.o=
rg>
+ *
+ * License: GPL (same as usblcd and lcdPROC)
+ *
+ * picoLCD: http://www.mini-box.com/picoLCD-20x2-OEM =20
+ * Can be purchased separately or preinstalled in units such as the=20
+ * M300 http://www.mini-box.com/Mini-Box-M300-LCD
+ *
+ * This driver (key lables and arrangement) is based on the M300 impleme=
ntation=20
+ * of the picoLCD
+ *
+ * The picoLCD is usb connected and is driven (currently) via userspace =

+ * libraries using the Mini-box.com usblcd library (not to be confused w=
ith the=20
+ * Linux usblcd module which does NOT support this device).  The usblcd =
library=20
+ * rides atop libusb and libhid (both of which are required for this dri=
ver to=20
+ * operate).
+ *
+ *   libusb: http://libusb.sf.net
+ *   libhid: http://libhid.alioth.debian.org
+ *   usblcd: http://www.mini-box.com/picoLCD-20x2-OEM
+ *=20
+ * The usblcd library is very haphazardly written and directly writes to=
=20
+ * stdout and stderr instead of returning the result for most functions =

+ * (including read_events).  Eventually it would be a good idea to elimi=
nate=20
+ * the need for usblcd and drive the hardware via libusb and libhid dire=
ctly. =20
+ * Such a conversion has the opportunity to provide meaningful return va=
lues=20
+ * for all fucntions (instead of stab and hope) and allow for use of mul=
tiple=20
+ * picoLCD devices.
+ *
+ * Due to the way libusblcd's read_events prints keys to stderr instead =
of=20
+ * returning a struct or some such, you will find my own get_key_events =
below.
+ *
+ * ### WARNING ###: libusblcd.so sets a handler for SIGTERM.  Because mo=
st=20
+ * applications would set up their signal handling early on (before call=
ing=20
+ * new_usblcd_operations()), this can result in a condition that will pr=
event
+ * a handler your application installed from executing.  If your handler=
 was=20
+ * responsible for cleaning up logs, syncing, etc, it can result in lost=
 data.=20
+ *=20
+ */
+
+/* lcdPROC includes */
+#include "lcd.h"
+#include "picolcd.h"
+#include "report.h"
+
+/* These three includes are the Mini-box.com libusblcd (usblcd) and comp=
any. */
+#include <usblcd.h>
+#include <widgets.h>
+#include <usblcd_util.h>
+
+/* Various odds and ends */
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* This is a hack */
+#define API_VERSION "0.5"
+
+/* 12 keys plus a 0 placeholder */
+#define KEYPAD_MAX 13
+#define KEYPAD_LIGHTS 6
+
+#define DEFAULT_CONTRAST  0   /* Full */
+#define DEFAULT_BACKLIGHT 1   /* On */
+#define DEFAULT_KEYLIGHTS 1   /* On */
+#define DEFAULT_TIMEOUT   500 /* Half second */
+
+/* Set this to 1 and get lots of cruft on stderr when using "LCDd -f 1 -=
d picolcd" */
+#define DEBUG_PICO 0
+
+/* PrivateData struct */
+typedef struct pd {
+	usblcd_operations *lcd; // Reference to the LCD instance
+	int  width;
+	int  height;
+	int  key_timeout;
+	int  contrast;
+	int  backlight;
+	int  keylights;
+	int  key_light[KEYPAD_LIGHTS];
+	char *key_matrix[KEYPAD_MAX];
+	char *info;
+	unsigned char *framebuf;
+	unsigned char *lstframe;
+} PrivateData;
+
+static char * keymap[KEYPAD_MAX] =3D {
+	NULL,
+	"Plus",
+	"Minus",
+	"F1",
+	"F2",
+	"F3",
+	"F4",
+	"F5",
+	"Left",
+	"Right",
+	"Up",
+	"Down",
+	"Enter"
+};
+
+/* Private function definitions */
+void get_key_event  ( usblcd_operations *self, lcd_packet *packet, int t=
imeout );
+void set_key_lights ( usblcd_operations *self, int keys[], int state );
+
+/* lcd_logical_driver Variables */
+MODULE_EXPORT char *api_version       =3D API_VERSION;
+MODULE_EXPORT int  stay_in_foreground =3D 0;
+MODULE_EXPORT int  supports_multiple  =3D 1;
+MODULE_EXPORT char *symbol_prefix     =3D "picoLCD_";
+
+/* lcd_logical_driver Manditory functions */
+MODULE_EXPORT int  picoLCD_init( Driver *drvthis ) {
+	PrivateData *pd;
+	int x;
+
+	pd =3D ( PrivateData * ) malloc( sizeof( PrivateData ) );
+
+	if ( ! pd )
+		return -1;
+
+	if ( drvthis->store_private_ptr( drvthis, pd ) )
+		return -1;
+
+	pd->lcd =3D new_usblcd_operations();
+	pd->lcd->init( pd->lcd );
+	pd->width  =3D 20; /* hard coded (mfg spec) */
+	pd->height =3D 2;  /* hard coded (mfg spec) */
+	pd->info =3D "picoLCD: Supports the LCD as installed on the M300 (http:=
//www.mini-box.com/Mini-Box-M300-LCD) ";
+
+	for ( x =3D 0; x < KEYPAD_LIGHTS; x++ )
+		pd->key_light[x] =3D 1; /* individual lights on */
+
+	pd->contrast     =3D drvthis->config_get_int( drvthis->name, "Contrast"=
,   0, DEFAULT_CONTRAST  );
+	pd->backlight    =3D drvthis->config_get_int( drvthis->name, "BackLight=
",  0, DEFAULT_BACKLIGHT );
+	pd->keylights    =3D drvthis->config_get_int( drvthis->name, "KeyLights=
",  0, DEFAULT_KEYLIGHTS ); /* key lights with LCD Backlight? */
+	pd->key_timeout  =3D drvthis->config_get_int( drvthis->name, "KeyTimeou=
t", 0, DEFAULT_TIMEOUT   );
+
+	/* These allow individual lights to be disabled */
+	pd->key_light[0] =3D drvthis->config_get_int( drvthis->name, "Key0Light=
",  0, 1 ); /* Directional PAD */
+	pd->key_light[1] =3D drvthis->config_get_int( drvthis->name, "Key1Light=
",  0, 1 ); /* F1 */
+	pd->key_light[2] =3D drvthis->config_get_int( drvthis->name, "Key2Light=
",  0, 1 ); /* F2 */
+	pd->key_light[3] =3D drvthis->config_get_int( drvthis->name, "Key3Light=
",  0, 1 ); /* F3 */
+	pd->key_light[4] =3D drvthis->config_get_int( drvthis->name, "Key4Light=
",  0, 1 ); /* F4 */
+	pd->key_light[5] =3D drvthis->config_get_int( drvthis->name, "Key5Light=
",  0, 1 ); /* F5 */
+
+	for ( x =3D 0; x < KEYPAD_MAX; x++ )
+		pd->key_matrix[x] =3D keymap[x];
+
+	pd->framebuf =3D ( unsigned char * ) malloc( pd->width * pd->height + 1=
 );
+	if ( pd->framebuf =3D=3D NULL ) {
+		report( RPT_ERR, "%s: unable to create framebuf.\n", __FUNCTION__ );
+		return -1;
+	}
+	memset( pd->framebuf, ' ', pd->width * pd->height );
+	pd->framebuf[pd->width * pd->height] =3D 0;
+
+	pd->lstframe =3D ( unsigned char * ) malloc( pd->width * pd->height + 1=
 );
+	if ( pd->lstframe =3D=3D NULL ) {
+		report( RPT_ERR, "%s: unable to create lstframe.\n", __FUNCTION__ );
+		return -1;
+	}
+	memset( pd->lstframe, ' ', pd->width * pd->height );
+	pd->lstframe[pd->width * pd->height] =3D 0;
+
+	if ( pd->backlight )
+		picoLCD_backlight( drvthis, 1 );
+		if ( ! pd->keylights )
+			set_key_lights( pd->lcd, pd->key_light, 0 );
+	else
+		picoLCD_backlight( drvthis, 0 );
+
+	picoLCD_set_contrast( drvthis, pd->contrast );
+
+	report( RPT_INFO, "picolcd: init complete\n", __FUNCTION__ );
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: init complete\n" );
+
+	return 0;
+}
+
+MODULE_EXPORT void picoLCD_close( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+	pd->lcd->close( pd->lcd ); /* This actually does not do anything in usb=
lcd (yet?) */
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: close complete\n" );
+}
+
+/* lcd_logical_driver Essential output functions */
+MODULE_EXPORT int  picoLCD_width( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+	return pd->width;
+}
+
+MODULE_EXPORT int  picoLCD_height( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+	return pd->height;
+}
+
+MODULE_EXPORT void picoLCD_clear( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+	memset( pd->framebuf, ' ', pd->width * pd->height );
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: clear complete\n" );
+}
+
+MODULE_EXPORT void picoLCD_flush( Driver *drvthis ) {
+	PrivateData   *pd =3D drvthis->private_data;
+	unsigned char *fb =3D pd->framebuf;
+	unsigned char *lf =3D pd->lstframe;
+	static char   text[48];
+	int           i, line, offset;
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: flush started\n" );
+
+	for ( line =3D 0; line < pd->height; line++ ) {=20
+		memset( text, 0, 48 );=20
+		offset =3D line * pd->width;
+		fb     =3D pd->framebuf + offset;
+		lf     =3D pd->lstframe + offset;
+
+		for ( i =3D 0; i < pd->width; i++ ) {
+			if ( *fb++ !=3D *lf++ ) {
+				strncpy( text, pd->framebuf + offset, pd->width );
+				pd->lcd->settext( pd->lcd, line, 0, text );
+				memcpy( pd->lstframe + offset, pd->framebuf + offset, pd->width );
+
+				if ( DEBUG_PICO )
+					fprintf( stderr, "picolcd: flush wrote line %d (%s)\n", line + 1, t=
ext );
+
+				break;
+			}
+		}
+	}
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: flush complete\n\t(%s)\n\t(%s)\n", pd->fram=
ebuf, pd->lstframe );
+}
+
+MODULE_EXPORT void picoLCD_string( Driver *drvthis, int x, int y, char *=
str ) {
+	PrivateData *pd =3D drvthis->private_data;
+	char *dest;
+	int  len;
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: string start (%s)\n", str );
+
+	if ( y < 1 || y > pd->height )
+		return;
+	if ( x < 1 || x > pd->width )
+		return;
+
+	len =3D strlen( str );
+	if ( len + x > pd->width ) {
+		if ( DEBUG_PICO )
+			fprintf( stderr, "picolcd: string overlength (>%d). Start: %d Length:=
 %d (%s)\n", pd->width, x, len ,str );
+
+		len =3D pd->width - x; /* Copy what we can */
+	}
+
+	x--; y--; /* Convert 1-based to 0-based */
+	dest =3D pd->framebuf + ( y * pd->width + x );
+	memcpy( dest, str, len * sizeof(char) );
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: string complete (%s)\n", str );
+}
+
+MODULE_EXPORT void picoLCD_chr( Driver *drvthis, int x, int y, char chr =
) {
+	PrivateData *pd =3D drvthis->private_data;
+	char *dest;
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: chr start (%c)\n", chr );
+
+	if ( y < 1 || y > pd->height )
+		return;
+	if ( x < 1 || x > pd->width )
+		return;
+
+	x--; y--; /* Convert 1-based to 0-based */
+	dest =3D pd->framebuf + ( y * pd->width + x );
+	memcpy( dest, &chr, sizeof(char) );
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: chr complete (%c)\n", chr );
+}
+
+/* lcd_logical_driver Essential input functions */
+
+MODULE_EXPORT char *picoLCD_get_key( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+	lcd_packet *keydata;
+	char *keystr;
+	int  keys_read =3D 0;
+	int  key_pass  =3D 0;
+	int  two_keys  =3D 0;
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: get_key start (timeout %d)\n", pd->key_time=
out );
+
+	keydata =3D malloc( sizeof( lcd_packet ) );
+
+	while ( ! keys_read ) {
+		get_key_event( pd->lcd, keydata, pd->key_timeout );
+		if ( DEBUG_PICO )
+			fprintf( stderr, "picolcd: get_key got an event\n" );
+
+		if ( keydata->type =3D=3D IN_REPORT_KEY_STATE ) {
+			if ( ! keydata->data[1] && key_pass ) {
+				if ( DEBUG_PICO )
+					fprintf( stderr, "picolcd: get_key got all clear\n" );
+				/* Got a <0, 0> key-up event after reading a valid key press event *=
/
+				keys_read++; /* All clear */
+			} else if ( ! keydata->data[2] && ! two_keys ) {
+				if ( DEBUG_PICO )
+					fprintf( stderr, "picolcd: get_key got one key\n" );
+				/* We got one key (but not after a two key event and before and all =
clear) */
+				keystr =3D pd->key_matrix[keydata->data[1]];
+			} else {
+				/* We got two keys */
+				if ( DEBUG_PICO )
+					fprintf( stderr, "picolcd: get_key got two keys\n" );
+				two_keys++;
+				sprintf( keystr, "%s+%s", pd->key_matrix[keydata->data[1]], pd->key_=
matrix[keydata->data[2]] );
+			}
+
+			key_pass++; /* This hack allows us to deal with receiving left over <=
0,0> first */
+		} else {
+			if ( DEBUG_PICO )
+				fprintf( stderr, "picolcd: get_key got non-key data or timeout\n" );=

+			/* We got IR or otherwise bad data */
+			return NULL;
+		}
+
+	}
+
+   free( keydata );
+
+	if ( DEBUG_PICO )
+		fprintf( stderr, "picolcd: get_key complete (%s)\n", keystr );
+
+	if ( ! strlen( keystr ) )
+		return NULL;
+
+	return keystr;
+
+/*=20
+ * Due to how key events are reported, we need to keep reading key press=
es=20
+ *	until we get the all clear (all keys up) event.
+ *=20
+ * Key events come back in such a way to report up to two simultanious k=
eys=20
+ * pressed.  The highest numbered key always comes back as the first key=
 and=20
+ * the lower numbered key follows.  If only one key was pressed, the sec=
ond=20
+ * key is 0.  I will refer to a key event as: <high key, low key>.
+ *
+ * Key ID numbers:
+ *        0 =3D (no key)
+ *        1 =3D + (plus)
+ *        2 =3D - (minus)
+ *        3 =3D F1
+ *        4 =3D F2
+ *        5 =3D F3
+ *        6 =3D F4
+ *        7 =3D F5
+ *        8 =3D Left
+ *        9 =3D Right
+ *       10 =3D Up
+ *       11 =3D Down
+ *       12 =3D Enter
+ *=20
+ * The picoLCD also sends key-up events.
+ *
+ * On a single key press, the return is <keynum, 0>.  The key-up event i=
s a=20
+ * read that returns <0, 0> (all clear).  On a dual key press, if one ke=
y is=20
+ * released later than the other key, the first key-up event is=20
+ * <remainingkey, 0>.  This will be followed by a final "all clear" key-=
up=20
+ * <0, 0>.  If both keys are release simultaniously, then after <hk, lk>=
,=20
+ * you will receive <0, 0>.  If the keys are pressed down in a staggard =

+ * fashion, you will receive <first key, 0> followed by <hk, lk> followe=
d by=20
+ * key-up events as already detailed.
+ *
+ * What this means is that we need to keep reading key presses until we =
get=20
+ * the <0, 0> all clear.
+ */
+=09
+}
+
+/* lcd_logical_driver Extended output functions */
+
+/* lcd_logical_driver User-defined character functions */
+
+/* lcd_logical_driver Hardware functions */
+/*MODULE_EXPORT int picoLCD_get_contrast( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+}*/
+
+MODULE_EXPORT int  picoLCD_set_contrast( Driver *drvthis, int promille )=
 {
+	PrivateData *pd =3D drvthis->private_data;
+
+	if ( promille <=3D 1000 && promille > 0 ) {
+		pd->lcd->contrast( pd->lcd, ( int ) ( promille / 1000 * 40 ) );
+		return 0;
+	} else if ( promille > 1000 ) {
+		pd->lcd->contrast( pd->lcd,  40 );
+		return 0;
+	} else if ( promille <=3D 0 ) {
+		pd->lcd->contrast( pd->lcd,  0 );
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+/*MODULE_EXPORT int picoLCD_get_brightness( Driver *drvthis, int state )=
 {
+	PrivateData *pd =3D drvthis->private_data;
+
+}*/
+
+/*MODULE_EXPORT int  picoLCD_set_brightness( Driver *drvthis, int state,=
 int promille ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+}*/
+
+MODULE_EXPORT void picoLCD_backlight( Driver *drvthis, int state ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+	if ( state =3D=3D 0 ) {
+		pd->lcd->backlight( pd->lcd, state );
+		set_key_lights( pd->lcd, pd->key_light, state );
+		return;
+	}
+
+	if ( state =3D=3D 1 ) {
+		pd->lcd->backlight( pd->lcd, state );
+		if ( pd->keylights )
+			set_key_lights( pd->lcd, pd->key_light, state );
+		return;
+	}
+
+	return;
+}
+
+/*MODULE_EXPORT int  picoLCD_output( Driver *drvthis, int state ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+}*/
+
+/* lcd_logical_driver Informational functions */
+MODULE_EXPORT char *picoLCD_get_info( Driver *drvthis ) {
+	PrivateData *pd =3D drvthis->private_data;
+
+	return pd->info;
+}
+
+/* Private functions */
+void get_key_event ( usblcd_operations *self, lcd_packet *packet, int ti=
meout ) {
+	int ret;
+
+	memset( packet->data, 0, 255 );
+	packet->type =3D 0;
+	ret =3D usb_interrupt_read( self->hid->hiddev->handle, USB_ENDPOINT_IN =
+ 1, packet->data, _USBLCD_MAX_DATA_LEN, timeout );
+	if ( ret > 0 ) {
+		switch ( packet->data[0] ) {
+			case IN_REPORT_KEY_STATE: {
+				packet->type =3D IN_REPORT_KEY_STATE;
+			} break;
+			case IN_REPORT_IR_DATA: {
+				packet->type =3D IN_REPORT_IR_DATA;
+			} break;
+			default: {
+				packet->type =3D 0;
+			}
+		}
+	}
+}
+
+void set_key_lights ( usblcd_operations *self, int keys[], int state ) {=

+	if ( state ) {
+		/* Only LEDs we want on */
+		if ( keys[0] )
+			self->setled( self, 0, 1 );
+		if ( keys[1] )
+			self->setled( self, 1, 1 );
+		if ( keys[2] )
+			self->setled( self, 2, 1 );
+		if ( keys[3] )
+			self->setled( self, 3, 1 );
+		if ( keys[4] )
+			self->setled( self, 4, 1 );
+		if ( keys[5] )
+			self->setled( self, 5, 1 );
+	} else {
+		/* All LEDs off */
+		self->setled( self, 0, 0 );
+		self->setled( self, 1, 0 );
+		self->setled( self, 2, 0 );
+		self->setled( self, 3, 0 );
+		self->setled( self, 4, 0 );
+		self->setled( self, 5, 0 );
+	}
+}
diff -uNrp lcdproc-0.5-orig/server/drivers/picolcd.h lcdproc-0.5-picolcd/=
server/drivers/picolcd.h
--- lcdproc-0.5-orig/server/drivers/picolcd.h	1969-12-31 17:00:00.0000000=
00 -0700
+++ lcdproc-0.5-picolcd/server/drivers/picolcd.h	2007-02-28 11:19:01.0000=
00000 -0700
@@ -0,0 +1,56 @@
+/*
+ * Driver for picoLCD graphical displays
+ * Header file
+ *
+ * (c) 2007 NitroSecurity, Inc.
+ * Written by Gatewood Green <woody@nitrosecurity.com> or <woody@linif.o=
rg>
+ *
+ * License: GPL (same as usblcd and lcdPROC)
+ *
+ * picoLCD: http://www.mini-box.com/picoLCD-20x2-OEM =20
+ * Can be purchased separately or preinstalled in units such as the=20
+ * M300 http://www.mini-box.com/Mini-Box-M300-LCD
+ *
+ * See picolcd.c for full details
+ *
+ */
+
+#ifndef PICOLCD_H
+#define PCIOLCD_H
+
+#include "lcd.h"
+
+typedef struct _lcd_packet lcd_packet;
+struct _lcd_packet {
+	unsigned char data[255];
+	unsigned int type;
+};
+
+MODULE_EXPORT int  picoLCD_init      ( Driver *drvthis );
+MODULE_EXPORT void picoLCD_close     ( Driver *drvthis );
+MODULE_EXPORT int  picoLCD_width     ( Driver *drvthis );
+MODULE_EXPORT int  picoLCD_height    ( Driver *drvthis );
+MODULE_EXPORT void picoLCD_clear     ( Driver *drvthis );
+MODULE_EXPORT void picoLCD_flush     ( Driver *drvthis );
+MODULE_EXPORT void picoLCD_string    ( Driver *drvthis, int x, int y, ch=
ar *str );
+MODULE_EXPORT void picoLCD_chr       ( Driver *drvthis, int x, int y, ch=
ar c );
+
+MODULE_EXPORT char *picoLCD_get_key  ( Driver *drvthis );
+
+//MODULE_EXPORT void picoLCD_vbar      ( Driver *drvthis, int x, int y, =
int len, int promille, int options );
+//MODULE_EXPORT void picoLCD_hbar      ( Driver *drvthis, int x, int y, =
int len, int promille, int options );
+//MODULE_EXPORT void picoLCD_num       ( Driver *drvthis, int x, int y, =
int num );
+//MODULE_EXPORT void picoLCD_heartbeat ( Driver *drvthis, int state );
+//MODULE_EXPORT void picoLCD_icon      ( Driver *drvthis, int x, int y, =
int icon );
+//MODULE_EXPORT void picoLCD_cursor    ( Driver *drvthis, int x, int y, =
int type );
+
+//MODULE_EXPORT int  picoLCD_get_contrast   ( Driver *drvthis );
+MODULE_EXPORT int  picoLCD_set_contrast   ( Driver *drvthis, int promill=
e );
+//MODULE_EXPORT int  picoLCD_get_brightness ( Driver *drvthis, int state=
 );
+//MODULE_EXPORT int  picoLCD_set_brightness ( Driver *drvthis, int state=
, int promille );
+MODULE_EXPORT void picoLCD_backlight      ( Driver *drvthis, int promill=
e );
+//MODULE_EXPORT void picoLCD_output         ( Driver *drvthis, int state=
 );
+
+MODULE_EXPORT char *picoLCD_get_info      ( Driver *drvthis );
+
+#endif

--------------060505070305030803050501--

--------------enig6960741B81A7F841F99764F4
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFF5yhEHnsUla8nzK0RA8ivAJ9DxtM0sQbrs76viFz5N4Y0csaVBwCgrold
Cs3MVeFjqVNhsZhkj7x9Zeg=
=X/KW
-----END PGP SIGNATURE-----

--------------enig6960741B81A7F841F99764F4--