[Lcdproc] picolcd patch against 0.5.1

Gatewood Green woody@nitrosecurity.com
Mon Mar 12 20:25:02 2007


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

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

Attached is an updated patch for 0.5.1 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

This pass also incorporates cleanup suggestions from Peter.  I am
sending this separate from the CVS patch for the benefit of those using
the release as the CVS patch does not cleanly apply.

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...


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

diff -uNrp lcdproc-0.5.1-orig/acinclude.m4 lcdproc-0.5.1/acinclude.m4
--- lcdproc-0.5.1-orig/acinclude.m4	2006-10-06 01:02:45.000000000 -0600
+++ lcdproc-0.5.1/acinclude.m4	2007-03-12 13:58:39.000000000 -0600
@@ -8,14 +8,14 @@ AC_ARG_ENABLE(drivers,
 	[                    bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,=
EyeboxOne,]
 	[                    g15,glcdlib,glk,hd44780,icp_a106,imon,IOWarrior,ir=
man,]
 	[                    joy,lb216,lcdm001,lcterm,lirc,MD8800,ms6931,mtc_s1=
6209x,]
-	[                    MtxOrb,NoritakeVFD,pyramid,sed1330,sed1520,serialV=
FD,]
+	[                    MtxOrb,NoritakeVFD,picolcd,pyramid,sed1330,sed1520=
,serialVFD,]
 	[                    sli,stv5730,svga,t6963,text,tyan,ula200,xosd]
 	[                  'all' compiles all drivers;]
 	[                  'all,!xxx,!yyy' de-selects previously selected drive=
rs],
 	drivers=3D"$enableval",
 	drivers=3D[bayrad,CFontz,CFontz633,curses,CwLnx,glk,lb216,lcdm001,MtxOr=
b,pyramid,text])
=20
-allDrivers=3D[bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,EyeboxOn=
e,g15,glcdlib,glk,hd44780,icp_a106,imon,IOWarrior,irman,joy,lb216,lcdm001=
,lcterm,lirc,MD8800,ms6931,mtc_s16209x,MtxOrb,NoritakeVFD,pyramid,sed1330=
,sed1520,serialVFD,sli,stv5730,svga,t6963,text,tyan,ula200,xosd]
+allDrivers=3D[bayrad,CFontz,CFontz633,CFontzPacket,curses,CwLnx,EyeboxOn=
e,g15,glcdlib,glk,hd44780,icp_a106,imon,IOWarrior,irman,joy,lb216,lcdm001=
,lcterm,lirc,MD8800,ms6931,mtc_s16209x,MtxOrb,NoritakeVFD,picolcd,pyramid=
,sed1330,sed1520,serialVFD,sli,stv5730,svga,t6963,text,tyan,ula200,xosd]
=20
 drivers=3D`echo $drivers | sed -e 's/,/ /g'`
=20
@@ -271,6 +271,23 @@ dnl				else
 			DRIVERS=3D"$DRIVERS NoritakeVFD${SO}"
 			actdrivers=3D["$actdrivers NoritakeVFD"]
 			;;
+		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       =20
+				AC_MSG_WARN([The picolcd driver needs widgets.h, usblcd.h and usblcd=
_util.h from the usblcd package])
+			])      =20
+			;;      =20
 		pyramid)
 			DRIVERS=3D"$DRIVERS pyramid${SO}"
 			actdrivers=3D["$actdrivers pyramid"]
@@ -391,6 +408,7 @@ AC_SUBST(LIBG15)
 AC_SUBST(LIBGLCD)
 AC_SUBST(LIBFTDI)
 AC_SUBST(LIBXOSD)
+AC_SUBST(LIBUSBLCD)
 ])
=20
=20
diff -uNrp lcdproc-0.5.1-orig/docs/LCDd.8.in lcdproc-0.5.1/docs/LCDd.8.in=

--- lcdproc-0.5.1-orig/docs/LCDd.8.in	2006-10-04 09:18:26.000000000 -0600=

