[Lcdproc] serialVFD driver update

Stefan Herdler herdler@gmx.de
Wed May 17 16:11:02 2006


This is a multi-part message in MIME format.
--------------090006010607090701090706
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit

Hi,

I've updated the serialVFD driver. Many changes and improvements have 
been made since the last version.
This are the important ones:
 - Support for parallel connection added.
 - Improved user-character handling to reduce data send to the display 
(fixes flicker and reduces cpuload slightly).
 - Backlight and brightness functions revised. The client can switch 
between 2 brightnesslevels like in the CFontzPacket-driver.
 - Driver has been successfully tested on a FUTABA M402SD06GL VFD. 
Thanks to Robert Buchholz.
 - Documentation updated.

Stefan

--------------090006010607090701090706
Content-Type: text/plain;
 name="serialVFD_0.3.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="serialVFD_0.3.diff"

--- ../lcdproc-CVS-current-test/server/drivers/serialVFD.c	2006-04-28 09:00:36.000000000 +0200
+++ ./server/drivers/serialVFD.c	2006-05-17 16:16:45.000000000 +0200
@@ -6,7 +6,7 @@
 	driver.
 	It may contain parts of other drivers of this package too.
 
-	2006-02-13 Version 0.2: everything should work (not all hardware tested!)
+	2006-05-16 Version 0.3: everything should work (not all hardware tested!)
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
@@ -24,120 +24,9 @@
 
 
 
