New Driver: parallax
"Markus Dolze" <[email protected]> Sat, 21 Jan 2012 20:46:32 +0100
| Newsgroups | gmane.comp.sysutils.lcdproc |
|---|---|
| Message-ID | <[email protected]> |
Hi everyone, attached you will find a driver for Parallax serial displays: 2 rows x 16 characters Non-backlit with Piezospeaker (#27976) 2 rows x 16 characters Backlit with Piezospeaker (#27977) 4 rows x 20 characters Backlit with Piezospeaker (#27979) I wrote this driver some weeks ago on user's request, but didn't get any feedback if it works or not. So if it happens that you own such a device, please give it a try. The driver is still incomplete (misses documentation) and will not be committed for now until someone finds it is usable. Regards, Markus _______________________________________________ LCDproc mailing list [email protected] http://lists.omnipotent.net/mailman/listinfo/lcdproc
parallax-driver.diff
(application/octet-stream, 19.2 KB)
Index: LCDd.conf
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/LCDd.conf,v
retrieving revision 1.161
diff -u -r1.161 LCDd.conf
--- LCDd.conf 30 Dec 2011 01:08:17 -0000 1.161
+++ LCDd.conf 21 Jan 2012 14:41:26 -0000
@@ -927,6 +927,21 @@
+## Parallax Inc. serial LCD driver ##
+[parallax]
+# Select the output device to use [default: /dev/lcd]
+Device=/dev/lcd
+
+# Set the communication speed of the serial port
+# [default: 19200; legal: 2400, 9600, 19200]
+#Speed=19200
+
+# Select the display type. The screen size and backlight are automatically
+# set from this value. [default: 27977; legal: 27976, 27977, 27979]
+Model=27977
+
+
+
## Mini-box.com picoLCD (usblcd) driver ##
[picolcd]
Index: acinclude.m4
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/acinclude.m4,v
retrieving revision 1.123
diff -u -r1.123 acinclude.m4
--- acinclude.m4 10 Dec 2011 15:39:46 -0000 1.123
+++ acinclude.m4 21 Jan 2012 14:41:27 -0000
@@ -13,7 +13,7 @@
[ icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,]
[ joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,]
[ ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,]
- [ picolcd,pyramid,sed1330,sed1520,serialPOS,]
+ [ parallax,picolcd,pyramid,sed1330,sed1520,serialPOS,]
[ serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,]
[ t6963,text,tyan,ula200,vlsys_m428,xosd]
[ ]
@@ -22,7 +22,7 @@
drivers="$enableval",
drivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,glk,lb216,lcdm001,MtxOrb,pyramid,text])
-allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,vlsys_m428,xosd]
+allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,parallax,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,vlsys_m428,xosd]
if test "$debug" = yes; then
allDrivers=["${allDrivers},debug"]
fi
@@ -377,6 +377,10 @@
DRIVERS="$DRIVERS NoritakeVFD${SO}"
actdrivers=["$actdrivers NoritakeVFD"]
;;
+ parallax)
+ DRIVERS="$DRIVERS parallax${SO}"
+ actdrivers=["$actdrivers parallax"]
+ ;;
picolcd)
if test "$enable_libusb" = yes ; then
DRIVERS="$DRIVERS picolcd${SO}"
Index: server/drivers/Makefile.am
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/Makefile.am,v
retrieving revision 1.106
diff -u -r1.106 Makefile.am
--- server/drivers/Makefile.am 10 Dec 2011 15:39:47 -0000 1.106
+++ server/drivers/Makefile.am 21 Jan 2012 14:41:27 -0000
@@ -22,7 +22,7 @@
## Keep the lists sorted!
pkglib_PROGRAMS = @DRIVERS@
-EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses debug CwLnx ea65 EyeboxOne g15 glcd glcdlib glk hd44780 icp_a106 imon imonlcd IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 SureElec svga t6963 text tyan sli ula200 vlsys_m428 xosd i2500vfd irtrans
+EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses debug CwLnx ea65 EyeboxOne g15 glcd glcdlib glk hd44780 icp_a106 imon imonlcd IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD parallax picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 SureElec svga t6963 text tyan sli ula200 vlsys_m428 xosd i2500vfd irtrans
noinst_LIBRARIES = libLCD.a libbignum.a
g15_CFLAGS = @LIBUSB_CFLAGS@ $(AM_CFLAGS)
@@ -63,6 +63,7 @@
MtxOrb_LDADD = libLCD.a libbignum.a
mx5000_LDADD = @LIBMX5000@
NoritakeVFD_LDADD = libbignum.a
+parallax_LDADD = libLCD.a libbignum.a
picolcd_LDADD = @LIBUSB_LIBS@ @LIBUSB_1_0_LIBS@ libLCD.a libbignum.a
pyramid_LDADD = libLCD.a libbignum.a
serialPOS_LDADD = libbignum.a
@@ -114,6 +115,7 @@
MtxOrb_SOURCES = lcd.h lcd_lib.h MtxOrb.c MtxOrb.h report.h adv_bignum.h
mx5000_SOURCES = lcd.h mx5000.c mx5000.h report.h
NoritakeVFD_SOURCES = lcd.h lcd_lib.h NoritakeVFD.c NoritakeVFD.h report.h adv_bignum.h
+parallax_SOURCES = lcd.h lcd_lib.h report.h adv_bignum.h parallax.c parallax.h
picolcd_SOURCES = lcd.h picolcd.h picolcd.c report.h
pyramid_SOURCES = lcd.h pylcd.c pylcd.h
sed1330_SOURCES = lcd.h sed1330.h sed1330.c port.h lpt-port.h timing.h report.h
--- /dev/null 2012-01-21 15:40:33.000000000 +0100
+++ server/drivers/parallax.c 2011-12-04 17:06:39.000000000 +0100
@@ -0,0 +1,551 @@
+/** \file server/drivers/parallax.c
+ * \c parallax driver for serial LCD devices made by Parallax Inc.
+ */
+
+/*-
+ * Copyright (C) 2011, Markus Dolze
+ *
+ * This file is released under the GNU General Public License. Refer to the
+ * COPYING file distributed with this package.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "lcd.h"
+#include "parallax.h"
+#include "report.h"
+#include "lcd_lib.h"
+#include "adv_bignum.h"
+
+#define DEFAULT_DEVICE "/dev/lcd"
+#define DEFAULT_SPEED 19200
+#define DEFAULT_MODEL "27977"
+#define NUM_CC 8
+
+
+/** private data for the \c debug driver */
+typedef struct parallax_private_data {
+ char *framebuf; /**< frame buffer */
+ int fd; /**< file descriptor of serial port */
+ int width; /**< display width in characters */
+ int height; /**< display height in characters */
+ int cellwidth; /**< character cell width */
+ int cellheight; /**< character cell height */
+ int have_backlight; /**< flag if the display has a backlight */
+ CGmode ccmode; /**< Custom character mode */
+} PrivateData;
+
+
+/* Vars for the server core */
+MODULE_EXPORT char *api_version = API_VERSION;
+MODULE_EXPORT int stay_in_foreground = 0;
+MODULE_EXPORT int supports_multiple = 1;
+MODULE_EXPORT char *symbol_prefix = "parallax_";
+
+/**
+ * API: Initialize the driver.
+ */
+MODULE_EXPORT int
+parallax_init(Driver *drvthis)
+{
+ PrivateData *p;
+ char device[256];
+ int speed;
+ struct termios portset;
+ const char *str;
+ char out[1];
+
+ report(RPT_INFO, "%s()", __FUNCTION__);
+
+ /* Allocate and store private data */
+ p = (PrivateData *) calloc(1, sizeof(PrivateData));
+ if (p == NULL)
+ return -1;
+ if (drvthis->store_private_ptr(drvthis, p))
+ return -1;
+
+ /* Initialize private data */
+ p->cellwidth = LCD_DEFAULT_CELLWIDTH;
+ p->cellheight = LCD_DEFAULT_CELLHEIGHT;
+ p->ccmode = standard;
+
+ /* Get configuration from config file */
+ strncpy(device, drvthis->config_get_string(drvthis->name, "Device", 0,
+ DEFAULT_DEVICE), sizeof(device));
+ device[sizeof(device)-1] = '\0';
+ report(RPT_INFO, "%s: using Device %s", drvthis->name, device);
+
+ speed = drvthis->config_get_int(drvthis->name, "Speed", 0, DEFAULT_SPEED);
+ switch (speed) {
+ case 2400:
+ speed = B2400;
+ case 9600:
+ speed = B9600;
+ case 19200:
+ speed = B19200;
+ default:
+ report(RPT_WARNING, "%s: illegal Speed: %d; must be one of 2400, 9600, or 19200; using default %d",
+ drvthis->name, speed, 19200);
+ speed = B19200;
+ }
+
+ str = drvthis->config_get_string(drvthis->name, "Model", 0, DEFAULT_MODEL);
+ if (strcasecmp(str, "27976") == 0) {
+ p->width = 16;
+ p->height = 2;
+ p->have_backlight = 0;
+ }
+ else if (strcasecmp(str, "27977") == 0) {
+ p->width = 16;
+ p->height = 2;
+ p->have_backlight = 1;
+ }
+ else if (strcasecmp(str, "27979") == 0) {
+ p->width = 20;
+ p->height = 4;
+ p->have_backlight = 1;
+ }
+ else {
+ report(RPT_WARNING, "%s: Unknown model; using defaults for 27977",
+ drvthis->name);
+ p->width = 16;
+ p->height = 2;
+ p->have_backlight = 1;
+ }
+
+ /* Allocate and clear frame buffer */
+ p->framebuf = malloc(p->width * p->height);
+ if (p->framebuf == NULL) {
+ report(RPT_INFO, "%s: unable to allocate framebuffer", drvthis->name);
+ return -1;
+ }
+ memset(p->framebuf, ' ', p->width * p->height);
+
+ /* Open and configure serial port */
+ if ((p->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY)) == -1) {
+ report(RPT_ERR, "%s: open(%s) failed (%s)", drvthis->name, device, strerror(errno));
+ return -1;
+ }
+ report(RPT_DEBUG, "%s: opened device %s", drvthis->name, device);
+
+ tcgetattr(p->fd, &portset);
+#ifdef HAVE_CFMAKERAW
+ cfmakeraw(&portset);
+#else
+ portset.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
+ | INLCR | IGNCR | ICRNL | IXON );
+ portset.c_oflag &= ~OPOST;
+ portset.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
+ portset.c_cflag &= ~( CSIZE | PARENB | CRTSCTS );
+ portset.c_cflag |= CS8 | CREAD | CLOCAL ;
+#endif
+ cfsetospeed(&portset, speed);
+ cfsetispeed(&portset, B0);
+ tcsetattr(p->fd, TCSANOW, &portset);
+
+ /* Clear display and set cursor home */
+ out[0] = 0x0C;
+ write(p->fd, out, 1);
+ usleep(5000);
+ out[0] = 0x16;
+ write(p->fd, out, 1);
+
+ return 0;
+}
+
+
+/**
+ * API: Close the driver (do necessary clean-up).
+ */
+MODULE_EXPORT void
+parallax_close(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ report(RPT_INFO, "%s()", __FUNCTION__);
+
+ if (p != NULL) {
+ if (p->fd >= 0)
+ close(p->fd);
+
+ if (p->framebuf != NULL)
+ free(p->framebuf);
+ p->framebuf = NULL;
+
+ free(p);
+ }
+ drvthis->store_private_ptr(drvthis, NULL);
+}
+
+
+/**
+ * API: Return the display width in characters.
+ */
+MODULE_EXPORT int
+parallax_width(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ return p->width;
+}
+
+
+/**
+ * API: Return the display height in characters.
+ */
+MODULE_EXPORT int
+parallax_height(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ return p->height;
+}
+
+
+/**
+ * API: Return the width of a character in pixels.
+ */
+MODULE_EXPORT int
+parallax_cellwidth(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ return p->cellwidth;
+}
+
+
+/**
+ * API: Return the height of a character in pixels.
+ */
+MODULE_EXPORT int
+parallax_cellheight(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ return p->cellheight;
+}
+
+
+/**
+ * API: Clear the screen.
+ */
+MODULE_EXPORT void
+parallax_clear(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+
+ memset(p->framebuf, ' ', p->width * p->height);
+ p->ccmode = standard;
+}
+
+
+/**
+ * API: Flush data on screen to the display.
+ */
+MODULE_EXPORT void
+parallax_flush(Driver *drvthis)
+{
+ PrivateData *p = drvthis->private_data;
+ int row;
+ unsigned char out[1];
+
+ /* Move cursor to line 0, position 0 */
+ out[0] = 0x80;
+ write(p->fd, out, 1);
+
+ for (row = 0; row < p->height; row++) {
+ write(p->fd, p->framebuf + row * p->width, p->width);
+ usleep(1000);
+ }
+}
+
+
+/**
+ * API: Print a string on the screen at position (x,y).
+ * \note The Parallax serial displays supported by this driver only allow
+ * diplay of visible ASCII characters in the range 32-127. Characters
+ * outside this range are used as control characters. Those are replaced
+ * by '_' (underscore) if they appear as input to this function.
+ */
+MODULE_EXPORT void
+parallax_string(Driver *drvthis, int x, int y, const char string[])
+{
+ PrivateData *p = drvthis->private_data;
+ int i;
+
+ y--; /* Convert 1-based coords to 0-based... */
+ x--;
+
+ if ((y < 0) || (y >= p->height))
+ return;
+
+ for (i = 0; (string[i] != '\0') && (x < p->width); i++, x++) {
+ if (x >= 0) {
+ if (string[i] >= 32 && string[i] <= 126)
+ p->framebuf[(y * p->width) + x] = string[i];
+ else
+ p->framebuf[(y * p->width) + x] = '_';
+ }
+ }
+}
+
+
+/**
+ * API: Print a character on the screen at position (x,y).
+ * \see parallax_string
+ */
+MODULE_EXPORT void
+parallax_chr(Driver *drvthis, int x, int y, char c)
+{
+ PrivateData *p = drvthis->private_data;
+
+ x--; /* Convert 1-based coords to 0-based... */
+ y--;
+
+ if (x >= 0 && y >= 0 && x < p->width && y < p->height) {
+ if ((c >= 0 && c <= 7) || (c >= 32 && c <= 126))
+ p->framebuf[(y * p->width) + x] = c;
+ else
+ p->framebuf[(y * p->width) + x] = '_';
+ }
+}
+
+
+/**
+ * API: Draw a vertical bar bottom-up.
+ */
+MODULE_EXPORT void
+parallax_vbar(Driver *drvthis, int x, int y, int len, int promille, int options)
+{
+ PrivateData *p = drvthis->private_data;
+ static unsigned char vbar_char[7][8] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F},
+ {0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F},
+ {0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F},
+ {0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F},
+ {0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}
+ /* Full block is done using icon */
+ };
+
+ if (p->ccmode != vbar) {
+ int i;
+
+ if (p->ccmode != standard) {
+ report(RPT_WARNING, "%s: hbar: cannot combine two modes using user-defined characters",
+ drvthis->name);
+ return;
+ }
+
+ p->ccmode = vbar;
+ for (i = 0; i < 7; i++)
+ parallax_set_char(drvthis, i + 1, vbar_char[i]);
+ }
+
+ lib_vbar_static(drvthis, x, y, len, promille, options, p->cellheight, 0);
+}
+
+
+/**
+ * API: Draw a horizontal bar to the right.
+ */
+MODULE_EXPORT void
+parallax_hbar(Driver *drvthis, int x, int y, int len, int promille, int options)
+{
+ PrivateData *p = drvthis->private_data;
+ static unsigned char hbar_char[4][8] = {
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
+ {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C},
+ {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E}
+ /* Full block is done using icon */
+ };
+
+ if (p->ccmode != hbar) {
+ int i;
+
+ if (p->ccmode != standard) {
+ report(RPT_WARNING, "%s: hbar: cannot combine two modes using user-defined characters",
+ drvthis->name);
+ return;
+ }
+
+ p->ccmode = hbar;
+ for (i = 0; i < 4; i++)
+ parallax_set_char(drvthis, i + 1, hbar_char[i]);
+ }
+
+ lib_hbar_static(drvthis, x, y, len, promille, options, p->cellwidth, 0);
+}
+
+
+/**
+ * API: Write a big number to the screen.
+ */
+MODULE_EXPORT void
+parallax_num(Driver *drvthis, int x, int num)
+{
+ PrivateData *p = drvthis->private_data;
+ int do_init = 0;
+
+ if ((num < 0) || (num > 10))
+ return;
+
+ if (p->ccmode != bignum) {
+ if (p->ccmode != standard) {
+ report(RPT_WARNING, "%s: num: cannot combine two modes using user-defined characters",
+ drvthis->name);
+ return;
+ }
+ p->ccmode = bignum;
+ do_init = 1;
+ }
+
+ lib_adv_bignum(drvthis, x, num, 0, do_init);
+}
+
+
+/**
+ * API: Place an icon on the screen.
+ * \note Parallax serial displays to not allow access to the full block
+ * character as its code (usually 0xFF) is used by a control command.
+ * Thus the full block is implemented using a custom character.
+ */
+MODULE_EXPORT int
+parallax_icon(Driver *drvthis, int x, int y, int icon)
+{
+ PrivateData *p = drvthis->private_data;
+
+ static unsigned char heart_open[] =
+ { b__XXXXX,
+ b__X_X_X,
+ b_______,
+ b_______,
+ b_______,
+ b__X___X,
+ b__XX_XX,
+ b__XXXXX };
+ static unsigned char heart_filled[] =
+ { b__XXXXX,
+ b__X_X_X,
+ b___X_X_,
+ b___XXX_,
+ b___XXX_,
+ b__X_X_X,
+ b__XX_XX,
+ b__XXXXX };
+ static unsigned char block_filled[] =
+ { b__XXXXX,
+ b__XXXXX,
+ b__XXXXX,
+ b__XXXXX,
+ b__XXXXX,
+ b__XXXXX,
+ b__XXXXX,
+ b__XXXXX };
+
+ /* The full block works except if ccmode=bignum */
+ if (icon == ICON_BLOCK_FILLED) {
+ if (p->ccmode != bignum) {
+ parallax_set_char(drvthis, 0, block_filled);
+ parallax_chr(drvthis, x, y, 0);
+ return 0;
+ }
+ else {
+ return -1;
+ }
+ }
+
+ /* The heartbeat icons do not work in bignum and vbar mode */
+ if ((icon == ICON_HEART_FILLED) || (icon == ICON_HEART_OPEN)) {
+ if ((p->ccmode != bignum) && (p->ccmode != vbar)) {
+ switch (icon) {
+ case ICON_HEART_FILLED:
+ parallax_set_char(drvthis, 7, heart_filled);
+ parallax_chr(drvthis, x, y, 7);
+ return 0;
+ case ICON_HEART_OPEN:
+ parallax_set_char(drvthis, 7, heart_open);
+ parallax_chr(drvthis, x, y, 7);
+ return 0;
+ }
+ }
+ else {
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+
+/**
+ * API: Define a custom character and write it to the LCD.
+ * \note Parallax serial displays can use custom characters at values 0x00 -
+ * 0x07. To set those characters the corresponding 'define custom
+ * character' command has to be sent (value 0xF8 - 0xFF).
+ */
+MODULE_EXPORT void
+parallax_set_char(Driver *drvthis, int n, unsigned char *dat)
+{
+ PrivateData *p = drvthis->private_data;
+ char out[9];
+ int row;
+
+ if ((n < 0) || (n > 7) || (!dat))
+ return;
+
+ memset(out, '\0', 9);
+ out[0] = 0xF8 + n;
+
+ for (row = 0; row < p->cellheight && row < 8; row++)
+ out[1 + row] = dat[row] & 0x1F;
+
+ write(p->fd, out, 9);
+}
+
+
+/**
+ * API: Get total number of custom characters available.
+ */
+MODULE_EXPORT int
+parallax_get_free_chars(Driver *drvthis)
+{
+ return NUM_CC;
+}
+
+
+/**
+ * API: Turn the backlight on or off.
+ */
+MODULE_EXPORT void
+parallax_backlight(Driver *drvthis, int state)
+{
+ PrivateData *p = drvthis->private_data;
+
+ if (p->have_backlight) {
+ char out[1];
+ if (state == BACKLIGHT_ON)
+ out[0] = 0x11;
+ else
+ out[0] = 0x12;
+ write(p->fd, out, 1);
+ }
+}
+
+
+/**
+ * API: Provide some information about this driver.
+ */
+MODULE_EXPORT const char *
+parallax_get_info(Driver *drvthis)
+{
+ static char *info_string = "Parallax Inc. serial LCD driver";
+ return info_string;
+}
--- /dev/null 2012-01-21 15:40:33.000000000 +0100
+++ server/drivers/parallax.h 2011-12-04 16:26:21.000000000 +0100
@@ -0,0 +1,26 @@
+#ifndef LCD_PARALLAX_H
+#define LCD_PARALLAX_H
+
+MODULE_EXPORT int parallax_init (Driver *drvthis);
+MODULE_EXPORT void parallax_close (Driver *drvthis);
+MODULE_EXPORT int parallax_width (Driver *drvthis);
+MODULE_EXPORT int parallax_height (Driver *drvthis);
+MODULE_EXPORT int parallax_cellwidth (Driver *drvthis);
+MODULE_EXPORT int parallax_cellheight (Driver *drvthis);
+MODULE_EXPORT void parallax_clear (Driver *drvthis);
+MODULE_EXPORT void parallax_flush (Driver *drvthis);
+MODULE_EXPORT void parallax_string (Driver *drvthis, int x, int y, const char string[]);
+MODULE_EXPORT void parallax_chr (Driver *drvthis, int x, int y, char c);
+
+MODULE_EXPORT void parallax_vbar (Driver *drvthis, int x, int y, int len, int promille, int options);
+MODULE_EXPORT void parallax_hbar (Driver *drvthis, int x, int y, int len, int promille, int options);
+MODULE_EXPORT void parallax_num (Driver *drvthis, int x, int num);
+MODULE_EXPORT int parallax_icon (Driver *drvthis, int x, int y, int icon);
+MODULE_EXPORT void parallax_set_char (Driver *drvthis, int n, unsigned char *dat);
+MODULE_EXPORT int parallax_get_free_chars(Driver *drvthis);
+
+MODULE_EXPORT void parallax_backlight (Driver *drvthis, int promille);
+
+MODULE_EXPORT const char *parallax_get_info (Driver *drvthis);
+
+#endif