+++ lcdproc-0.5.1/docs/LCDd.8.in	2007-03-12 13:59:39.000000000 -0600
@@ -192,6 +192,9 @@ Matrix Orbital displays (except Matrix O
 .B NoritakeVFD
 Noritake VFD Device CU20045SCPB-T28A
 .TP
+.B picolcd
+Mini-box.com USB LCD (picoLCD 20x2)
+.TP
 .B pyramid
 LCD displays from Pyramid (http://www.pyramid.de)=20
 .TP
diff -uNrp lcdproc-0.5.1-orig/docs/lcdproc-user/drivers/picolcd.docbook l=
cdproc-0.5.1/docs/lcdproc-user/drivers/picolcd.docbook
--- lcdproc-0.5.1-orig/docs/lcdproc-user/drivers/picolcd.docbook	1969-12-=
31 17:00:00.000000000 -0700
+++ lcdproc-0.5.1/docs/lcdproc-user/drivers/picolcd.docbook	2007-03-12 13=
:53:17.000000000 -0600
@@ -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.1-orig/docs/lcdproc-user/drivers.docbook lcdproc-0=
=2E5.1/docs/lcdproc-user/drivers.docbook
--- lcdproc-0.5.1-orig/docs/lcdproc-user/drivers.docbook	2006-10-06 01:02=
:46.000000000 -0600
+++ lcdproc-0.5.1/docs/lcdproc-user/drivers.docbook	2007-03-12 14:00:22.0=
00000000 -0600
@@ -32,6 +32,7 @@ well as the configuration of LCDd.
 &mtc_s16209x;
 &MtxOrb;
 &NoritakeVFD;
+&picolcd;
 &pylcd;
 &sed1330;
 &sed1520;
diff -uNrp lcdproc-0.5.1-orig/LCDd.conf lcdproc-0.5.1/LCDd.conf
--- lcdproc-0.5.1-orig/LCDd.conf	2006-10-08 01:02:29.000000000 -0600
+++ lcdproc-0.5.1/LCDd.conf	2007-03-12 13:54:51.000000000 -0600
@@ -39,7 +39,7 @@
 #   bayrad, CFontz, CFontz633, CFontzPacket, curses, CwLnx, EyeboxOne,
 #   g15, glcdlib, glk, hd44780, icp_a106, imon, IOWarrior, irman,
 #   joy, lb216,lcdm001, lcterm, lirc,MD8800, ms6931, mtc_s16209x,
-#   MtxOrb, NoritakeVFD, pyramid, sed1330, sed1520, serialVFD,
+#   MtxOrb, NoritakeVFD, picolcd, pyramid, sed1330, sed1520, serialVFD,
 #   sli, stv5730, svga, t6963, text, tyan, ula200, xosd
 Driver=3Dcurses
=20
@@ -681,6 +681,38 @@ Speed=3D9600
=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.  1000 is the default.
+Contrast=3D1000
+
+# 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
+
+
+
 ## Pyramid LCD driver ##
 [pyramid]
=20
diff -uNrp lcdproc-0.5.1-orig/server/drivers/Makefile.am lcdproc-0.5.1/se=
rver/drivers/Makefile.am
--- lcdproc-0.5.1-orig/server/drivers/Makefile.am	2006-10-06 01:02:47.000=
000000 -0600
+++ lcdproc-0.5.1/server/drivers/Makefile.am	2007-03-12 14:01:36.00000000=
0 -0600
@@ -19,7 +19,7 @@ AM_LDFLAGS =3D @LDSHARED@
 #LIBS =3D
=20
 pkglib_PROGRAMS =3D @DRIVERS@
-EXTRA_PROGRAMS =3D bayrad CFontz CFontz633 CFontzPacket curses CwLnx Eye=
boxOne g15 glcdlib glk hd44780 icp_a106 imon IOWarrior irman joy lb216 lc=
dm001 lcterm lirc MD8800 ms6931 mtc_s16209x MtxOrb NoritakeVFD pyramid se=
d1330 sed1520 serialVFD stv5730 svga t6963 text tyan sli ula200 xosd
+EXTRA_PROGRAMS =3D bayrad CFontz CFontz633 CFontzPacket curses CwLnx Eye=
boxOne g15 glcdlib glk hd44780 icp_a106 imon IOWarrior irman joy lb216 lc=
dm001 lcterm lirc MD8800 ms6931 mtc_s16209x MtxOrb NoritakeVFD picolcd py=
ramid sed1330 sed1520 serialVFD stv5730 svga t6963 text tyan sli ula200 x=
osd
 noinst_LIBRARIES =3D libLCD.a libbignum.a
=20
 IOWarrior_CFLAGS =3D   @libusb_cflags@ $(AM_CFLAGS)
@@ -45,6 +45,7 @@ MD8800_LDADD =3D       libLCD.a
 mtc_s16209x_LDADD =3D  libLCD.a
 MtxOrb_LDADD =3D       libLCD.a libbignum.a
 NoritakeVFD_LDADD =3D  libLCD.a
+picolcd_LDADD =3D      libLCD.a @LIBUSBLCD@
 pyramid_LDADD =3D      libLCD.a
 serialVFD_LDADD =3D    libLCD.a libbignum.a
 svga_LDADD =3D         @LIBSVGA@
@@ -84,6 +85,7 @@ ms6931_SOURCES =3D     lcd.h lcd_lib.h ms6
 mtc_s16209x_SOURCES =3D  lcd.h lcd_lib.h mtc_s16209x.c mtc_s16209x.h rep=
ort.h
 MtxOrb_SOURCES =3D     lcd.h lcd_lib.h MtxOrb.c MtxOrb.h report.h adv_bi=
gnum.h
 NoritakeVFD_SOURCES =3D lcd.h lcd_lib.h NoritakeVFD.c NoritakeVFD.h repo=
rt.h
+picolcd_SOURCES =3D    lcd.h picolcd.h picolcd.c report.h
 pyramid_SOURCES =3D    lcd.h pylcd.c pylcd.h
 sed1330_SOURCES =3D    lcd.h sed1330.h sed1330.c port.h lpt-port.h timin=
g.h report.h
 sed1520_SOURCES =3D    lcd.h sed1520.c sed1520.h sed1520fm.c sed1520fm.h=
 port.h report.h
diff -uNrp lcdproc-0.5.1-orig/server/drivers/picolcd.c lcdproc-0.5.1/serv=
er/drivers/picolcd.c
--- lcdproc-0.5.1-orig/server/drivers/picolcd.c	1969-12-31 17:00:00.00000=
0000 -0700
+++ lcdproc-0.5.1/server/drivers/picolcd.c	2007-03-12 13:53:17.000000000 =
-0600
@@ -0,0 +1,520 @@
+/*
+ * 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  1000 /* 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_bool( drvthis->name, "BackLigh=
t",  0, DEFAULT_BACKLIGHT );
+	pd->keylights    =3D drvthis->config_get_bool( drvthis->name, "KeyLight=
s",  0, DEFAULT_KEYLIGHTS ); /* key lights with LCD Backlight? */
+	pd->key_timeout  =3D drvthis->config_get_int(  drvthis->name, "KeyTimeo=
ut", 0, DEFAULT_TIMEOUT   );
+
+	/* These allow individual lights to be disabled */
+	pd->key_light[0] =3D drvthis->config_get_bool( drvthis->name, "Key0Ligh=
t",  0, 1 ); /* Directional PAD */
+	pd->key_light[1] =3D drvthis->config_get_bool( drvthis->name, "Key1Ligh=
t",  0, 1 ); /* F1 */
+	pd->key_light[2] =3D drvthis->config_get_bool( drvthis->name, "Key2Ligh=
t",  0, 1 ); /* F2 */
+	pd->key_light[3] =3D drvthis->config_get_bool( drvthis->name, "Key3Ligh=
t",  0, 1 ); /* F3 */
+	pd->key_light[4] =3D drvthis->config_get_bool( drvthis->name, "Key4Ligh=
t",  0, 1 ); /* F4 */
+	pd->key_light[5] =3D drvthis->config_get_bool( drvthis->name, "Key5Ligh=
t",  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;
+	int inv; /* The hardware seems to go dark on higher values, so we turn =
it around */
+
+	if ( promille <=3D 1000 && promille > 0 ) {
+		inv =3D 1000 - promille;
+		pd->lcd->contrast( pd->lcd, ( int ) ( inv / 1000 * 40 ) );
+		return 0;
+	} else if ( promille > 1000 ) {
+		pd->lcd->contrast( pd->lcd,  0 );
+		return 0;
+	} else if ( promille <=3D 0 ) {
+		pd->lcd->contrast( pd->lcd,  40 );
+		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.1-orig/server/drivers/picolcd.h lcdproc-0.5.1/serv=
er/drivers/picolcd.h
--- lcdproc-0.5.1-orig/server/drivers/picolcd.h	1969-12-31 17:00:00.00000=
0000 -0700
+++ lcdproc-0.5.1/server/drivers/picolcd.h	2007-03-12 13:53:17.000000000 =
-0600
@@ -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

--------------020204080900060403060904--

--------------enig035A41FDBCE5322AEFADF467
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

iD8DBQFF9bcUHnsUla8nzK0RA+GoAJ91UXqEHLJVq2Uz8cuggH8QTcaeVwCfdXP/
HJT4HNcExw4jYk2tmp2kbjg=
=Rt1M
-----END PGP SIGNATURE-----

--------------enig035A41FDBCE5322AEFADF467--