-	The serialVFD-driver should work with all NEC FIPC8367 based VFDs:
-	NEC FC20X2JA
-	NEC FM20X2KB-AB
-	NEC FC20X1SA-AB/AA
-	...
-	Tested only on: NEC FM20X2KB-AB
-	The driver also works (tested) on "KD Rev 2.1" (an ATMEL AT90S....
-	based FM20X2KB-AB replacement).
-	Note: Above char. 128 the FIPC-displays and KD's charactersets
-	are different.
-
-	The driver may work or will be easy to get working on the following
-	Displays / Controllers (not tested!).
-	Display:		Controller:
-	FUTABA M204SD01AA	FUTABA 5P00A016
-	Noritake CU20026SCPB-T	(microcontroller)
-	Noritake CU20045SCPB-T28A	?
-	... or compatible.
-	(most Futaba/Noritake 7x5 dot VFDs with serial(rs232) interface
-	(including  serial(rs232)/parallel types))
-	Maybe there are little changes in the commands to do to get all
-	functions to work correctly. But because of the similarity of the
-	protocols, it wont be much work.
-
-	If you want to add a new device to the driver add a new section
-	to the displaytype-switch-case in the init-function and fill it
-	with the corrrect commands for the display.
-	(Try wich displaytype works best with your display, copy and modify
-	it's section that is the easiest way I guess.)
-
-
-        On this page I found pictures and datasheets of the VFD's:
-	http://www.maltepoeggel.de/html/vfd/index.html
-
-
-
-
-	To enable the bignumbers on 2-line displays (only this driver supports
-	this yet) you have to edit "/clients/lcdproc/chrono.c" before compiling.
-	In function "big_clock_screen" you have to replace the "4" by a "2" in
-	this line: "if (lcd_hgt < 4)".
-
-
-
-	This driver uses the serial mode of the displays.
-	It is NOT possible to connect most of the displays directly to the
-	serialport. The signal has to be inverted. I use the following
-	circuit to do that job.
-
-	Computer                                          Display
-	                                                  (signal)
-	HDD Powerconnector
-	color(Voltage)
-
-	red(+5V)    --------------------------------o----- +5V
-	                                            |
-	black(GND)  --------------------o           |
-	                                |           R
-	                                |           R 10k
-	Serial(SUB-D 9Pin female)       V*          R
-	pin(signal)                                 |
-	                                            |
-	3(TxD)  --RRRR--o--o      o-----------------o----- RxD
-	          10k   |  |      |
-	                |  |     C|
-	                |  |   -----  BC547c (or similar NPN)
-	                R  | B|  /  |
-	            10k R  o--|-|   |
-	                R     |  \  |
-	                |      --->-    A*
-	                |         E|    |
-	                |          |    |
-	5(GND)  --------o----------o----o----------------- GND
-
-	Shield  ------------------------------------------
-	optional
-
-	*connect near display
-
-
-	The pins on the different displays vary.
-
-
-
-	FM20X2KB-AB:
-
-	CN1:
-	Pin 33 <--- RxD
-	(Testmode: connect pins 25 & 26 then power up)
-
-	CN2:
-	Pin 1  <--- +5V
-	Pin 2  ---- GND
-
-
-
-	KD Rev 2.1:
-
-	blue connector (6pin in a row) (the important one!):
-	--------------------------------
-	| +5V  +5V  RxD  GND  GND  GND |
-	--------------------------------
-	NOTE: hold the display in that position where you can read
-	the "KD Rev 2.1" marking normally!
-
-	gray connector (10pin 2 rows):
-	Do not use. (the ATMEL ISP connector I guess)
-
-	The two jumpers next to the gray connector:
-	Normally not used.
-	You can activate two different testmodes with them.
-
-
-
+	The driver should operate most of NEC, Futaba and Noritake 7x5 dot VFDs with
+	serial(rs232) and/or parallel interface. See /docs/lcdproc-user/serialvfd-howto.html
+	for further information
 
 
 List of driver entry point:
@@ -147,7 +36,7 @@ close		Implemented.
 width		Implemented.
 height		Implemented.
 clear		Implemented by space filling no custom char info.
-flush		Calling draw_frame only.
+flush		Implemented.
 string		Implemented.
 chr		Implemented.
 vbar		Implemented.
@@ -164,7 +53,7 @@ get_contrast	Not implemented, no softwar
 set_contrast	Not implemented, no software control.
 get_brightness	Implemented.
 set_brightness	Implemented.
-backlight	Not implemented, no software control.
+backlight	Implemented.
 output		Not implemented.
 get_key		Not implemented, no keys.
 get_info	Implemented.
@@ -185,6 +74,7 @@ get_info	Implemented.
 # include "config.h"
 #endif
 
+
 #include "lcd.h"
 #include "serialVFD.h"
 
@@ -192,41 +82,16 @@ get_info	Implemented.
 #include "lcd_lib.h"
 #include "adv_bignum.h"
 
+#define DEFAULT_OFF_BRIGHTNESS	300
+#define DEFAULT_ON_BRIGHTNESS	1000
+
 #define pos1_cursor	4 //moves cursor to top left character.
 #define mv_cursor	5 //moves cursor to position specified by the next byte.
 #define reset		6 //reset
 #define init_cmds	7 //commands needed to initialize the display.
 #define set_user_char	8 //set user character.
 #define hor_tab		9 //moves cursor 1 chr right
-
-typedef struct driver_private_data {
-	char device[200];
-	int fd;
-	int speed;
-	/* dimensions */
-	int width, height;
-	int cellwidth, cellheight;
-	/* framebuffer and buffer for old LCD contents */
-	unsigned char *framebuf;
-	unsigned char *backingstore;
-	/* defineable characters */
-	int ccmode;
-	int brightness;
-	int customchars;
-	int ISO_8859_1;
-	unsigned int refresh_timer;
-	unsigned char charmap[128];
-	int display_type;
-	char custom_char[31][7]; 	// used for "KD Rev 2.1" only
-	char custom_char_changed[32]; 	// used only if need_refresh==1
-	int need_refresh; 		// 1 if displays need refresh after changing custonchars
-	char hw_cmd[10][4]; 		// hardwarespecific commands
-	int usr_chr_dot_assignment[57];	// how to setup usercharacters
-	unsigned int usr_chr_mapping[31];// where to place the usercharacters (0..30) in the asciicode
-	int hbar_cc_offset;		// character offset of the bars
-	int vbar_cc_offset;		// character offset of the bars
-	char info[255];
-} PrivateData;
+#define LPTPORT 0x378
 
 /* Vars for the server core */
 MODULE_EXPORT char *api_version = API_VERSION;
@@ -237,8 +102,6 @@ MODULE_EXPORT char *symbol_prefix = "ser
 /* Internal functions */
 static void serialVFD_init_vbar (Driver *drvthis);
 static void serialVFD_init_hbar (Driver *drvthis);
-static void serialVFD_draw_frame (Driver *drvthis, unsigned char *dat);
-static void serialVFD_put_brightness (Driver *drvthis);
 static void serialVFD_put_char (Driver *drvthis, int n);
 
 // Opens com port and sets baud correctly...
@@ -246,8 +109,7 @@ static void serialVFD_put_char (Driver *
 MODULE_EXPORT int
 serialVFD_init (Driver *drvthis)
 {
-	struct termios portset;
-	int tmp, w, h, brightness;
+	int tmp, w, h;
 	char size[200] = DEFAULT_SIZE;
 
 	PrivateData *p;
@@ -265,22 +127,44 @@ serialVFD_init (Driver *drvthis)
 	p->ccmode = CCMODE_STANDARD;
 	p->ISO_8859_1 = 1;
 	p->refresh_timer = 0;
+	p->hw_brightness = 0;
 
 	debug(RPT_INFO, "%s(%p)", __FUNCTION__, drvthis );
+	
+/* Read config file */
 
-	/* Read config file */
+	p->use_parallel		= drvthis->config_get_bool( drvthis->name, "use_parallel", 0, 0 );
+	if (p->use_parallel){
+	p->port			= drvthis->config_get_int( drvthis->name, "port", 0, LPTPORT );
+	}
+	else {
 	/* Which device should be used */
-	strncpy(p->device, drvthis->config_get_string(drvthis->name, "Device", 0, DEFAULT_DEVICE), sizeof(p->device));
+	strncpy(p->device, drvthis->config_get_string (drvthis->name, "Device", 0, DEFAULT_DEVICE), sizeof(p->device));
 	p->device[sizeof(p->device)-1] = '\0';
 	report(RPT_INFO, "%s: using Device %s", drvthis->name, p->device);
 
+	/* Which speed */
+	tmp = drvthis->config_get_int (drvthis->name, "Speed", 0, DEFAULT_SPEED);
+	if ((tmp != 1200) && (tmp != 2400) && (tmp != 9600) && (tmp != 19200) && (tmp != 115200)) {
+		report(RPT_WARNING, "%s: Speed must be 1200, 2400, 9600, 19200 or 115200. Using default %d.\n",
+			drvthis->name, DEFAULT_SPEED);
+		tmp = DEFAULT_SPEED;
+	}
+	if (tmp == 1200) p->speed = B1200;
+	else if (tmp == 2400) p->speed = B2400;
+	else if (tmp == 9600) p->speed = B9600;
+	else if (tmp == 19200) p->speed = B19200;
+	else if (tmp == 115200) p->speed = B115200;
+	}
+//	report(RPT_ERR, "%s: Port: %X\n", __FUNCTION__, p->port, strerror (errno));
+
 	/* Which size */
 	strncpy(size, drvthis->config_get_string(drvthis->name, "Size", 0, DEFAULT_SIZE), sizeof(size));
 	size[sizeof(size)-1] = '\0';
 	if ((sscanf(size, "%dx%d", &w, &h) != 2)
 	    || (w <= 0) || (w > LCD_MAX_WIDTH)
 	    || (h <= 0) || (h > LCD_MAX_HEIGHT)) {
-		report(RPT_WARNING, "%s: cannot parse Size: %s; using default %s",
+		report(RPT_WARNING, "%s: cannot parse size: %s; using default %s.",
 			drvthis->name, size, DEFAULT_SIZE);
 		sscanf(DEFAULT_SIZE, "%dx%d", &w, &h);
 	}
@@ -288,14 +172,24 @@ serialVFD_init (Driver *drvthis)
 	p->height = h;
 
 	/* Which backlight brightness */
-	tmp = drvthis->config_get_int(drvthis->name, "Brightness", 0, DEFAULT_BRIGHTNESS);
+	tmp = drvthis->config_get_int(drvthis->name, "Brightness", 0, DEFAULT_ON_BRIGHTNESS);
+	debug(RPT_INFO, "%s: Brightness (in config) is '%d'", __FUNCTION__, tmp);
 	if ((tmp < 0) || (tmp > 1000)) {
 		report(RPT_WARNING, "%s: Brightness must be between 0 and 1000; using default %d",
-			drvthis->name, DEFAULT_BRIGHTNESS);
-		tmp = DEFAULT_BRIGHTNESS;
+			drvthis->name, DEFAULT_ON_BRIGHTNESS);
+		tmp = DEFAULT_ON_BRIGHTNESS;
 	}
-	brightness = tmp;
+	p->on_brightness = tmp;
 
+	/* Which backlight-off "brightness" */
+	tmp = drvthis->config_get_int(drvthis->name, "OffBrightness", 0, DEFAULT_OFF_BRIGHTNESS);
+	debug(RPT_INFO, "%s: OffBrightness (in config) is '%d'", __FUNCTION__, tmp);
+	if ((tmp < 0) || (tmp > 1000)) {
+		report(RPT_WARNING, "%s: OffBrightness must be between 0 and 1000; using default %d",
+			drvthis->name, DEFAULT_OFF_BRIGHTNESS);
+		tmp = DEFAULT_OFF_BRIGHTNESS;
+	}
+	p->off_brightness = tmp;
 
 	/* ISO 8859 1 */
 	p->ISO_8859_1 = drvthis->config_get_bool(drvthis->name, "ISO_8859_1", 0, 1);
@@ -309,57 +203,29 @@ serialVFD_init (Driver *drvthis)
 	}
 	p->display_type = tmp;
 
-
-	/* Which speed */
-	tmp = drvthis->config_get_int(drvthis->name, "Speed", 0, DEFAULT_SPEED);
-	if ((tmp != 1200) && (tmp != 2400) && (tmp != 9600) && (tmp != 19200) && (tmp != 115200)) {
-		report(RPT_WARNING, "%s: Speed must be 1200, 2400, 9600, 19200 or 115200; using default %d",
-			drvthis->name, DEFAULT_SPEED);
-		tmp = DEFAULT_SPEED;
+	/* Number of custom characters */
+	tmp = drvthis->config_get_int (drvthis->name, "Custom-Characters", 0, -83);
+	if ((tmp < 0) || (tmp > 99)) {
+		report(RPT_WARNING, "%s: The number of Custom-Characters must be between 0 and 99. Using default.",
+			drvthis->name, 0);
+		tmp = -83;
 	}
-	if (tmp == 1200) p->speed = B1200;
-	else if (tmp == 2400) p->speed = B2400;
-	else if (tmp == 9600) p->speed = B9600;
-	else if (tmp == 19200) p->speed = B19200;
-	else if (tmp == 115200) p->speed = B115200;
+	p->customchars = tmp;
 
 
+//	report (RPT_ERR, "%s: Port: %X\n", __FUNCTION__, p->port, strerror (errno));
 
-	/* Set up io port correctly, and open it...*/
-	debug(RPT_DEBUG, "%s: Opening device: %s", __FUNCTION__, p->device);
-	p->fd = open(p->device, O_RDWR | O_NOCTTY | O_NDELAY);
-	if (p->fd == -1) {
-		report(RPT_ERR, "%s: open(%s) failed (%s)", drvthis->name, p->device, strerror(errno));
+// Do connection type specific io-port init
+	if (Port_Function[p->use_parallel].init_fkt (drvthis)==-1) {
+		report(RPT_ERR, "%s: unable to initialize io-port.", drvthis->name);
 		return -1;
 	}
 
-	tcgetattr(p->fd, &portset);
-
-	// We use RAW mode
-#ifdef HAVE_CFMAKERAW
-	// The easy way
-	cfmakeraw(&portset);
-#else
-		// The hard way
-	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
-
-	// Set port speed
-	cfsetospeed(&portset, p->speed);
-	cfsetispeed (&portset, B0);
-
-	// Do it...
-	tcsetattr(p->fd, TCSANOW, &portset);
-
+// setup frame buffer and backing store
 	/* make sure the frame buffer is there... */
 	p->framebuf = (unsigned char *) malloc(p->width * p->height);
 	if (p->framebuf == NULL) {
-		report(RPT_ERR, "%s: unable to create framebuffer", drvthis->name);
+		report(RPT_ERR, "%s: unable to create framebuffer.", drvthis->name);
 		return -1;
 	}
 	memset(p->framebuf, ' ', p->width * p->height);
@@ -367,318 +233,85 @@ serialVFD_init (Driver *drvthis)
 	/* make sure the framebuffer backing store is there... */
 	p->backingstore = (unsigned char *) malloc(p->width * p->height);
 	if (p->backingstore == NULL) {
-		report(RPT_ERR, "%s: unable to create framebuffer backing store", drvthis->name);
+		report(RPT_ERR, "%s: unable to create framebuffer backing store.", drvthis->name);
 		return -1;
 	}
 	memset(p->backingstore, ' ', p->width * p->height);
 
 //setup displayspecific data
-	switch (p->display_type) {
-//nec_fipc
-		case 0: 		//nec_fipc
-			p->need_refresh = 0; 	// 1 if displays need refresh after changing custonchars
-			p->customchars = 1;	// number of customchaaracters the display provides
-			p->vbar_cc_offset = 5;	// character offset of the bars
-			p->hbar_cc_offset = 12;	// character offset of the bars
-
-			// hardwarespecific commands:
-			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
-			//					.....
-			//				 {commandlength , command N}}
-			const char hw_cmd_0[10][4]=	{{1	,0x04},  	// dark
-						{1      ,0x03},
-						{1	,0x02},
-						{1	,0x01},  	// bright
-						{1	,0x0D},  	// pos1
-						{1	,0x1B},  	// move cursor
-						{1	,0x0C},  	// reset
-						{2	,0x14, 0x11},  	// init
-						{1	,0x1A}, 	// set user char
-						{1	,0x09}}; 	// tab
-			for (tmp = 0; tmp < 10; tmp++)
-				for (w = 0; w < 4  ;w++)
-					p->hw_cmd[tmp][w] = hw_cmd_0[tmp][w];
-
-			// Translates ISO 8859-1 to display charset.
-			const unsigned char charmap_0[] = {
-				/* #128  = 0x80 */
-				128, 129, 130, 131, 132, 133, 134, 135,
-				136, 137, 138, 139, 140, 141, 142, 143,
-				144, 145, 146, 147, 148, 149, 150, 151,
-				152, 153, 154, 155, 156, 157, 158, 159,
-				/* #160 = 0xA0 */
-				160,   '!', 0xF7, 0xF8,  '?',  '?', 0x7C, 0xF9,
-				'"',   '?',  '?',  '?',  '?',  '-',  '?',  '?',
-				0x8B, 0xF3, 0x89, 0x8A, 0x27, 0x98,  '?',  '.',
-				',',   '?',  '?',  '?',  '?', 0x8C,  '?', 0xAA,
-				/* #192 = 0xC0 */
-				'A',   'A',  'A',  'A', 0xA2, 0xA8,  'A',  'C',
-				'E',   'E',  'E', 0xB6,  'I',  'I',  'I',  'I',
-				'D',   0xA9, 'O',  'O',  'O',  'O', 0xA3, 0x8D,
-				'0',   'U',  'U',  'U', 0xA4,  'Y',  'p', 0x91,
-				/* #224 = 0xE0 */
-				'a',   'a',  'a',  'a', 0xA5,  'a',  'a',  'c',
-				'e',   'e',  'e',  'e',  'i',  'i',  'i',  'i',
-				'o',   'n',  'o',  'o',  'o',  'o', 0xA6, 0x8E,
-				'0',   'u',  'u',  'u', 0xA7,  'y',  'p',  'y'
-				};
-			for (tmp = 0; tmp < 128 ; tmp++)
-				p->charmap[tmp] = charmap_0[tmp];
-
-			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
-			const int usr_chr_dot_assignment_0[57]={ 7,
-								 1, 2, 3, 4, 5, 0, 0, 0,
-								 6, 7, 8, 9,10, 0, 0, 0,
-								11,12,13,14,15, 0, 0, 0,
-								16,17,18,19,20, 0, 0, 0,
-								21,22,23,24,25, 0, 0, 0,
-								26,27,28,29,30, 0, 0, 0,
-								31,32,33,34,35, 0, 0, 0 };
-			for (tmp = 0; tmp < 57 ;tmp++)
-				p->usr_chr_dot_assignment[tmp] = usr_chr_dot_assignment_0[tmp];
-
-			//Where to place the usercharacters (0..30) in the asciicode.
-			//Also used to map standardcharacters in the usercharacterspace(0..30)
-			//(useful for displays with less then 30 usercharacters and predefined bars)
-			const unsigned int usr_chr_mapping_0[31]=
-			{0xAF,0,0,0,0,0, 0x5F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0, 0x5F, 0xE1, 0xE3, 0xE4};
-			for (tmp = 0; tmp < 31; tmp++)
-				p->usr_chr_mapping[tmp] = usr_chr_mapping_0[tmp];
-			break;
+	serialVFD_load_display_data(drvthis);
 
-//KD Rev2.1
-		case 1: 		//KD Rev2.1
-			p->need_refresh=1; 	// 1 if displays need refresh after changing custonchars
-			p->customchars=31;	// number of customchaaracters the display provides
-			p->vbar_cc_offset=0;	// character offset of the bars
-			p->hbar_cc_offset=0;	// character offset of the bars
-
-			// hardwarespecific commands:
-			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
-			//					.....
-			//				 {commandlength , command N}}
-			const char hw_cmd_1[10][4]=	{{1	,0x04},  	// dark
-						{1      ,0x03},
-						{1	,0x02},
-						{1	,0x01},  	// bright
-						{1	,0x0D},  	// pos1
-						{1	,0x1B},  	// move cursor
-						{1	,0x0C},  	// reset
-						{2	,0x14, 0x11},  	// init
-						{1	,0x1A}, 	// set user char
-						{1	,0x09}}; 	// tab
-			for (tmp = 0; tmp < 10; tmp++)
-				for (w = 0; w < 4; w++)
-					p->hw_cmd[tmp][w] = hw_cmd_1[tmp][w];
-
-			const unsigned char charmap_1[] = {
-				/* #128  = 0x80 */
-				128, 129, 130, 131, 132, 133, 134, 135,
-				136, 137, 138, 139, 140, 141, 142, 143,
-				144, 145, 146, 147, 148, 149, 150, 151,
-				152, 153, 154, 155, 156, 157, 158, 159,
-				/* #160 = 0xA0 */
-				160,   '!', 0xF7, 0xF8,  '?',  '?', 0x7C, 0xF9,
-				'"',   '?',  '?',  '?',  '?',  '-',  '?',  '?',
-				0xA9, 0xBA,  '?',  '?', 0x27,  '?',  '?',  '.',
-				',',   '?',  '?',  '?',  '?',  '?',  '?',  '?',
-				/* #192 = 0xC0 */
-				0xB2,  'A',  'A',  'A', 0xA2, 0xA1,  'A',  'C',
-				'E',   'E', 0xA8, 0xB6, 0xAB, 0xAA, 0xAC, 0xA9,
-				'D',  0xAE, 0xB1, 0xB0, 0xBF,  'O', 0xA3,  'x',
-				0xAF, 0xB7, 0xB6, 0xB8, 0xA4,  'Y',  'p', 0x91,
-				/* #224 = 0xE0 */
-				0xD2, 0xC2, 0xC4,  'a', 0xA5, 0xC1, 0xC5, 0xC3,
-				0xC7, 0xC6, 0xC8, 0xD4, 0xCC, 0xCB, 0xCD, 0xCA,
-				'o',  0xCF, 0xD1, 0xD0, 0xCE,  'o', 0xA6, 0xBB,
-				0xD0, 0xD7, 0xD6, 0xD8, 0xA7,  'y',  'p',  'y'
-				};
-			for (tmp = 0; tmp < 128; tmp++)
-				p->charmap[tmp] = charmap_1[tmp];
-
-
-			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
-			const int usr_chr_dot_assignment_1[57]={ 7,
-								 1, 2, 3, 4, 5, 0, 0, 0,
-								 6, 7, 8, 9,10, 0, 0, 0,
-								11,12,13,14,15, 0, 0, 0,
-								16,17,18,19,20, 0, 0, 0,
-								21,22,23,24,25, 0, 0, 0,
-								26,27,28,29,30, 0, 0, 0,
-								31,32,33,34,35, 0, 0, 0};
-			for (tmp = 0; tmp < 57; tmp++)
-				p->usr_chr_dot_assignment[tmp] = usr_chr_dot_assignment_1[tmp];
-
-			//Where to place the usercharacters (0..30) in the asciicode.
-			//Also used to map standardcharacters in the usercharacterspace(0..30)
-			//(useful for displays with less then 30 usercharacters and predefined bars)
-			const unsigned int usr_chr_mapping_1[31]=
-			{0xAF};
-			for (tmp = 0; tmp < 31; tmp++)
-				p->usr_chr_mapping[tmp] = usr_chr_mapping_1[tmp];
-			break;
+//	report (RPT_ERR, "%s: Port: %X\n", drvthis->name, p->port, strerror (errno));
 
-//Noritake
-		case 2: 		//Noritake
-			p->need_refresh=0; 	// 1 if displays need refresh after changing custonchars
-			p->customchars=16;	// number of customchaaracters the display provides
-			p->vbar_cc_offset=0;	// character offset of the bars
-			p->hbar_cc_offset=0;	// character offset of the bars
-
-			// hardwarespecific commands:
-			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
-			//					.....
-			//				 {commandlength , command N}}
-			const char hw_cmd_2[10][4]=	{{1	,0x1B, 0x4C, 0x00},  // dark
-						{1      ,0x1B, 0x4C, 0x50},
-						{2	,0x1B, 0x4C, 0x90},
-						{1	,0x1B, 0x4C, 0xFF},  // bright
-						{1	,0x0C},		// pos1
-						{2	,0x1B, 0x48},	// move cursor
-						{2	,0x1B, 0x49},	// reset
-						{2	,0x14, 0x11},  	// init
-						{2	,0x1B, 0x43}, 	// set user char
-						{1	,0x09}}; 	// tab
-			for (tmp = 0; tmp < 10; tmp++)
-				for (w = 0; w < 4; w++)
-					p->hw_cmd[tmp][w] = hw_cmd_2[tmp][w];
-
-			// no charmap needed
-			for (tmp = 128; tmp <= 255; tmp++)
-				p->charmap[tmp]=tmp;
-
-			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
-			const int usr_chr_dot_assignment_2[57]={ 5,
-								 1, 2, 3, 4, 5, 6, 7, 8,
-								 9,10,11,12,13,14,15,16,
-								17,18,19,20,21,22,23,24,
-								25,26,27,28,29,30,31,32,
-								33,34,35, 0, 0, 0, 0, 0};
-			for (tmp=0; tmp < 57; tmp++)
-				p->usr_chr_dot_assignment[tmp]=usr_chr_dot_assignment_2[tmp];
-
-			//Where to place the usercharacters (0..30) in the asciicode.
-			//Also used to map standardcharacters in the usercharacterspace(0..30)
-			//(useful for displays with less then 30 usercharacters and predefined bars)
-			const unsigned int usr_chr_mapping_2[31]=
-			{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\
-	 		0x0F, 0x10, 0x13 , 0x14, 0x1C, 0x1D, 0x1E, 0x1F};
-			for (tmp=0;tmp < 31 ;tmp++)
-				p->usr_chr_mapping[tmp]=usr_chr_mapping_2[tmp];
-			break;
-//Futaba
-		case 3: 		//Futaba
-			p->need_refresh=0; 	// 1 if displays need refresh after changing custonchars
-			p->customchars=3;	// number of customchaaracters the display provides
-			p->vbar_cc_offset=0x30;	// character offset of the bars
-			p->hbar_cc_offset=0x30;	// character offset of the bars
-
-			// hardwarespecific commands:
-			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
-			//					.....
-			//				 {commandlength , command N}}
-			const char hw_cmd_3[10][4]=  {{1      ,0x04, 0x20},	// dark
-						{1      ,0x04, 0x40},
-						{2	,0x04, 0x60},
-						{1	,0x04, 0xFF},	// bright
-						{2	,0x10, 0x00},	// pos1
-						{1	,0x10,},	// move cursor
-						{1	,0x1F},		// reset
-						{1	,0x11},  	// init
-						{1	,0x03}, 	// set user char
-						{1	,0x09}}; 	// tab
-			for (tmp=0;tmp < (10) ;tmp++)
-				for (w=0;w < (4) ;w++)
-					p->hw_cmd[tmp][w]=hw_cmd_3[tmp][w];
-
-			// Translates ISO 8859-1 to display charset.
-			const unsigned char charmap_3[] = {
-				/* #128  = 0x80 */
-				128, 129, 130, 131, 132, 133, 134, 135,
-				136, 137, 138, 139, 140, 141, 142, 143,
-				144, 145, 146, 147, 148, 149, 150, 151,
-				152, 153, 154, 155, 156, 157, 158, 159,
-				/* #160 = 0xA0 */
-				160,  0xAD, 0x9B, 0x9C, 0xC8, 0x9D, 0x7C, 0xC0,
-				'"',   '?', 0xA6, 0xAE, 0xAA,  '-',  '?',  '?',
-				0xEF, 0xCA, 0xC6, 0xC7, 0x27, 0xB8,  '?',  '.',
-				',',   '?', 0xA7, 0xAF, 0xAC, 0xAB,  '?', 0xA8,
-				/* #192 = 0xC0 */
-				0xD0,  'A', 0xD5,  'A', 0x8E, 0x8F, 0x92, 0x80,
-				0xD1, 0x90, 0xD6, 0xD3, 'I',   'I', 0xD7, 0xD4,
-				'D',  0xA5,  'O',  'O', 0xD8,  'O', 0x99,  'x',
-				'0',  0xD2,  'U', 0xD9, 0x9A,  'Y',  'p', 0xB1,
-				/* #224 = 0xE0 */
-				0x85, 0xA0, 0x83,  'a', 0x84, 0x86, 0x91, 0x87,
-				0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B,
-				'o',  0xA4, 0x95, 0xA9, 0x93,  'o', 0x94,  '/',
-				'0',  0x97, 0xA3, 0x96, 0x81,  'y',  'p', 0x89
-				};
-			for (tmp = 0; tmp < 128; tmp++)
-				p->charmap[tmp] = charmap_3[tmp];
-
-			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
-			const int usr_chr_dot_assignment_3[57]={ 5,
-								 8, 7, 6, 5, 4, 3, 2, 1,
-								16,15,14,13,12,11,10, 9,
-								24,23,22,21,20,19,18,17,
-								32,31,30,29,28,27,26,25,
-								 0, 0, 0, 0, 0,35,34,33};
-			for (tmp=0;tmp < 57 ;tmp++)
-				p->usr_chr_dot_assignment[tmp]=usr_chr_dot_assignment_3[tmp];
-
-			//Where to place the usercharacters (0..30) in the asciicode.
-			//Also used to map standardcharacters in the usercharacterspace(0..30)
-			//(useful for displays with less then 30 usercharacters and predefined bars)
-			const unsigned int usr_chr_mapping_3[31]=
-			{0xCD, 0xCE, 0xCF};
-			for (tmp = 0; tmp < 31; tmp++)
-				p->usr_chr_mapping[tmp] = usr_chr_mapping_3[tmp];
-			break;
-		}
+//initialise display
+	Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[reset][1],p->hw_cmd[reset][0]);
+	Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[init_cmds][1],p->hw_cmd[init_cmds][0]);
+	serialVFD_backlight(drvthis, 1);
+	report(RPT_DEBUG, "%s: init() done", drvthis->name);
+	return 0;
 
-	//initialise display
-	write(p->fd, &p->hw_cmd[reset][1],p->hw_cmd[reset][0]);
-	write(p->fd, &p->hw_cmd[init_cmds][1],p->hw_cmd[init_cmds][0]);
-	serialVFD_set_brightness(drvthis, 1, brightness);
+}
 
-	report(RPT_DEBUG, "%s: init() done", drvthis->name);
+/*
+ * Retrieves brightness (in promille)
+ */
 
-	return 0;
+MODULE_EXPORT int
+serialVFD_get_brightness(Driver *drvthis, int state)
+{
+	PrivateData *p = drvthis->private_data;
 
+	return (state == BACKLIGHT_ON) ? p->on_brightness : p->off_brightness;
 }
 
 
-/////////////////////////////////////////////////////////////////
-// Changes screen brightness (0 min ... 255 max ... 1000 also max)
-//
+/*
+ * Sets on/off brightness (in promille)
+ */
 MODULE_EXPORT void
-serialVFD_set_brightness (Driver *drvthis, int state, int brightness)
-{	// set p->brightness
+serialVFD_set_brightness(Driver *drvthis, int state, int promille)
+{
 	PrivateData *p = drvthis->private_data;
 
-	if (brightness > 0) {
-		if (brightness > 255)
-			brightness = 255;
-		if (p->brightness != brightness) {
-			p->brightness = brightness;
-			serialVFD_put_brightness(drvthis);
-		}
+	/* Check it */
+	if (promille < 0 || promille > 1000)
+		return;
+
+	/* store the software value since there is not get */
+	if (state == BACKLIGHT_ON) {
+		p->on_brightness = promille;
+	}
+	else {
+		p->off_brightness = promille;
 	}
 }
 
-static void
-serialVFD_put_brightness (Driver *drvthis)
-{	// set hardware brightness
+
+/*
+ * Sets the backlight on or off.
+ * The hardware support any value between 0 and 100.
+ */
+MODULE_EXPORT void
+serialVFD_backlight (Driver *drvthis, int on)
+{
 	PrivateData *p = drvthis->private_data;
-	int realbrightness = (int) (p->brightness / 64);
+	int hardware_value = (on == BACKLIGHT_ON)
+			     ? p->on_brightness
+			     : p->off_brightness;
+
+	// map range [0, 1000] -> [0, 4] that the hardware understands
+	//(4 steps 0-250, 251-500, 501-750, 751-1000)
+	hardware_value /= 251;
+	if(hardware_value != p->hw_brightness){
+		p->hw_brightness=hardware_value;
+		Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[p->hw_brightness][1],\
+		p->hw_cmd[p->hw_brightness][0]);
+		}
 
-	//(4 steps 0-64, 65-128, 129-192, 193-1000)
-	write(p->fd, &p->hw_cmd[realbrightness][1],\
-		p->hw_cmd[realbrightness][0]);
 }
 
 
+
 /////////////////////////////////////////////////////////////////
 // Draws a vertical bar...
 //
@@ -719,7 +352,7 @@ serialVFD_set_char (Driver *drvthis, int
 	PrivateData *p = drvthis->private_data;
 	unsigned int byte, bit;
 
-	if ((n < 0) || (n > p->customchars-1))
+	if (n < 0 || n > p->customchars-1)
 		return;
 	if (!dat)
 		return;
@@ -735,16 +368,11 @@ serialVFD_set_char (Driver *drvthis, int
 				int posbit = 4 - ((pos-1) % 5);
 
 				letter |= ((dat[posbyte] >> posbit) & 1) << bit;;
-			}	
+			}
 		}
 		p->custom_char[n][byte] = letter;
 	}
 
-	if (p->display_type != 1) //not KD Rev 2.1
-		serialVFD_put_char(drvthis, n);
-
-	if (p->need_refresh == 1)
-		p->custom_char_changed[n] = 1;
 }
 
 static void
@@ -752,10 +380,10 @@ serialVFD_put_char (Driver *drvthis, int
 {	// put char in display
 	PrivateData *p = drvthis->private_data;
 
-	write(p->fd, &p->hw_cmd[set_user_char][1],
+	Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[set_user_char][1],\
 		p->hw_cmd[set_user_char][0]);// substitute and select Character to overwrite
-	write(p->fd, &p->usr_chr_mapping[n], 1);
-	write(p->fd, &p->custom_char[n][0], p->usr_chr_dot_assignment[0]);// overwrite selected Character
+	Port_Function[p->use_parallel].write_fkt (drvthis, (char*)&p->usr_chr_mapping[n], 1);
+	Port_Function[p->use_parallel].write_fkt (drvthis, &p->custom_char[n][0], p->usr_chr_dot_assignment[0]);// overwrite selected Character
 }
 
 
@@ -765,85 +393,95 @@ serialVFD_put_char (Driver *drvthis, int
 //
 // Input is a character array, sized serialVFD->width*serialVFD->height
 //
-static void
-serialVFD_draw_frame (Driver *drvthis, unsigned char *dat)
+MODULE_EXPORT void
+serialVFD_flush (Driver *drvthis)
 {
 	PrivateData *p = drvthis->private_data;
 	int i, j, last_chr = -10;
+	char custom_char_changed[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+
+	for (i = 0; i < p->customchars; i++) {
+		for (j = 0; j < p->usr_chr_dot_assignment[0]; j++) {
+			if (p->custom_char[i][j] != p->custom_char_store[i][j]) {
+				custom_char_changed[i]=1;
+//				report (RPT_ERR, "%s: Char: %X   %i\n", __FUNCTION__, i, j, strerror (errno));
+				}
+			p->custom_char_store[i][j]=p->custom_char[i][j];
+		}
+	}
 
-	if (!dat)
-		return;
 	if (p->refresh_timer > 500) { // Do a full refresh every 500 refreshs.
 	// With this it is possible to switch display on and off while lcdproc is running
-		write(p->fd, &p->hw_cmd[init_cmds][1],p->hw_cmd[init_cmds][0]);
-		serialVFD_put_brightness(drvthis); // restore brightness
+		Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[init_cmds][1],p->hw_cmd[init_cmds][0]);
+
+		Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[p->hw_brightness][1],\
+		p->hw_cmd[p->hw_brightness][0]); // restore brightness
 
 		for (i = 0; i < (p->height * p->width); i++)
-			p->backingstore[i] = '\0'; // clear Backing-store
+			p->backingstore[i]=0; // clear Backing-store
 
-		if (p->display_type != 1) {//not KD Rev 2.1
-			for (i = 0; i < p->customchars; i++) // refresh all customcharacters
-				serialVFD_put_char(drvthis, i);
-/*				{
-					write(p->fd, &p->hw_cmd[set_user_char][1],\
-					p->hw_cmd[set_user_char][0]);// substitute and select character to overwrite
-					write(p->fd, &p->usr_chr_mapping[i], 1);
-					write(p->fd, &p->custom_char[(int)dat[i]][0], p->usr_chr_dot_assignment[0]);// overwrite selected Character
-				}*/
-		}
+		for(i=0;i<p->customchars;i++) // refresh all customcharacters
+			custom_char_changed[i]=1;
 		p->refresh_timer = 0;
 	}
+
 	p->refresh_timer++;
 
+	if (p->display_type != 1) { //not KD Rev 2.1
+		for(i=0;i<p->customchars;i++) // set customcharacters
+			if(custom_char_changed[i])
+				serialVFD_put_char (drvthis, i);
+		}
+
+	if(custom_char_changed[p->last_custom])
+		p->last_custom=-10;
+
 	for (i = 0; i < (p->height * p->width); i++) {
+
 		/* Backing-store implementation.  If it's already
 		 * on the screen, don't put it there again
 		 */
 
-		if (dat[i] != p->backingstore[i] || (dat[i] <=30 && p->custom_char_changed[(int)dat[i]]))
-		{
-			if (last_chr < i-1) { // if not last char written cursor has to be moved.
-				if (last_chr < i-2-p->hw_cmd[mv_cursor][0]) {
-					write(p->fd, &p->hw_cmd[mv_cursor][1],
+		if(p->framebuf[i] != p->backingstore[i] || (p->framebuf[i] <=30 && custom_char_changed[(int)p->framebuf[i]])) {
+			if (last_chr < i-1){ // if not last char written cursor has to be moved.
+				if(last_chr < i-2-p->hw_cmd[mv_cursor][0]) {
+					Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[mv_cursor][1],\
 						p->hw_cmd[mv_cursor][0]);
-					write(p->fd, &i, 1);
-				}
-				else {
-					for (j = last_chr; j < (i-1); j++) {
-						write(p->fd, &p->hw_cmd[hor_tab][1], p->hw_cmd[hor_tab][0]);
+					Port_Function[p->use_parallel].write_fkt (drvthis, (char*)&i, 1);
 					}
+				else {
+					for (j = last_chr; j < (i-1); j++)
+						Port_Function[p->use_parallel].write_fkt (drvthis, &p->hw_cmd[hor_tab][1], p->hw_cmd[hor_tab][0]);
 				}
 			}
 
-			if (dat[i] <= 30) {// custom character
-				if (p->display_type == 1) {// KD Rev 2.1 only
-					write(p->fd, "\x1A\xDB", 2);		// substitute and select character to overwrite(237)
-					write(p->fd, &p->custom_char[(int)dat[i]][0], 7);// overwrite selected character
-					write(p->fd, "\xDB", 1);			// write character
+			if(p->framebuf[i] <= 30) { // custom character
+				if (p->display_type == 1) { // KD Rev 2.1 only
+					if (p->last_custom != p->framebuf[i]){
+						Port_Function[p->use_parallel].write_fkt (drvthis, "\x1A\xDB", 2);		// substitute and select character to overwrite (237)
+						Port_Function[p->use_parallel].write_fkt (drvthis, &p->custom_char[(int)p->framebuf[i]][0], 7);// overwrite selected character
+						}
+					Port_Function[p->use_parallel].write_fkt (drvthis, "\xDB", 1);			// write character
+					p->last_custom = p->framebuf[i];
 				}
 				else {	// all other displays
-					write(p->fd, &p->usr_chr_mapping[(int)dat[i]], 1);
+					Port_Function[p->use_parallel].write_fkt (drvthis, (char*)&p->usr_chr_mapping[(int)p->framebuf[i]], 1);
 				}
 			}
-			else if (dat[i] > 127 && (p->ISO_8859_1 != 0)) { // ISO_8859_1 translation for 129 ... 255
-				write(p->fd, &p->charmap[dat[i] + 128], 1);
+			else if(p->framebuf[i] > 127 && (p->ISO_8859_1 != 0)) { // ISO_8859_1 translation for 129 ... 255
+				Port_Function[p->use_parallel].write_fkt (drvthis, &p->charmap[p->framebuf[i] - 128], 1);
 			}
 			else {
-				write(p->fd, &dat[i], 1);
+				Port_Function[p->use_parallel].write_fkt (drvthis, &p->framebuf[i], 1);
 			}
 
 			last_chr = i;
 		}
 	}
 
-	if (last_chr != -10) { // update backingstore if something changed
-		int i;
-
-		memcpy(p->backingstore, dat, p->height * p->width);
-
-		for (i = 0; i < p->customchars; i++)
-			p->custom_char_changed[i] = '\0';
-	}
+	if (last_chr != -10) // update backingstore if something changed
+		memcpy(p->backingstore, p->framebuf, p->height * p->width);
 }
 
 
@@ -863,6 +501,7 @@ serialVFD_num( Driver * drvthis, int x, 
 
 
 
+
 /*
  * Places an icon on screen
  */
@@ -870,7 +509,7 @@ MODULE_EXPORT int
 serialVFD_icon (Driver *drvthis, int x, int y, int icon)
 {
 	PrivateData *p = drvthis->private_data;
-	static unsigned char heart_open[] = 
+	static unsigned char heart_open[] =
 		{ b__XXXXX,
 		  b__X_X_X,
 		  b_______,
@@ -879,7 +518,7 @@ serialVFD_icon (Driver *drvthis, int x, 
 		  b__X___X,
 		  b__XX_XX,
 		  b__XXXXX };
-	static unsigned char heart_filled[] = 
+	static unsigned char heart_filled[] =
 		{ b__XXXXX,
 		  b__X_X_X,
 		  b___X_X_,
@@ -969,6 +608,7 @@ MODULE_EXPORT void
 serialVFD_clear (Driver *drvthis)
 {
 	PrivateData *p = drvthis->private_data;
+
 	memset(p->framebuf, ' ', p->width * p->height);
 
 }
@@ -1001,17 +641,16 @@ MODULE_EXPORT void
 serialVFD_close (Driver *drvthis)
 {
 	PrivateData *p = drvthis->private_data;
-
 	if (p != NULL) {
-		close(p->fd);
-
+		if (p->fd >= 0)
+			close(p->fd);
 		if (p->framebuf)
 			free(p->framebuf);
-
 		if (p->backingstore)
 			free(p->backingstore);
 		free(p);
 	}
+
 	drvthis->store_private_ptr(drvthis, NULL);
 }
 
@@ -1073,16 +712,6 @@ serialVFD_cellheight (Driver *drvthis)
 }
 
 
-MODULE_EXPORT void
-serialVFD_flush (Driver *drvthis)
-{
-	PrivateData *p = drvthis->private_data;
-
-	serialVFD_draw_frame(drvthis, p->framebuf);
-}
-
-
-
 /////////////////////////////////////////////////////////////////
 // Prints a character on the lcd display, at position (x,y).  The
 // upper-left is (1,1), and the lower right should be (20,4).
@@ -1091,23 +720,14 @@ MODULE_EXPORT void
 serialVFD_chr (Driver *drvthis, int x, int y, char c)
 {
 	PrivateData *p = drvthis->private_data;
-
+	if ((x > p->width) || (y > p->height))
+		return;
 	y--;
 	x--;
+
 	p->framebuf[(y * p->width) + x ] = c;
 }
 
-/////////////////////////////////////////////////////////////////
-//
-// Retrieves brightness
-//
-MODULE_EXPORT int
-serialVFD_get_brightness(Driver *drvthis, int state)
-{
-	PrivateData *p = drvthis->private_data;
-
-	return p->brightness;
-}
 
 /////////////////////////////////////////////////////////////////
 // provides some info about this driver
@@ -1116,7 +736,6 @@ MODULE_EXPORT const char *
 serialVFD_get_info (Driver *drvthis)
 {
 	PrivateData *p = drvthis->private_data;
-
 	strcpy(p->info, "Driver for many serialVFDs from NEC(all FIPC based), Noritake, Futaba and the \"KD Rev2.1\"VFD.");
 	return p->info;
 }
--- ../lcdproc-CVS-current-test/server/drivers/serialVFD.h	2006-04-26 09:00:40.000000000 +0200
+++ ./server/drivers/serialVFD.h	2006-05-16 14:47:20.000000000 +0200
@@ -6,7 +6,7 @@
 	driver.
 	It may contain parts of other drivers of this package too.
 
-	2006-02-13 Version 0.2: everything should work (not all hardware tested!)
+	2006-05-16 Version 0.3: everything should work (not all hardware tested!)
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
@@ -26,6 +26,8 @@
 #define SERIALVFD_H
 #include "lcd.h"
 #include "adv_bignum.h"
+#include "serialVFD_displays.h"
+#include "serialVFD_io.h"
 
 #define CCMODE_STANDARD 0 /* only char 0 is used for heartbeat */
 #define CCMODE_VBAR 1
@@ -63,8 +65,43 @@ MODULE_EXPORT void serialVFD_set_char (D
 
 MODULE_EXPORT int  serialVFD_get_brightness (Driver *drvthis, int state);
 MODULE_EXPORT void serialVFD_set_brightness (Driver *drvthis, int state, int promille);
+MODULE_EXPORT void serialVFD_backlight (Driver *drvthis, int on);
 MODULE_EXPORT void serialVFD_output (Driver *drvthis, int state);
 MODULE_EXPORT void serialVFD_num (Driver * drvthis, int x, int num);
 MODULE_EXPORT int serialVFD_get_free_chars (Driver *drvthis);
 MODULE_EXPORT const char * serialVFD_get_info( Driver *drvthis );
+
+typedef struct driver_private_data {
+	int use_parallel;		// use parallel?
+	unsigned int port;		// Port in parallel mode
+	char device[200];		// Device in serial mode
+	int fd;
+	int speed;			// Speed in serial mode
+	/* dimensions */
+	int width, height;
+	int cellwidth, cellheight;
+	/* framebuffer and buffer for old LCD contents */
+	unsigned char *framebuf;
+	unsigned char *backingstore;
+	/* defineable characters */
+	int ccmode;
+	int on_brightness;
+	int off_brightness;
+	int hw_brightness;
+	int customchars;
+	int ISO_8859_1;
+	unsigned int refresh_timer;
+	unsigned char charmap[128];
+	int display_type;		// display type
+	int last_custom;		// last custom character written
+	char custom_char[31][7]; 	// stored custom characters
+	char custom_char_store[31][7]; 	// custom characters backingstore
+	char hw_cmd[10][4]; 		// hardwarespecific commands
+	int usr_chr_dot_assignment[57];	// how to setup usercharacters
+	unsigned int usr_chr_mapping[31];// where to place the usercharacters (0..30) in the asciicode
+	int hbar_cc_offset;		// character offset of the bars
+	int vbar_cc_offset;		// character offset of the bars
+	char info[255];
+} PrivateData;
+
 #endif
--- ../lcdproc-CVS-current-test/server/drivers/serialVFD_io.c	1970-01-01 01:00:00.000000000 +0100
+++ ./server/drivers/serialVFD_io.c	2006-05-17 01:03:56.000000000 +0200
@@ -0,0 +1,127 @@
+/* 	This file is part the LCDproc driver for various serial VFD Devices.
+
+	It contains the hardwaredependent commands ach characterset.
+
+	If you want to add a new device to the driver add a new section
+	to the displaytype-switch-case in the init-function, add a new load_...
+	function below and fill it with the corrrect commands for the display.
+	(Try wich displaytype works best with your display, copy and modify
+	it's section that is the easiest way I guess.)
+
+	Copyright (C) 2006 Stefan Herdler
+
+	2006-05-15 Version 0.3: everything should work (not all hardware tested!)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+
+*/
+
+
+#include "port.h"
+#include "serialVFD_io.h"
+#include "serialVFD.h"
+#include "lcd.h"
+#define WR_on  0x10
+#define WR_off 0x11
+#define Busy   0x80
+#define LPTPORT 0x378
+
+#define MAXBUSY 300
+
+void
+serialVFD_write_serial (Driver *drvthis, char *dat, size_t length)
+{
+	PrivateData *p = drvthis->private_data;
+	write (p->fd,dat,length);
+}
+
+void
+serialVFD_write_parallel (Driver *drvthis, char *dat, size_t length)
+{
+	PrivateData *p = drvthis->private_data;
+	int i_para, j_para;
+
+	for(i_para = 0; i_para < length; i_para++) {
+		port_out(p->port, dat[i_para]);
+		port_in(p->port+1);
+		port_out(p->port+2, WR_on);
+		port_in(p->port+1);
+		port_out(p->port+2, WR_off);
+
+		for(j_para=0; j_para < MAXBUSY; j_para++) {
+			if((port_in(p->port+1)) & Busy)
+				break;
+		}
+	}
+}
+
+int
+serialVFD_init_serial (Driver *drvthis)
+{
+	PrivateData *p = drvthis->private_data;
+	struct termios portset;
+
+	/* Set up io port correctly, and open it...*/
+	debug( RPT_DEBUG, "%s: Opening device: %s", __FUNCTION__, p->device);
+	p->fd = open (p->device, O_RDWR | O_NOCTTY | O_NDELAY);
+
+	if (p->fd == -1) {
+		report (RPT_ERR, "%s: open() of %s failed (%s)\n", __FUNCTION__, p->device, strerror (errno));
+		return -1;
+	}
+
+	tcgetattr (p->fd, &portset);
+
+	// We use RAW mode
+#ifdef HAVE_CFMAKERAW
+	// The easy way
+	cfmakeraw( &portset );
+#else
+	// The hard way
+	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
+
+	// Set port speed
+	cfsetospeed (&portset, p->speed);
+	cfsetispeed (&portset, B0);
+
+	// Do it...
+	tcsetattr (p->fd, TCSANOW, &portset);
+	return 0;
+}
+
+int
+serialVFD_init_parallel (Driver *drvthis)
+{
+	int ret=0;
+	PrivateData *p = drvthis->private_data;
+	debug( RPT_DEBUG, "%s: Opening parallelport at: 0x%X", __FUNCTION__, p->port);
+//	if(port_access_multiple(p->port,3)) return -1;
+	if(port_access(p->port) != 0) ret=-1;
+	if(port_access(p->port+1) != 0) ret=-1;
+	if(port_access(p->port+2) != 0) ret=-1;
+	if(ret == -1) {
+		report (RPT_ERR, "%s: port_access() of 0x%X failed (%s)\n", __FUNCTION__, p->port, strerror (errno));
+		return -1;
+	}
+	return 0;
+}
+
+
--- ../lcdproc-CVS-current-test/server/drivers/serialVFD_io.h	1970-01-01 01:00:00.000000000 +0100
+++ ./server/drivers/serialVFD_io.h	2006-05-16 14:46:09.000000000 +0200
@@ -0,0 +1,65 @@
+/* 	This is the LCDproc driver for various serial VFD Devices
+
+	Copyright (C) 2006 Stefan Herdler
+
+	2006-05-16 Version 0.3: everything should work (not all hardware tested!)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 */
+
+#ifndef SERIALVFD_IO_H
+#define SERIALVFD_IO_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "serialVFD_displays.h"
+#include "port.h"
+#include "lpt-port.h"
+#include "lcd.h"
+#include "serialVFD.h"
+#include "report.h"
+
+
+int serialVFD_init_serial (Driver *drvthis);
+int serialVFD_init_parallel (Driver *drvthis);
+void serialVFD_write_serial (Driver *drvthis, char *dat, size_t length);
+void serialVFD_write_parallel (Driver *drvthis, char *dat, size_t length);
+
+typedef struct Port_fkt {
+	void (*write_fkt) (Driver *drvthis, char *dat, size_t length);
+	int (*init_fkt) (Driver *drvthis);
+} Port_fkt;
+
+
+static const Port_fkt Port_Function[] = {
+	// initialisation function
+	// write function
+
+	{serialVFD_write_serial, serialVFD_init_serial},
+	{serialVFD_write_parallel, serialVFD_init_parallel}
+};
+
+
+#endif
--- ../lcdproc-CVS-current-test/server/drivers/serialVFD_displays.c	1970-01-01 01:00:00.000000000 +0100
+++ ./server/drivers/serialVFD_displays.c	2006-05-17 01:07:26.000000000 +0200
@@ -0,0 +1,336 @@
+/* 	This file is part the LCDproc driver for various serial VFD Devices.
+
+	It contains the hardwaredependent commands ach characterset.
+
+	If you want to add a new device to the driver add a new section
+	to the displaytype-switch-case in the init-function, add a new load_...
+	function below and fill it with the corrrect commands for the display.
+	(Try wich displaytype works best with your display, copy and modify
+	it's section that is the easiest way I guess.)
+
+	Copyright (C) 2006 Stefan Herdler
+
+	2006-05-16 Version 0.3: everything should work (not all hardware tested!)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+
+*/
+
+#include "serialVFD_displays.h"
+#include "serialVFD.h"
+#include "lcd.h"
+
+void serialVFD_load_NEC_FIPC (Driver *drvthis);
+void serialVFD_load_KD (Driver *drvthis);
+void serialVFD_load_Noritake (Driver *drvthis);
+void serialVFD_load_Futaba (Driver *drvthis);
+
+
+void serialVFD_load_display_data(Driver *drvthis)
+{
+	PrivateData *p = (PrivateData*) drvthis->private_data;
+	switch (p->display_type)
+		{
+		case 0:
+			serialVFD_load_NEC_FIPC (drvthis);
+			break;
+		case 1:
+			serialVFD_load_KD (drvthis);
+			break;
+		case 2:
+			serialVFD_load_Noritake (drvthis);
+			break;
+		case 3:
+			serialVFD_load_Futaba (drvthis);
+			break;
+		}
+}
+
+
+
+void
+serialVFD_load_NEC_FIPC (Driver *drvthis)
+{		//nec_fipc
+			PrivateData *p = (PrivateData*) drvthis->private_data;
+			int tmp, w;
+
+			if (p->customchars == -83)
+				p->customchars=1;	// number of customchaaracters the display provides
+			p->vbar_cc_offset=5;	// character offset of the bars
+			p->hbar_cc_offset=12;	// character offset of the bars
+
+			// hardwarespecific commands:
+			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
+			//					.....
+			//				 {commandlength , command N}}
+			const char hw_cmd[10][4]={{1	,0x04},  	// dark
+						{1      ,0x03},
+						{1	,0x02},
+						{1	,0x01},  	// bright
+						{1	,0x0D},  	// pos1
+						{1	,0x1B},  	// move cursor
+						{1	,0x0C},  	// reset
+						{2	,0x14, 0x11},  	// init
+						{1	,0x1A}, 	// set user char
+						{1	,0x09}}; 	// tab
+			for (tmp=0;tmp < (10) ;tmp++)
+				for (w=0;w < (4) ;w++)
+					p->hw_cmd[tmp][w]=hw_cmd[tmp][w];
+
+			// Translates ISO 8859-1 to display charset.
+			const unsigned char charmap[] = {
+				/* #128  = 0x80 */
+				128, 129, 130, 131, 132, 133, 134, 135,
+				136, 137, 138, 139, 140, 141, 142, 143,
+				144, 145, 146, 147, 148, 149, 150, 151,
+				152, 153, 154, 155, 156, 157, 158, 159,
+				/* #160 = 0xA0 */
+				160,   '!', 0xF7, 0xF8,  '?',  '?', 0x7C, 0xF9,
+				'"',   '?',  '?',  '?',  '?',  '-',  '?',  '?',
+				0x8B, 0xF3, 0x89, 0x8A, 0x27, 0x98,  '?',  '.',
+				',',   '?',  '?',  '?',  '?', 0x8C,  '?', 0xAA,
+				/* #192 = 0xC0 */
+				'A',   'A',  'A',  'A', 0xA2, 0xA8,  'A',  'C',
+				'E',   'E',  'E', 0xB6,  'I',  'I',  'I',  'I',
+				'D',   0xA9, 'O',  'O',  'O',  'O', 0xA3, 0x8D,
+				'0',   'U',  'U',  'U', 0xA4,  'Y',  'p', 0x91,
+				/* #224 = 0xE0 */
+				'a',   'a',  'a',  'a', 0xA5,  'a',  'a',  'c',
+				'e',   'e',  'e',  'e',  'i',  'i',  'i',  'i',
+				'o',   'n',  'o',  'o',  'o',  'o', 0xA6, 0x8E,
+				'0',   'u',  'u',  'u', 0xA7,  'y',  'p',  'y'
+				};
+			for (tmp=0;tmp < 128 ;tmp++)
+			p->charmap[tmp]=charmap[tmp];
+
+			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
+			const int usr_chr_dot_assignment[57]={7,	 1, 2, 3, 4, 5, 0, 0, 0,
+								6, 7, 8, 9,10, 0, 0, 0,
+								11,12,13,14,15, 0, 0, 0,
+								16,17,18,19,20, 0, 0, 0,
+								21,22,23,24,25, 0, 0, 0,
+								26,27,28,29,30, 0, 0, 0,
+								31,32,33,34,35, 0, 0, 0};
+			for (tmp=0;tmp < 57 ;tmp++)
+				p->usr_chr_dot_assignment[tmp]=usr_chr_dot_assignment[tmp];
+
+			//Where to place the usercharacters (0..30) in the asciicode.
+			//Also used to map standardcharacters in the usercharacterspace(0..30)
+			//(useful for displays with less then 30 usercharacters and predefined bars)
+			const unsigned int usr_chr_mapping[31]=
+			{0xAF,0,0,0,0,0, 0x5F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0, 0x5F, 0xE1, 0xE3, 0xE4};
+			for (tmp=0;tmp < 31 ;tmp++)
+				p->usr_chr_mapping[tmp]=usr_chr_mapping[tmp];
+}
+
+void
+serialVFD_load_KD (Driver *drvthis)
+{ 		//KD Rev2.1
+			PrivateData *p = (PrivateData*) drvthis->private_data;
+			int tmp, w;
+
+			if (p->customchars == -83)
+				p->customchars=31;	// number of customchaaracters the display provides
+			p->vbar_cc_offset=0;	// character offset of the bars
+			p->hbar_cc_offset=0;	// character offset of the bars
+
+			// hardwarespecific commands:
+			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
+			//					.....
+			//				 {commandlength , command N}}
+			const char hw_cmd[10][4]={{1	,0x04},  	// dark
+						{1      ,0x03},
+						{1	,0x02},
+						{1	,0x01},  	// bright
+						{1	,0x0D},  	// pos1
+						{1	,0x1B},  	// move cursor
+						{1	,0x0C},  	// reset
+						{2	,0x14, 0x11},  	// init
+						{1	,0x1A}, 	// set user char
+						{1	,0x09}}; 	// tab
+			for (tmp=0;tmp < (10) ;tmp++)
+				for (w=0;w < (4) ;w++)
+					p->hw_cmd[tmp][w]=hw_cmd[tmp][w];
+
+			const unsigned char charmap[] = {
+				/* #128  = 0x80 */
+				128, 129, 130, 131, 132, 133, 134, 135,
+				136, 137, 138, 139, 140, 141, 142, 143,
+				144, 145, 146, 147, 148, 149, 150, 151,
+				152, 153, 154, 155, 156, 157, 158, 159,
+				/* #160 = 0xA0 */
+				160,   '!', 0xF7, 0xF8,  '?',  '?', 0x7C, 0xF9,
+				'"',   '?',  '?',  '?',  '?',  '-',  '?',  '?',
+				0xA9, 0xBA,  '?',  '?', 0x27,  '?',  '?',  '.',
+				',',   '?',  '?',  '?',  '?',  '?',  '?',  '?',
+				/* #192 = 0xC0 */
+				0xB2,  'A',  'A',  'A', 0xA2, 0xA1,  'A',  'C',
+				'E',   'E', 0xA8, 0xB6, 0xAB, 0xAA, 0xAC, 0xA9,
+				'D',  0xAE, 0xB1, 0xB0, 0xBF,  'O', 0xA3,  'x',
+				0xAF, 0xB7, 0xB6, 0xB8, 0xA4,  'Y',  'p', 0x91,
+				/* #224 = 0xE0 */
+				0xD2, 0xC2, 0xC4,  'a', 0xA5, 0xC1, 0xC5, 0xC3,
+				0xC7, 0xC6, 0xC8, 0xD4, 0xCC, 0xCB, 0xCD, 0xCA,
+				'o',  0xCF, 0xD1, 0xD0, 0xCE,  'o', 0xA6, 0xBB,
+				0xD0, 0xD7, 0xD6, 0xD8, 0xA7,  'y',  'p',  'y'
+				};
+			for (tmp=0;tmp < 128 ;tmp++)
+			p->charmap[tmp]=charmap[tmp];
+
+
+			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
+			const int usr_chr_dot_assignment[57]={7,	 1, 2, 3, 4, 5, 0, 0, 0,
+								6, 7, 8, 9,10, 0, 0, 0,
+								11,12,13,14,15, 0, 0, 0,
+								16,17,18,19,20, 0, 0, 0,
+								21,22,23,24,25, 0, 0, 0,
+								26,27,28,29,30, 0, 0, 0,
+								31,32,33,34,35, 0, 0, 0};
+			for (tmp=0;tmp < 57 ;tmp++)
+				p->usr_chr_dot_assignment[tmp]=usr_chr_dot_assignment[tmp];
+
+			//Where to place the usercharacters (0..30) in the asciicode.
+			//Also used to map standardcharacters in the usercharacterspace(0..30)
+			//(useful for displays with less then 30 usercharacters and predefined bars)
+			const unsigned int usr_chr_mapping[31]=
+			{0xAF};
+			for (tmp=0;tmp < 31 ;tmp++)
+				p->usr_chr_mapping[tmp]=usr_chr_mapping[tmp];
+}
+
+void
+serialVFD_load_Noritake (Driver *drvthis)
+{ 		//Noritake
+			PrivateData *p = (PrivateData*) drvthis->private_data;
+			int tmp, w;
+
+			if (p->customchars == -83)
+				p->customchars=16;	// number of customchaaracters the display provides
+			p->vbar_cc_offset=0;	// character offset of the bars
+			p->hbar_cc_offset=0;	// character offset of the bars
+
+			// hardwarespecific commands:
+			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
+			//					.....
+			//				 {commandlength , command N}}
+			const char hw_cmd[10][4]={{3	,0x1B, 0x4C, 0x00},  // dark
+						{3      ,0x1B, 0x4C, 0x50},
+						{3	,0x1B, 0x4C, 0x90},
+						{3	,0x1B, 0x4C, 0xFF},  // bright
+						{1	,0x0C},		// pos1
+						{2	,0x1B, 0x48},	// move cursor
+						{2	,0x1B, 0x49},	// reset
+						{2	,0x14, 0x11},  	// init
+						{2	,0x1B, 0x43}, 	// set user char
+						{1	,0x09}}; 	// tab
+			for (tmp=0;tmp < (10) ;tmp++)
+				for (w=0;w < (4) ;w++)
+					p->hw_cmd[tmp][w]=hw_cmd[tmp][w];
+
+			// no charmap needed
+			for (tmp=128;tmp <= 255 ;tmp++)
+			p->charmap[tmp]=tmp;
+
+			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
+			const int usr_chr_dot_assignment[57]={5,	 1, 2, 3, 4, 5, 6, 7, 8,
+								 9,10,11,12,13,14,15,16,
+								17,18,19,20,21,22,23,24,
+								25,26,27,28,29,30,31,32,
+								33,34,35, 0, 0, 0, 0, 0};
+			for (tmp=0;tmp < 57 ;tmp++)
+				p->usr_chr_dot_assignment[tmp]=usr_chr_dot_assignment[tmp];
+
+			//Where to place the usercharacters (0..30) in the asciicode.
+			//Also used to map standardcharacters in the usercharacterspace(0..30)
+			//(useful for displays with less then 30 usercharacters and predefined bars)
+			const unsigned int usr_chr_mapping[31]=
+			{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\
+ 	 		0x0F, 0x10, 0x13 , 0x14, 0x1C, 0x1D, 0x1E, 0x1F};
+			for (tmp=0;tmp < 31 ;tmp++)
+				p->usr_chr_mapping[tmp]=usr_chr_mapping[tmp];
+}
+void
+serialVFD_load_Futaba (Driver *drvthis)
+{ 		//Futaba
+			PrivateData *p = (PrivateData*) drvthis->private_data;
+			int tmp, w;
+
+			if (p->customchars == -83)
+				p->customchars=3;	// number of customchaaracters the display provides
+			p->vbar_cc_offset=0x30;	// character offset of the bars
+			p->hbar_cc_offset=0x30;	// character offset of the bars
+
+			// hardwarespecific commands:
+			//  hw_cmd[Command][data]  = 	{{commandlength , command 1},
+			//					.....
+			//				 {commandlength , command N}}
+			const char hw_cmd[10][4]={{2    ,0x04, 0x20},	// dark
+						{2      ,0x04, 0x40},
+						{2	,0x04, 0x60},
+						{2	,0x04, 0xFF},	// bright
+						{2	,0x10, 0x00},	// pos1
+						{1	,0x10,},	// move cursor
+						{1	,0x1F},		// reset
+						{1	,0x11},  	// init
+						{1	,0x03}, 	// set user char
+						{1	,0x09}}; 	// tab
+			for (tmp=0;tmp < (10) ;tmp++)
+				for (w=0;w < (4) ;w++)
+					p->hw_cmd[tmp][w]=hw_cmd[tmp][w];
+
+			// Translates ISO 8859-1 to display charset.
+			const unsigned char charmap[] = {
+				/* #128  = 0x80 */
+				128, 129, 130, 131, 132, 133, 134, 135,
+				136, 137, 138, 139, 140, 141, 142, 143,
+				144, 145, 146, 147, 148, 149, 150, 151,
+				152, 153, 154, 155, 156, 157, 158, 159,
+				/* #160 = 0xA0 */
+				160,  0xAD, 0x9B, 0x9C, 0xC8, 0x9D, 0x7C, 0xC0,
+				'"',   '?', 0xA6, 0xAE, 0xAA,  '-',  '?',  '?',
+				0xEF, 0xCA, 0xC6, 0xC7, 0x27, 0xB8,  '?',  '.',
+				',',   '?', 0xA7, 0xAF, 0xAC, 0xAB,  '?', 0xA8,
+				/* #192 = 0xC0 */
+				0xD0,  'A', 0xD5,  'A', 0x8E, 0x8F, 0x92, 0x80,
+				0xD1, 0x90, 0xD6, 0xD3, 'I',   'I', 0xD7, 0xD4,
+				'D',  0xA5,  'O',  'O', 0xD8,  'O', 0x99,  'x',
+				'0',  0xD2,  'U', 0xD9, 0x9A,  'Y',  'p', 0xB1,
+				/* #224 = 0xE0 */
+				0x85, 0xA0, 0x83,  'a', 0x84, 0x86, 0x91, 0x87,
+				0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B,
+				'o',  0xA4, 0x95, 0xA9, 0x93,  'o', 0x94,  '/',
+				'0',  0x97, 0xA3, 0x96, 0x81,  'y',  'p', 0x89
+				};
+			for (tmp=0;tmp < 128 ;tmp++)
+			p->charmap[tmp]=charmap[tmp];
+
+
+			//{bytes to send, icon bit mapped to bit 0, icon bit mapped to bit 1, ...}
+			const int usr_chr_dot_assignment[57]={5,	 8, 7, 6, 5, 4, 3, 2, 1,
+								16,15,14,13,12,11,10, 9,
+								24,23,22,21,20,19,18,17,
+								32,31,30,29,28,27,26,25,
+								0, 0, 0, 0, 0,35,34,33};
+			for (tmp=0;tmp < 57 ;tmp++)
+				p->usr_chr_dot_assignment[tmp]=usr_chr_dot_assignment[tmp];
+
+			//Where to place the usercharacters (0..30) in the asciicode.
+			//Also used to map standardcharacters in the usercharacterspace(0..30)
+			//(useful for displays with less then 30 usercharacters and predefined bars)
+			const unsigned int usr_chr_mapping[31]=
+			{0xCD, 0xCE, 0xCF};
+			for (tmp=0;tmp < 31 ;tmp++)
+				p->usr_chr_mapping[tmp]=usr_chr_mapping[tmp];
+		}
--- ../lcdproc-CVS-current-test/server/drivers/serialVFD_displays.h	1970-01-01 01:00:00.000000000 +0100
+++ ./server/drivers/serialVFD_displays.h	2006-05-16 14:46:31.000000000 +0200
@@ -0,0 +1,28 @@
+/* 	This is the LCDproc driver for various serial VFD Devices
+
+	Copyright (C) 2006 Stefan Herdler
+
+	2006-05-16 Version 0.3: everything should work (not all hardware tested!)
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 */
+
+#ifndef SERIALVFD_DISPLAYS_H
+#define SERIALVFD_DISPLAYS_H
+
+#include "lcd.h"
+#include "serialVFD.h"
+
+void serialVFD_load_display_data(Driver *drvthis);
+#endif
--- ../lcdproc-CVS-current-test/server/drivers/Makefile.am	2006-05-08 23:56:19.000000000 +0200
+++ ./server/drivers/Makefile.am	2006-05-17 01:08:44.000000000 +0200
@@ -82,7 +82,7 @@ NoritakeVFD_SOURCES = lcd.h lcd_lib.h No
 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
 sed1520_SOURCES =    lcd.h sed1520.c sed1520.h sed1520fm.c sed1520fm.h port.h report.h
-serialVFD_SOURCES =  lcd.h lcd_lib.h serialVFD.c serialVFD.h report.h adv_bignum.h
+serialVFD_SOURCES =  lcd.h lcd_lib.h serialVFD.c serialVFD.h report.h adv_bignum.h serialVFD_displays.c serialVFD_displays.h serialVFD_io.c serialVFD_io.h
 stv5730_SOURCES =    lcd.h stv5730.c stv5730.h report.h
 svga_SOURCES =       lcd.h svgalib_drv.c svgalib_drv.h report.h
 t6963_SOURCES =      lcd.h lcd_lib.h t6963.c t6963.h t6963_font.h report.h
--- ../lcdproc-CVS-current-test/docs/lcdproc-user/drivers/serialVFD.docbook	2006-04-05 12:36:59.000000000 +0200
+++ ./docs/lcdproc-user/drivers/serialVFD.docbook	2006-05-16 22:58:44.000000000 +0200
@@ -2,69 +2,116 @@
 <title>The serialVFD Driver</title>
 
 <para>
-This section talks about using LCDproc with LCD displays that use the
-serialVFD chipset.
+This section talks about using LCDproc with VFD character-displays build by NEC, FUTABA and NORITAKE.
 </para>
 
-<sect2 id="serialVFD-connections">
-<title>Connections</title>
 
+<para>
+The serialVFD-driver is working with NEC FIPC8367 based VFDs
+and the "KD Rev 2.1" (an ATMEL AT90S.... based FM20X2KB-AB replacement).
+ It is also known to work on FUTABA VFDs.</para>
 
-The serialVFD-driver should work with all NEC FIPC8367 based VFDs:
-NEC FC20X2JA
-NEC FM20X2KB-AB
-NEC FC20X1SA-AB/AA
-...
-Tested only on: NEC FM20X2KB-AB
-The driver also works (tested) on "KD Rev 2.1" (an ATMEL AT90S....
-based FM20X2KB-AB replacement).
-Note: Above char. 128 the FIPC-displays and KD's charactersets
-are different.
+<para>
+The driver should operate most of NEC, Futaba and Noritake 7x5 dot VFDs with
+ serial(rs232) and/or parallel interface. See the following table for testing-status.
+  Feedback is welcome.
 
-The driver may work or will be easy to get working on the following
-Displays / Controllers (not tested!).
 
-<table>
-<tgroup cols="2">
+<table><title>serialVFD: Display Status</title>
+<tgroup cols="5">
   <thead>
     <row>
       <entry>Display</entry>
       <entry>Controller</entry>
+      <entry>Serial</entry>
+      <entry>Parallel</entry>
+      <entry>Display tested</entry>
+      <entry>Remark</entry>
     </row>
   </thead>
   <tbody>
     <row>
+      <entry>NEC FM20X2KB-AB</entry>
+      <entry>NEC FIPC8367</entry>
+      <entry>Ok</entry>
+      <entry>Ok</entry>
+      <entry>Yes</entry>
+      <entry> </entry>
+    </row>
+    <row>
+      <entry>NEC FC20X2JA</entry>
+      <entry>NEC FIPC8367</entry>
+      <entry>(Ok)</entry>
+      <entry>(Ok)</entry>
+      <entry>No</entry>
+      <entry>Same Controller as on FM20X2KB-AB</entry>
+    </row>
+    <row>
+      <entry>NEC FC20X1SA-AB/AA</entry>
+      <entry>NEC FIPC8367</entry>
+      <entry>(Ok)</entry>
+      <entry>(Ok)</entry>
+      <entry>No</entry>
+      <entry>Same Controller as on FM20X2KB-AB</entry>
+    </row>
+    <row>
+      <entry>KD Rev 2.1</entry>
+      <entry>AT90S....
+ microcontroller</entry>
+      <entry>Ok</entry>
+      <entry>Ok</entry>
+      <entry>Yes</entry>
+      <entry> </entry>
+    </row>
+
+    <row>
+      <entry>FUTABA M402SD06GJ</entry>
+      <entry>?</entry>
+      <entry>(?)*</entry>
+      <entry>Ok</entry>
+      <entry>Yes</entry>
+      <entry>(* perhaps no compatible baudrate, not tested)
+ The display has no user-characters set  <command>Custom-Characters=0</command>
+ in <filename>LCDd.conf.</filename></entry>
+    </row>
+    <row>
       <entry>FUTABA M204SD01AA</entry>
       <entry>FUTABA 5P00A016</entry>
+      <entry>(Ok)</entry>
+      <entry>(Ok)</entry>
+      <entry>No</entry>
+      <entry> </entry>
     </row>
+
+
     <row>
       <entry>Noritake CU20026SCPB-T</entry>
-      <entry>(microcontroller)</entry>
+      <entry>microcontroller</entry>
+      <entry>(Ok)</entry>
+      <entry>(Ok)</entry>
+      <entry>No</entry>
+      <entry> </entry>
+
     </row>
     <row>
       <entry>Noritake CU20045SCPB-T28A</entry>
       <entry>?</entry>
+      <entry>(Ok)</entry>
+      <entry>(Ok)</entry>
+      <entry>No</entry>
+      <entry> </entry>
     </row>
   </tbody>
 </tgroup>
 </table>
-
-... or compatible.
-(most Futaba/Noritake 7x5 dot VFDs with serial(rs232) interface
-(including  serial(rs232)/parallel types))
-
-<para>
-Maybe there are little changes in the commands to do to get all
-functions to work correctly. But because of the similarity of the
-protocols, it wont be much work.
+() feature not tested.
 </para>
-
 <para>
-If you want to add a new device to the driver add a new section
-to the displaytype-switch-case in the init-function and fill it
-with the correct commands for the display.
-(Try which displaytype works best with your display, copy and modify
-it's section that is the easiest way I guess.)
+If your display isn't working 100% satisfactorily you can add a new device with modified hardware
+commands to the driver if you want. To do that you have to add a new section to the display-
+<command>Type=</command>-switch-case in <filename>./server/drivers/serialVFD-displays.c</filename>
+and to write a new "load"function with the correct commands for the display.(Try which display-<command>Type=</command>
+works best with your display, copy, rename and modify this function that is the easiest way I guess.)
 </para>
 
 <para>
@@ -78,24 +125,25 @@ running. It may take a few minutes until
 the display show everything correctly.
 </para>
 
-<para>
-To enable the bignumbers on 2-line displays (only this driver supports
-this yet) you have to edit <filename>clients/lcdproc/chrono.c</filename>
-before compiling.
-In function <function>big_clock_screen</function> you have to replace the
-<literal>4</literal> by a <literal>2</literal> in this line:
-<code>if (lcd_hgt &lt; 4)</code>
-</para>
 
+<sect2 id="serialVFD-connections">
+<title>Connecting The Display</title>
+<para>The Connections shown have been tested successfully.</para>
+<warning><para>Always cross-check with your datasheet, before connecting your display!
+ Displays of same manufacturer may have different pin assignments!</para></warning>
+<para>With this example connections it will be easy to connect displays with different connector
+ pin-layouts, the pins are commonly named equal in the datasheet.<para>
+
+<sect3 id="serialVFD-serial-connections">
+<title>Serial Connections</title>
 <para>
-This driver uses the serial mode of the displays.
 It is NOT possible to connect most of the displays directly to the
 serialport. The signal has to be inverted. I use the following
 circuit to do that job.
 </para>
 
 <figure>
-<title>serialVFD: Connecting the display</title>
+<title>serialVFD: Serial Inverter</title>
 <screen>
 <![CDATA[
 Computer                                          Display
@@ -121,9 +169,9 @@ pin(signal)                             
 		|      --->-    A*
 		|         E|    |
 		|          |    |
-5(GND)  --------o----------o----o----------------- GND
-
-Shield  ------------------------------------------
+5(GND)  --------o----------o----o--------------o-- GND
+					       |*
+Shield  ---------------------------------------o
 optional
 
 *connect near display
@@ -131,25 +179,27 @@ optional
 </screen>
 </figure>
 
-The pins on the different displays vary.
+<para>The pins on the different displays vary.</para>
 
+<para><title>NEC Displays (FM20X2KB-AB):</title></para>
 
-FM20X2KB-AB:
-
-CN1:
+<para>CN1:</para>
+<screen><![CDATA[
 Pin 33 &lt;--- RxD
 (Testmode: connect pins 25 and 26, then power up)
+]]></screen>
 
-CN2:
+<para>CN2:</para>
+<screen><![CDATA[
 Pin 1  &lt;--- +5V
 Pin 2  &lt;--- GND
+]]></screen>
 
 
-
-KD Rev 2.1:
-
-blue connector (6pin in a row) (the important one!):
-
+<para><title>KD Rev 2.1:</title></para>
+<para>
+The blue connector (6pin in a row) (the important one!):
+</para>
 <screen>
 <![CDATA[
 --------------------------------
@@ -163,33 +213,147 @@ blue connector (6pin in a row) (the impo
   Hold the display in that position where you can read
   the "KD Rev 2.1" marking normally!
   </para>
-</tip>  
+</tip>
 
-gray connector (10pin 2 rows):
-Do not use. (the ATMEL ISP connector I guess)
-
-The two jumpers next to the gray connector:
-Normally not used.
+<para>The gray connector (10pin 2 rows):</para>
+<screen>
+<![CDATA[Do not use. (the ATMEL ISP connector I guess)
+]]>
+</screen>
+<para>The two jumpers next to the gray connector:</para>
+<screen>
+<![CDATA[Normally not used.
 You can activate two different testmodes with them.
+]]>
+</screen>
 
-</sect2>
+</sect3>
+
+<sect3 id="serialVFD-parallel-connections">
+<title>Parallel Connections</title>
+
+
+<para><title>NEC Displays (FM20X2KB-AB):</title></para>
+
+<para>CN1:</para>
+<screen><![CDATA[
+parallel Port:			Display (NEC):
+Pin: 	Name:			Name:   Pin:
+
+1	/STROBE --------------	/WR	1
+2	D0      --------------	D0	15
+3	D1      --------------	D1	13
+4	D2      --------------	D2	11
+5	D3      --------------	D3	9
+6	D4      --------------	D4	7
+7	D5      --------------	D5	5
+8	D6      --------------	D6	3
+9	D7      --------------	D7	1
+10	/ACK	--o
+		  |
+11	BUSY    --o-----------	BUSY	27
+
+			   o--  /CS	23
+			   |
+18 - 25	GND    ------------o--	GND	2,4,6,8,10,12,14,16,18,20,22,24,26,28,20,32,34
+			   |*
+Shield  -------------------o
+optional
 
+*connect near display
+]]></screen>
+<para>CN2:</para>
+<screen><![CDATA[
+Pin 1  &lt;--- +5V
+Pin 2  &lt;--- GND
+]]></screen>
+
+<para><title>FUTABA Displays (M402SD06GJ):</title></para>
+<screen><![CDATA[
+parallel Port:			Display (FUTABA):
+Pin: 	Name:			Name:   Pin:
+
+1	/STROBE --------------	/WR	1
+2	D0      --------------	D0	15
+3	D1      --------------	D1	13
+4	D2      --------------	D2	11
+5	D3      --------------	D3	9
+6	D4      --------------	D4	7
+7	D5      --------------	D5	5
+8	D6      --------------	D6	3
+9	D7      --------------	D7	1
+10	/ACK	--o
+		  |
+11	BUSY    --o-----------	BUSY	20
+
+			   o--  /SEL	23
+			   |
+18 - 25	GND    ------------o--	GND	10,12,14
+			   |*
+Shield  -------------------o
+optional
+			   0--	TEST	16
+			   |
+		+5V -------o--	+5V	2,4,6
+
+*connect near display
+]]></screen>
+
+</sect3>
+</sect2>
 <!-- ## Serial VFD driver ## -->
 <sect2 id="serialVFD-config">
 <title>Configuration in LCDd.conf</title>
 
+
 <sect3>
 <title>[serialVFD]</title>
 
 <variablelist>
+
+<varlistentry>
+  <term>
+    <command>use_parallel=</command>
+    <arg choice="plain">
+    <group choice="req">
+      <arg choice="plain"><literal><emphasis>yes</emphasis></literal></arg>
+      <arg choice="plain"><literal>no</literal></arg>
+    </group>
+    </arg>
+  </term>
+  <listitem><para>
+    "<literal>no</literal>" if display connected serial, "<literal>yes</literal>" if connected parallel [default: <literal>no</literal>(serial)].
+  </para></listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>
+    <command>Port=</command>
+    <arg choice="plain"><replaceable>PORT</replaceable></arg>
+  </term>
+  <listitem><para>
+    Portaddress where the LPT is. Used in parallelmode only. Usual values are 0x278, 0x378 and 0x3BC [default: <literal>0x278</literal>].
+  </para></listitem>
+</varlistentry>
+
 <varlistentry>
   <term>
     <command>Device=</command>
     <arg choice="plain"><replaceable>DEVICE</replaceable></arg>
   </term>
   <listitem><para>
-    Device where the VFD is. Usual values are <filename>/dev/ttyS0</filename> and <filename>/dev/ttyS1</filename>
-    Default: <filename>/dev/lcd</filename>
+    Device to use in serial mode. Usual values are <filename>/dev/ttyS0</filename> and <filename>/dev/ttyS1</filename>
+    [default: <filename>/dev/lcd</filename>].
+  </para></listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>
+    <command>Custom-Characters=</command>
+    <arg choice="plain"><replaceable>CUSTOM-CHARACTERS</replaceable></arg>
+  </term>
+  <listitem><para>
+Number of Custom-Characters [default: Display-<command>Type</command> dependent].
   </para></listitem>
 </varlistentry>
 
@@ -204,7 +368,7 @@ You can activate two different testmodes
   </term>
   <listitem><para>
     Specifies the size of the VFD.
-    default: <literal>20x2</literal>
+    [default: <literal>20x2</literal>]
   </para></listitem>
 </varlistentry>
 
@@ -247,7 +411,7 @@ You can activate two different testmodes
     </tgroup>
     </informaltable>
     <note><para>
-      Options 3 and 4 should work, but have not been tested yet. Feedback is welcome.
+      Noritake VFDs have not been tested yet. Feedback is welcome.
     </para></note>
   </listitem>
 </varlistentry>
@@ -258,9 +422,21 @@ You can activate two different testmodes
     <arg choice="plain"><replaceable>BRIGHTNESS</replaceable></arg>
   </term>
   <listitem><para>
-    Display brightness [default: 255].
-  0 min ... 255 max ... 1000 also max
-  (4 steps 0-64, 65-128, 129-192, 193-1000)
+Set the initial brightness [default: 1000; legal: 0 - 1000]
+ (4 steps 0-250, 251-500, 501-750, 751-1000)
+  </para></listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>
+    <command>OffBrightness=</command>
+    <arg choice="plain"><replaceable>OFFBRIGHTNESS</replaceable></arg>
+  </term>
+  <listitem><para>
+Set the initial off-brightness [default: 0; legal: 0 - 1000].
+ This value is used when the display is normally
+ switched off in case LCDd is inactive.
+ (4 steps 0-250, 251-500, 501-750, 751-1000)
   </para></listitem>
 </varlistentry>
 
@@ -279,7 +455,7 @@ You can activate two different testmodes
   </term>
   <listitem><para>
     Set the the baud rate communication with the VFD.
-    If not given, it defaults to <literal>9600</literal>.
+    If not given [default <literal>9600</literal>].
   </para></listitem>
 </varlistentry>
 
@@ -294,7 +470,7 @@ You can activate two different testmodes
     </arg>
   </term>
   <listitem><para>
-    Enable ISO-8859-1 compatibility. Ddefault is <literal>yes</literal>.
+    Enable ISO-8859-1 compatibility [default is <literal>yes</literal>].
   </para></listitem>
 </varlistentry>
 </variablelist>
--- ../lcdproc-CVS-current-test/docs/LCDd.8	2006-04-14 15:05:00.000000000 +0200
+++ ./docs/LCDd.8	2006-05-16 23:04:52.000000000 +0200
@@ -169,7 +169,7 @@ SED1330/SED1335 (aka S1D13300/S1D13305) 
 122x32 pixel graphic displays based on SED1520 controllers
 .TP
 .B serialVFD
-NEC FIPC8367 based serial VFDs
+NEC (FIPC8367 based) and FUTABA VFDs
 .TP
 .B sli
 Wirz SLI driver (unknown)
--- ../lcdproc-CVS-current-test/LCDd.conf	2006-05-08 23:56:19.000000000 +0200
+++ ./LCDd.conf	2006-05-17 16:27:06.000000000 +0200
@@ -662,30 +662,44 @@ Port=0x378
 ## Serial VFD driver ##
 ## Drives various (see below) serial 5x7dot VFD's.  ##
 [serialVFD]
-# device where the VFD is. Usual values are /dev/ttyS0 and /dev/ttyS1
+
+# Specifies the displaytype.[default: 0]
+# 0 NEC (FIPC8367 based) VFDs.
+# 1 KD Rev 2.1.
+# 2 Noritake VFDs (*).
+# 3 Futaba VFDs
+# (* most should work, not testet yet.)
+Type=0
+
+# "no" if display connected serial, "yes" if connected parallel. [default: no(serial)]
+use_parallel=no
+
+# Number of Custom-Characters [default: displaytype dependent]
+#Custom-Characters=0
+
+# Portaddress where the LPT is. Used in parallelmode only. Usual values are 0x278, 0x378 and 0x3BC
+Port=0x378
+
+# Device to use in serial mode. Usual values are /dev/ttyS0 and /dev/ttyS1
 Device=/dev/ttyS1
 
 # Specifies the size of the VFD.
 Size=20x2
 
-# Specifies the display type [default: 0]
-# 0 NEC (FIPC8367 based) VFDs.
-# 1 KD Rev 2.1.
-# 2 Noritake VFDs (*).
-# 3 Futaba VFDs (*).
-# (* most should work, not tested yet.)
-Type=1
-
-# Display brightness [default: 255].
-# 0 min ... 255 max ... 1000 also max
-# (4 steps 0-64, 65-128, 129-192, 193-1000)
-Brightness=255
+# Set the initial brightness [default: 1000; legal: 0 - 1000]
+# (4 steps 0-250, 251-500, 501-750, 751-1000)
+Brightness=1000
+# Set the initial off-brightness [default: 0; legal: 0 - 1000]
+# This value is used when the display is normally
+# switched off in case LCDd is inactive
+# (4 steps 0-250, 251-500, 501-750, 751-1000)
+OffBrightness=0
 
-# set the serial port speed [default: 9600; legal: 1200, 2400, 9600, 19200, 115200]
+# set the serial port speed [default: 9600]
 Speed=9600
 
-# enable ISO 8859 1 compatibility [default: yes; legal: yes, no]
-ISO_8859_1=yes
+# enable ISO 8859 1 compatibility [default: 1]
+# ISO_8859_1=1
 
 
 

--------------090006010607090701090706--