diff options
| -rw-r--r-- | config.h.in | 6 | ||||
| -rwxr-xr-x | configure | 79 | ||||
| -rw-r--r-- | configure.in | 14 | ||||
| -rw-r--r-- | drivers.m4 | 9 | ||||
| -rw-r--r-- | drv_HD44780.c | 2987 | ||||
| -rw-r--r-- | drv_generic_i2c.c | 350 | ||||
| -rw-r--r-- | drv_generic_i2c.h | 139 | ||||
| -rw-r--r-- | lcd4linux_i2c.h | 643 | 
8 files changed, 2408 insertions, 1819 deletions
| diff --git a/config.h.in b/config.h.in index 6381155..d008bc9 100644 --- a/config.h.in +++ b/config.h.in @@ -55,12 +55,6 @@  /* Define to 1 if you have the <linux/dvb/frontend.h> header file. */  #undef HAVE_LINUX_DVB_FRONTEND_H -/* Define to 1 if you have the <linux/i2c-dev.h> header file. */ -#undef HAVE_LINUX_I2C_DEV_H - -/* Define to 1 if you have the <linux/i2c.h> header file. */ -#undef HAVE_LINUX_I2C_H -  /* Define to 1 if you have the <linux/isdn.h> header file. */  #undef HAVE_LINUX_ISDN_H @@ -5452,76 +5452,7 @@ done  # check for i2c - - - -for ac_header in linux/compiler.h linux/i2c.h linux/i2c-dev.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then -  echo $ECHO_N "(cached) $ECHO_C" >&6 -else -  cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h.  */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h.  */ - -#if HAVE_LINUX_COMPILER_H -#include <linux/compiler.h> -# endif -#if HAVE_LINUX_I2C_H -#include <linux/i2c.h> -# endif - - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 -  (eval $ac_compile) 2>conftest.er1 -  ac_status=$? -  grep -v '^ *+' conftest.er1 >conftest.err -  rm -f conftest.er1 -  cat conftest.err >&5 -  echo "$as_me:$LINENO: \$? = $ac_status" >&5 -  (exit $ac_status); } && -	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err' -  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 -  (eval $ac_try) 2>&5 -  ac_status=$? -  echo "$as_me:$LINENO: \$? = $ac_status" >&5 -  (exit $ac_status); }; } && -	 { ac_try='test -s conftest.$ac_objext' -  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 -  (eval $ac_try) 2>&5 -  ac_status=$? -  echo "$as_me:$LINENO: \$? = $ac_status" >&5 -  (exit $ac_status); }; }; then -  eval "$as_ac_Header=yes" -else -  echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -eval "$as_ac_Header=no" -fi -rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 -if test `eval echo '${'$as_ac_Header'}'` = yes; then -  cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - has_i2c="true" -else -  has_i2c="false";break -fi - -done +has_i2c="true"  # check for serdisplib @@ -6062,7 +5993,7 @@ TEXT="no"  GRAPHIC="no"  IMAGE="no" -# generiv I/O drivers +# generic I/O drivers  PARPORT="no"  SERIAL="no"  I2C="no" @@ -6374,18 +6305,12 @@ fi  # generic i2c driver  if test "$I2C" = "yes"; then -   if test "$has_i2c" = true; then        DRIVERS="$DRIVERS drv_generic_i2c.o"  cat >>confdefs.h <<\_ACEOF  #define WITH_I2C 1  _ACEOF -   else -      I2C="no" -      { echo "$as_me:$LINENO: WARNING: I2C include files not found: I2C bus driver disabled" >&5 -echo "$as_me: WARNING: I2C include files not found: I2C bus driver disabled" >&2;} -   fi  fi diff --git a/configure.in b/configure.in index a2d9822..8c42187 100644 --- a/configure.in +++ b/configure.in @@ -54,23 +54,9 @@ AC_CHECK_HEADERS(gd/gd.h gd.h, [has_gd="true";break], [has_gd="false"])  # check for usb.h  AC_CHECK_HEADERS(usb.h, [has_usb="true"], [has_usb="false"]) -# check for i2c -AC_CHECK_HEADERS(linux/compiler.h linux/i2c.h linux/i2c-dev.h,[has_i2c="true"],[has_i2c="false";break],[ -#if HAVE_LINUX_COMPILER_H -#include <linux/compiler.h> -# endif -#if HAVE_LINUX_I2C_H -#include <linux/i2c.h> -# endif -]) -  # check for serdisplib  AC_CHECK_HEADERS(serdisplib/serdisp.h, [has_serdisplib="true"], [has_serdisplib="false"]) -# check for python -sinclude(python.m4) -AC_PYTHON_DEVEL -  # drivers  sinclude(drivers.m4) @@ -372,13 +372,8 @@ fi  # generic i2c driver  if test "$I2C" = "yes"; then -   if test "$has_i2c" = true; then -      DRIVERS="$DRIVERS drv_generic_i2c.o" -      AC_DEFINE(WITH_I2C, 1, [I2C bus driver]) -   else -      I2C="no" -      AC_MSG_WARN(I2C include files not found: I2C bus driver disabled) -   fi    +   DRIVERS="$DRIVERS drv_generic_i2c.o" +   AC_DEFINE(WITH_I2C, 1, [I2C bus driver])  fi diff --git a/drv_HD44780.c b/drv_HD44780.c index e032a5d..91215c3 100644 --- a/drv_HD44780.c +++ b/drv_HD44780.c @@ -1,1492 +1,1497 @@ -/* $Id: drv_HD44780.c,v 1.49 2005/05/08 04:32:44 reinelt Exp $ - * - * new style driver for HD44780-based displays - * - * Copyright (C) 2003 Michael Reinelt <reinelt@eunet.at> - * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> - * - * Support for I2C bus - * Copyright (C) 2005 Luis F. Correia <luis.f.correia@seg-social.pt> - * - * Modification for 4-Bit mode - * Copyright (C) 2003 Martin Hejl (martin@hejl.de) - * - * Modification for 2nd controller support - * Copyright (C) 2003 Jesse Brook Kovach <jkovach@wam.umd.edu> - * - * This file is part of LCD4Linux. - * - * LCD4Linux 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, or (at your option) - * any later version. - * - * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * +/* $Id: drv_HD44780.c,v 1.50 2005/05/31 20:42:55 lfcorreia Exp $
 + *
 + * new style driver for HD44780-based displays
 + *
 + * Copyright (C) 2003 Michael Reinelt <reinelt@eunet.at>
 + * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 + *
 + * Support for I2C bus
 + * Copyright (C) 2005 Luis F. Correia <luis.f.correia@seg-social.pt>
 + *
 + * Modification for 4-Bit mode
 + * Copyright (C) 2003 Martin Hejl (martin@hejl.de)
 + *
 + * Modification for 2nd controller support
 + * Copyright (C) 2003 Jesse Brook Kovach <jkovach@wam.umd.edu>
 + *
 + * This file is part of LCD4Linux.
 + *
 + * LCD4Linux 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, or (at your option)
 + * any later version.
 + *
 + * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 + *
 + *
   * $Log: drv_HD44780.c,v $ - * Revision 1.49  2005/05/08 04:32:44  reinelt - * CodingStyle added and applied - * - * Revision 1.48  2005/05/05 08:36:12  reinelt - * changed SELECT to SLCTIN - * - * Revision 1.47  2005/03/28 22:29:23  reinelt - * HD44780 multiple displays patch from geronet - * - * Revision 1.46  2005/03/28 19:39:23  reinelt - * HD44780/I2C patch from Luis merged (still does not work for me) - * - * Revision 1.45  2005/03/25 15:44:43  reinelt - * HD44780 Backlight fixed (thanks to geronet) - * - * Revision 1.44  2005/01/29 09:30:56  reinelt - * minor HD44780 cleanups - * - * Revision 1.43  2005/01/18 06:30:23  reinelt - * added (C) to all copyright statements - * - * Revision 1.42  2005/01/17 06:38:48  reinelt - * info about backlight and brightness - * - * Revision 1.41  2005/01/17 06:29:24  reinelt - * added software-controlled backlight support to HD44780 - * - * Revision 1.40  2004/11/30 05:01:25  reinelt - * removed compiler warnings for deactivated i2c bus - * - * Revision 1.39  2004/10/17 09:24:31  reinelt - * I2C support for HD44780 displays by Luis (does not work by now) - * - * Revision 1.38  2004/09/19 09:31:19  reinelt - * HD44780 busy flag checking improved: fall back to busy-waiting if too many errors occur - * - * Revision 1.37  2004/09/18 15:58:57  reinelt - * even more HD44780 cleanups, hardwiring for LCM-162 - * - * Revision 1.36  2004/09/18 10:57:29  reinelt - * more parport/i2c cleanups - * - * Revision 1.35  2004/09/18 09:48:29  reinelt - * HD44780 cleanup and prepararation for I2C backend - * LCM-162 submodel framework - * - * Revision 1.34  2004/09/18 08:22:59  reinelt - * drv_generic_parport_status() to read status lines - * - * Revision 1.33  2004/08/29 13:03:41  reinelt - * - * added RouterBoard driver - * - * Revision 1.32  2004/06/26 12:04:59  reinelt - * - * uh-oh... the last CVS log message messed up things a lot... - * - * Revision 1.31  2004/06/26 09:27:20  reinelt - * - * added '-W' to CFLAGS - * changed all C++ comments to C ones - * cleaned up a lot of signed/unsigned mistakes - * - * Revision 1.30  2004/06/20 10:09:54  reinelt - * - * 'const'ified the whole source - * - * Revision 1.29  2004/06/06 06:51:59  reinelt - * - * do not display end splash screen if quiet=1 - * - * Revision 1.28  2004/06/05 06:41:39  reinelt - * - * chancged splash screen again - * - * Revision 1.27  2004/06/05 06:13:11  reinelt - * - * splash screen for all text-based display drivers - * - * Revision 1.26  2004/06/02 10:09:22  reinelt - * - * splash screen for HD44780 - * - * Revision 1.25  2004/06/02 09:41:19  reinelt - * - * prepared support for startup splash screen - * - * Revision 1.24  2004/06/01 06:45:29  reinelt - * - * some Fixme's processed - * documented some code - * - * Revision 1.23  2004/05/31 05:38:02  reinelt - * - * fixed possible bugs with user-defined chars (clear high bits) - * thanks to Andy Baxter for debugging the MilfordInstruments driver! - * - * Revision 1.22  2004/05/27 03:39:47  reinelt - * - * changed function naming scheme to plugin::function - * - * Revision 1.21  2004/05/26 11:37:36  reinelt - * - * Curses driver ported. - * - * Revision 1.20  2004/05/22 04:23:49  reinelt - * - * removed 16*x fix again (next time think before commit :-) - * - * Revision 1.19  2004/05/22 04:21:02  reinelt - * - * fix for display RAM layout on 16x4 displays (thanks to toxicated101) - * - * Revision 1.18  2004/03/20 07:31:32  reinelt - * support for HD66712 (which has a different RAM layout) - * further threading development - * - * Revision 1.17  2004/03/19 09:17:46  reinelt - * - * removed the extra 'goto' function, row and col are additional parameters - * of the write() function now. - * - * Revision 1.16  2004/03/11 06:39:58  reinelt - * big patch from Martin: - * - reuse filehandles - * - memory leaks fixed - * - earlier busy-flag checking with HD44780 - * - reuse memory for strings in RESULT and hash - * - netdev_fast to wavid time-consuming regex - * - * Revision 1.15  2004/03/03 03:47:04  reinelt - * big patch from Martin Hejl: - * - use qprintf() where appropriate - * - save CPU cycles on gettimeofday() - * - add quit() functions to free allocated memory - * - fixed lots of memory leaks - * - * Revision 1.14  2004/03/01 04:29:51  reinelt - * cfg_number() returns -1 on error, 0 if value not found (but default val used), - *  and 1 if value was used from the configuration. - * HD44780 driver adopted to new cfg_number() - * Crystalfontz 631 driver nearly finished - * - * Revision 1.13  2004/02/15 21:43:43  reinelt - * T6963 driver nearly finished - * framework for graphic displays done - * i2c_sensors patch from Xavier - * some more old generation files removed - * - * Revision 1.12  2004/02/14 11:56:17  reinelt - * M50530 driver ported - * changed lots of 'char' to 'unsigned char' - * - * Revision 1.11  2004/02/04 19:10:51  reinelt - * Crystalfontz driver nearly finished - * - * Revision 1.10  2004/02/02 05:22:16  reinelt - * Brightness fpr Noritake Displays avaliable as a plugin - * - * Revision 1.9  2004/02/01 11:51:22  hejl - * Fixes for busy flag - * - * Revision 1.8  2004/02/01 08:05:12  reinelt - * Crystalfontz 633 extensions (CRC checking and stuff) - * Models table for HD44780 - * Noritake VFD BVrightness patch from Bill Paxton - * - * Revision 1.7  2004/01/30 07:12:35  reinelt - * HD44780 busy-flag support from Martin Hejl - * loadavg() uClibc replacement from Martin Heyl - * round() uClibc replacement from Martin Hejl - * warning in i2c_sensors fixed - * [ - * - * Revision 1.6  2004/01/29 04:40:02  reinelt - * every .c file includes "config.h" now - * - * Revision 1.5  2004/01/23 07:04:17  reinelt - * icons finished! - * - * Revision 1.4  2004/01/23 04:53:48  reinelt - * icon widget added (not finished yet!) - * - * Revision 1.3  2004/01/22 07:57:45  reinelt - * several bugs fixed where segfaulting on layout>display - * Crystalfontz driver optimized, 632 display already works - * - * Revision 1.2  2004/01/21 06:39:27  reinelt - * HD44780 missed the "clear display' sequence - * asc255bug handling added - * HD44780 tested, works here! - * - * Revision 1.1  2004/01/20 15:32:49  reinelt - * first version of Next Generation HD44780 (untested! but it compiles...) - * some cleanup in the other drivers - * - */ - -/*  - * - * exported fuctions: - * - * struct DRIVER drv_HD44780 - * - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <termios.h> -#include <fcntl.h> -#include <sys/time.h> -#include <sys/ioctl.h> - -#include "debug.h" -#include "cfg.h" -#include "udelay.h" -#include "qprintf.h" -#include "timer.h" -#include "plugin.h" -#include "widget.h" -#include "widget_text.h" -#include "widget_icon.h" -#include "widget_bar.h" -#include "drv.h" -#include "drv_generic_text.h" -#include "drv_generic_parport.h" - -#ifdef WITH_I2C -#include "drv_generic_i2c.h" -#endif - -static char Name[] = "HD44780"; - -static int Bus; -static int Model; -static int Capabilities; - - -/* low level communication timings [nanoseconds] - * as these values differ from spec to spec, - * we use the worst-case values. - */ - -#define T_CYCLE 1000		/* Enable cycle time */ -#define T_PW     450		/* Enable pulse width */ -#define T_AS      60		/* Address setup time */ -#define T_H       40		/* Data hold time */ -#define T_AH      20		/* Address hold time */ - - -/* HD44780 execution timings [microseconds] - * as these values differ from spec to spec, - * we use the worst-case values. - */ - -#define T_INIT1 4100		/* first init sequence:  4.1 msec */ -#define T_INIT2  100		/* second init sequence: 100 usec */ -#define T_EXEC    80		/* normal execution time */ -#define T_WRCG   120		/* CG RAM Write */ -#define T_CLEAR 2250		/* Clear Display */ - - -static int Bits = 0; -static int numControllers = 0; -static int allControllers = 0; -static int currController = 0; - -/* size of every single controller */ -static int CROWS[4]; -static int CCOLS[4]; - -static unsigned char SIGNAL_RW; -static unsigned char SIGNAL_RS; -static unsigned char SIGNAL_ENABLE; -static unsigned char SIGNAL_ENABLE2; -static unsigned char SIGNAL_ENABLE3; -static unsigned char SIGNAL_ENABLE4; -static unsigned char SIGNAL_BACKLIGHT; -static unsigned char SIGNAL_GPO; - -/* maximum time to wait for the busy-flag (in usec) */ -#define MAX_BUSYFLAG_WAIT 10000 - -/* maximum busy flag errors before falling back to busy-waiting */ -#define MAX_BUSYFLAG_ERRORS 20 - -/* flag for busy-waiting vs. busy flag checking */ -static int UseBusy = 0; - - -/* Fixme: GPO's not yet implemented */ -static int GPOS; -/* static int GPO=0; */ - - -typedef struct { -    int type; -    char *name; -    int capabilities; -} MODEL; - -#define CAP_PARPORT    (1<<0) -#define CAP_I2C        (1<<1) -#define CAP_GPO        (1<<2) -#define CAP_BACKLIGHT  (1<<3) -#define CAP_BRIGHTNESS (1<<4) -#define CAP_BUSY4BIT   (1<<5) -#define CAP_HD66712    (1<<6) -#define CAP_LCM162     (1<<7) - -#define BUS_PP  CAP_PARPORT -#define BUS_I2C CAP_I2C - - -static MODEL Models[] = { -    {0x01, "generic", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BACKLIGHT}, -    {0x02, "Noritake", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BRIGHTNESS}, -    {0x03, "Soekris", CAP_PARPORT | CAP_BUSY4BIT}, -    {0x04, "HD66712", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BACKLIGHT | CAP_HD66712}, -    {0x05, "LCM-162", CAP_PARPORT | CAP_LCM162}, -    {0xff, "Unknown", 0} -}; - - -/****************************************/ -/***  generic functions               ***/ -/****************************************/ - -static int (*drv_HD_load) (const char *section); -static void (*drv_HD_command) (const unsigned char controller, const unsigned char cmd, const int delay); -static void (*drv_HD_data) (const unsigned char controller, const char *string, const int len, const int delay); -static void (*drv_HD_stop) (void); - - - -/****************************************/ -/***  parport dependant functions     ***/ -/****************************************/ - -static void drv_HD_PP_busy(const int controller) -{ -    static unsigned int errors = 0; - -    unsigned char enable; -    unsigned char data = 0xFF; -    unsigned char busymask; -    unsigned char ctrlmask; -    unsigned int counter; - -    if (Bits == 8) { -	busymask = 0x80; -    } else { -	/* Since in 4-Bit mode DB0 on the parport is mapped to DB4 on the LCD -	 * (and consequently, DB3 on the partport is mapped to DB7 on the LCD) -	 * we need to listen for DB3 on the parport to go low -	 */ -	busymask = 0x08; -    } - -    ctrlmask = 0x08; -    while (ctrlmask > 0) { - -	if (controller & ctrlmask) { - -	    enable = 0; -	    if (ctrlmask & 0x01) -		enable = SIGNAL_ENABLE; -	    else if (ctrlmask & 0x02) -		enable = SIGNAL_ENABLE2; -	    else if (ctrlmask & 0x04) -		enable = SIGNAL_ENABLE3; -	    else if (ctrlmask & 0x08) -		enable = SIGNAL_ENABLE4; - -	    /* set data-lines to input */ -	    drv_generic_parport_direction(1); - -	    if (Bits == 8) { -		/* Set RW, clear RS */ -		drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RW); -	    } else { -		drv_generic_parport_data(SIGNAL_RW); -	    } - -	    /* Address set-up time */ -	    ndelay(T_AS); - -	    /* rise ENABLE */ -	    if (Bits == 8) { -		drv_generic_parport_control(enable, enable); -	    } else { -		drv_generic_parport_data(SIGNAL_RW | enable); -	    } - -	    counter = 0; -	    while (1) { -		/* read the busy flag */ -		data = drv_generic_parport_read(); -		if ((data & busymask) == 0) { -		    errors = 0; -		    break; -		} - -		/* make sure we don't wait forever -		 * - but only check after 5 iterations -		 * that way, we won't slow down normal mode -		 * (where we don't need the timeout anyway)  -		 */ -		counter++; - -		if (counter >= 5) { -		    struct timeval now, end; - -		    if (counter == 5) { -			/* determine the time when the timeout has expired */ -			gettimeofday(&end, NULL); -			end.tv_usec += MAX_BUSYFLAG_WAIT; -			while (end.tv_usec > 1000000) { -			    end.tv_usec -= 1000000; -			    end.tv_sec++; -			} -		    } - -		    /* get the current time */ -		    gettimeofday(&now, NULL); -		    if (now.tv_sec == end.tv_sec ? now.tv_usec >= end.tv_usec : now.tv_sec >= end.tv_sec) { -			error("%s: timeout waiting for busy flag on controller %x (%x)", Name, ctrlmask, data); -			if (++errors >= MAX_BUSYFLAG_ERRORS) { -			    error("%s: too many busy flag failures, turning off busy flag checking.", Name); -			    UseBusy = 0; -			} -			break; -		    } -		} -	    } - -	    /* RS=low, RW=low, EN=low */ -	    if (Bits == 8) { -		/* Lower EN */ -		drv_generic_parport_control(enable, 0); - -		/* Address hold time */ -		ndelay(T_AH); - -		drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, 0); -	    } else { -		/* Lower EN */ -		drv_generic_parport_data(SIGNAL_RW); -		ndelay(T_AH); -		drv_generic_parport_data(0); -	    } - -	    /* set data-lines to output */ -	    drv_generic_parport_direction(0); -	} -	ctrlmask >>= 1; -    } -} - - -static void drv_HD_PP_nibble(const unsigned char controller, const unsigned char nibble) -{ -    unsigned char enable; - -    /* enable signal: 'controller' is a bitmask */ -    /* bit n .. send to controller #n */ -    /* so we can send a byte to more controllers at the same time! */ -    enable = 0; -    if (controller & 0x01) -	enable |= SIGNAL_ENABLE; -    if (controller & 0x02) -	enable |= SIGNAL_ENABLE2; -    if (controller & 0x04) -	enable |= SIGNAL_ENABLE3; -    if (controller & 0x08) -	enable |= SIGNAL_ENABLE4; - -    /* clear ENABLE */ -    /* put data on DB1..DB4 */ -    /* nibble already contains RS bit! */ -    drv_generic_parport_data(nibble); - -    /* Address set-up time */ -    ndelay(T_AS); - -    /* rise ENABLE */ -    drv_generic_parport_data(nibble | enable); - -    /* Enable pulse width */ -    ndelay(T_PW); - -    /* lower ENABLE */ -    drv_generic_parport_data(nibble); -} - - -static void drv_HD_PP_byte(const unsigned char controller, const unsigned char data, const unsigned char RS) -{ -    /* send high nibble of the data */ -    drv_HD_PP_nibble(controller, ((data >> 4) & 0x0f) | RS); - -    /* Make sure we honour T_CYCLE */ -    ndelay(T_CYCLE - T_AS - T_PW); - -    /* send low nibble of the data */ -    drv_HD_PP_nibble(controller, (data & 0x0f) | RS); -} - - -static void drv_HD_PP_command(const unsigned char controller, const unsigned char cmd, const int delay) -{ -    unsigned char enable; - -    if (UseBusy) -	drv_HD_PP_busy(controller); - -    if (Bits == 8) { - -	/* enable signal: 'controller' is a bitmask */ -	/* bit n .. send to controller #n */ -	/* so we can send a byte to more controllers at the same time! */ -	enable = 0; -	if (controller & 0x01) -	    enable |= SIGNAL_ENABLE; -	if (controller & 0x02) -	    enable |= SIGNAL_ENABLE2; -	if (controller & 0x04) -	    enable |= SIGNAL_ENABLE3; -	if (controller & 0x08) -	    enable |= SIGNAL_ENABLE4; - -	/* put data on DB1..DB8 */ -	drv_generic_parport_data(cmd); - -	/* clear RW and RS */ -	drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, 0); - -	/* Address set-up time */ -	ndelay(T_AS); - -	/* send command */ -	drv_generic_parport_toggle(enable, 1, T_PW); - -    } else { - -	drv_HD_PP_byte(controller, cmd, 0); - -    } - -    /* wait for command completion */ -    if (!UseBusy) -	udelay(delay); - -} - - -static void drv_HD_PP_data(const unsigned char controller, const char *string, const int len, const int delay) -{ -    int l = len; -    unsigned char enable; - -    /* sanity check */ -    if (len <= 0) -	return; - -    if (Bits == 8) { - -	/* enable signal: 'controller' is a bitmask */ -	/* bit n .. send to controller #n */ -	/* so we can send a byte to more controllers at the same time! */ -	enable = 0; -	if (controller & 0x01) -	    enable |= SIGNAL_ENABLE; -	if (controller & 0x02) -	    enable |= SIGNAL_ENABLE2; -	if (controller & 0x04) -	    enable |= SIGNAL_ENABLE3; -	if (controller & 0x08) -	    enable |= SIGNAL_ENABLE4; - -	if (!UseBusy) { -	    /* clear RW, set RS */ -	    drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RS); -	    /* Address set-up time */ -	    ndelay(T_AS); -	} - -	while (l--) { - -	    if (UseBusy) { -		drv_HD_PP_busy(controller); -		/* clear RW, set RS */ -		drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RS); -		/* Address set-up time */ -		ndelay(T_AS); -	    } - -	    /* put data on DB1..DB8 */ -	    drv_generic_parport_data(*(string++)); - -	    /* send command */ -	    drv_generic_parport_toggle(enable, 1, T_PW); - -	    /* wait for command completion */ -	    if (!UseBusy) -		udelay(delay); -	} - -    } else {			/* 4 bit mode */ - -	while (l--) { -	    if (UseBusy) -		drv_HD_PP_busy(controller); - -	    /* send data with RS enabled */ -	    drv_HD_PP_byte(controller, *(string++), SIGNAL_RS); - -	    /* wait for command completion */ -	    if (!UseBusy) -		udelay(delay); -	} -    } -} - - -static int drv_HD_PP_load(const char *section) -{ -    if (cfg_number(section, "Bits", 8, 4, 8, &Bits) < 0) -	return -1; - -    if (Bits != 4 && Bits != 8) { -	error("%s: bad %s.Bits '%d' from %s, should be '4' or '8'", Name, section, Bits, cfg_source()); -	return -1; -    } - -    /* LCM-162 only supports 8-bit-mode */ -    if (Capabilities & CAP_LCM162 && Bits != 8) { -	error("%s: Model '%s' does not support %d bit mode!", Name, Models[Model].name, Bits); -	Bits = 8; -    } -    info("%s: using %d bit mode", Name, Bits); - -    if (drv_generic_parport_open(section, Name) != 0) { -	error("%s: could not initialize parallel port!", Name); -	return -1; -    } - -    /* Soft-Wiring */ -    if (Capabilities & CAP_LCM162) { -	/* the LCM-162 is hardwired */ -	if ((SIGNAL_RS = drv_generic_parport_hardwire_ctrl("RS", "SLCTIN")) == 0xff) -	    return -1; -	if ((SIGNAL_RW = drv_generic_parport_hardwire_ctrl("RW", "INIT")) == 0xff) -	    return -1; -	if ((SIGNAL_ENABLE = drv_generic_parport_hardwire_ctrl("ENABLE", "AUTOFD")) == 0xff) -	    return -1; -	if ((SIGNAL_ENABLE2 = drv_generic_parport_hardwire_ctrl("ENABLE2", "GND")) == 0xff) -	    return -1; -	if ((SIGNAL_ENABLE3 = drv_generic_parport_hardwire_ctrl("ENABLE3", "GND")) == 0xff) -	    return -1; -	if ((SIGNAL_ENABLE4 = drv_generic_parport_hardwire_ctrl("ENABLE4", "GND")) == 0xff) -	    return -1; -	if ((SIGNAL_BACKLIGHT = drv_generic_parport_hardwire_ctrl("BACKLIGHT", "GND")) == 0xff) -	    return -1; -	if ((SIGNAL_GPO = drv_generic_parport_hardwire_ctrl("GPO", "GND")) == 0xff) -	    return -1; -    } else { -	if (Bits == 8) { -	    if ((SIGNAL_RS = drv_generic_parport_wire_ctrl("RS", "AUTOFD")) == 0xff) -		return -1; -	    if ((SIGNAL_RW = drv_generic_parport_wire_ctrl("RW", "GND")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE = drv_generic_parport_wire_ctrl("ENABLE", "STROBE")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_ctrl("ENABLE2", "GND")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE3 = drv_generic_parport_wire_ctrl("ENABLE3", "GND")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE4 = drv_generic_parport_wire_ctrl("ENABLE4", "GND")) == 0xff) -		return -1; -	} else { -	    if ((SIGNAL_RS = drv_generic_parport_wire_data("RS", "DB4")) == 0xff) -		return -1; -	    if ((SIGNAL_RW = drv_generic_parport_wire_data("RW", "DB5")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE = drv_generic_parport_wire_data("ENABLE", "DB6")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_data("ENABLE2", "GND")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE3 = drv_generic_parport_wire_data("ENABLE3", "GND")) == 0xff) -		return -1; -	    if ((SIGNAL_ENABLE4 = drv_generic_parport_wire_data("ENABLE4", "GND")) == 0xff) -		return -1; -	} -	/* backlight and GPO are always control signals */ -	if ((SIGNAL_BACKLIGHT = drv_generic_parport_wire_ctrl("BACKLIGHT", "GND")) == 0xff) -	    return -1; -	if ((SIGNAL_GPO = drv_generic_parport_wire_ctrl("GPO", "GND")) == 0xff) -	    return -1; -    } - -    /* clear capabilities if corresponding signal is GND */ -    if (SIGNAL_BACKLIGHT == 0) { -	Capabilities &= ~CAP_BACKLIGHT; -    } -    if (SIGNAL_GPO == 0) { -	Capabilities &= ~CAP_GPO; -    } - - -    /* clear all signals */ -    if (Bits == 8) { -	drv_generic_parport_control(SIGNAL_RS | -				    SIGNAL_RW | SIGNAL_ENABLE | SIGNAL_ENABLE2 | SIGNAL_ENABLE3 | SIGNAL_ENABLE4 | SIGNAL_BACKLIGHT | SIGNAL_GPO, 0); -    } else { -	drv_generic_parport_data(0); -    } - -    /* set direction: write */ -    drv_generic_parport_direction(0); - -    /* initialize *all* controllers */ -    if (Bits == 8) { -	drv_HD_PP_command(allControllers, 0x30, T_INIT1);	/* 8 Bit mode, wait 4.1 ms */ -	drv_HD_PP_command(allControllers, 0x30, T_INIT2);	/* 8 Bit mode, wait 100 us */ -	drv_HD_PP_command(allControllers, 0x38, T_EXEC);	/* 8 Bit mode, 1/16 duty cycle, 5x8 font */ -    } else { -	drv_HD_PP_nibble(allControllers, 0x03); -	udelay(T_INIT1);	/* 4 Bit mode, wait 4.1 ms */ -	drv_HD_PP_nibble(allControllers, 0x03); -	udelay(T_INIT2);	/* 4 Bit mode, wait 100 us */ -	drv_HD_PP_nibble(allControllers, 0x03); -	udelay(T_INIT1);	/* 4 Bit mode, wait 4.1 ms */ -	drv_HD_PP_nibble(allControllers, 0x02); -	udelay(T_INIT2);	/* 4 Bit mode, wait 100 us */ -	drv_HD_PP_command(allControllers, 0x28, T_EXEC);	/* 4 Bit mode, 1/16 duty cycle, 5x8 font */ -    } - -    /* maybe use busy-flag from now on  */ -    /* (we can't use the busy flag during the init sequence) */ -    cfg_number(section, "UseBusy", 0, 0, 1, &UseBusy); - -    /* make sure we don't use the busy flag with RW wired to GND */ -    if (UseBusy && !SIGNAL_RW) { -	error("%s: busy-flag checking is impossible with RW wired to GND!", Name); -	UseBusy = 0; -    } - -    /* make sure the display supports busy-flag checking in 4-Bit-Mode */ -    /* at the moment this is inly possible with Martin Hejl's gpio driver, */ -    /* which allows to use 4 bits as input and 4 bits as output */ -    if (UseBusy && Bits == 4 && !(Capabilities & CAP_BUSY4BIT)) { -	error("%s: Model '%s' does not support busy-flag checking in 4 bit mode", Name, Models[Model].name); -	UseBusy = 0; -    } - -    info("%s: %susing busy-flag checking", Name, UseBusy ? "" : "not "); - -    /* The LCM-162 should really use BusyFlag checking */ -    if (!UseBusy && (Capabilities & CAP_LCM162)) { -	error("%s: Model '%s' should definitely use busy-flag checking!", Name, Models[Model].name); -    } - -    return 0; -} - - -static void drv_HD_PP_stop(void) -{ -    /* clear all signals */ -    if (Bits == 8) { -	drv_generic_parport_control(SIGNAL_RS | -				    SIGNAL_RW | SIGNAL_ENABLE | SIGNAL_ENABLE2 | SIGNAL_ENABLE3 | SIGNAL_ENABLE4 | SIGNAL_BACKLIGHT | SIGNAL_GPO, 0); -    } else { -	drv_generic_parport_data(0); -    } - -    drv_generic_parport_close(); - -} - - - -/****************************************/ -/***  i2c dependant functions         ***/ -/****************************************/ - -#ifdef WITH_I2C - -static void drv_HD_I2C_nibble(unsigned char controller, unsigned char nibble) -{ -    unsigned char enable; - -    /* enable signal: 'controller' is a bitmask */ -    /* bit n .. send to controller #n */ -    /* so we can send a byte to more controllers at the same time! */ -    enable = 0; -    if (controller & 0x01) -	enable |= SIGNAL_ENABLE; -    if (controller & 0x02) -	enable |= SIGNAL_ENABLE2; -    if (controller & 0x04) -	enable |= SIGNAL_ENABLE3; -    if (controller & 0x08) -	enable |= SIGNAL_ENABLE4; - - -    /* clear ENABLE */ -    /* put data on DB1..DB4 */ -    /* nibble already contains RS bit! */ -    drv_generic_i2c_data(nibble); - -    /* Address set-up time */ -    ndelay(T_AS); - -    /* rise ENABLE */ -    drv_generic_i2c_data(nibble | enable); - -    /* Enable pulse width */ -    ndelay(T_PW); - -    /* lower ENABLE */ -    drv_generic_i2c_data(nibble); - -    /* Address hold time */ -    ndelay(T_H); -} - - -static void drv_HD_I2C_byte(const unsigned char controller, const unsigned char data) -{ -    /* send data with RS disabled */ -    /* send high nibble of the data */ -    drv_HD_I2C_nibble(controller, ((data >> 4) & 0x0f) | SIGNAL_RS); - -    /* Make sure we honour T_CYCLE */ -    ndelay(T_CYCLE - T_AS - T_PW); - -    /* send low nibble of the data */ -    drv_HD_I2C_nibble(controller, (data & 0x0f) | SIGNAL_RS); -} - - -static void drv_HD_I2C_command(const unsigned char controller, const unsigned char cmd, const int delay) -{ -    /* send data with RS disabled */ -    drv_HD_I2C_nibble(controller, ((cmd >> 4) & 0x0f)); - -    ndelay(T_CYCLE - T_AS - T_PW); - -    drv_HD_I2C_nibble(controller, ((cmd) & 0x0f)); - -    /* wait for command completion */ -    udelay(delay); -} - -static void drv_HD_I2C_data(const unsigned char controller, const char *string, const int len, const int delay) -{ -    int l = len; - -    /* sanity check */ -    if (len <= 0) -	return; - -    while (l--) { -	/* send data with RS enabled */ -	drv_HD_I2C_byte(controller, *(string++)); - -	/* wait for command completion */ -	udelay(delay); -    } -} - - -static int drv_HD_I2C_load(const char *section) -{ -    if (cfg_number(section, "Bits", 8, 4, 8, &Bits) < 0) -	return -1; -    if (Bits != 4) { -	error("%s: bad %s.Bits '%d' from %s, should be '4'", Name, section, Bits, cfg_source()); -	return -1; -    } - -    info("%s: using %d bit mode", Name, Bits); - -    if (drv_generic_i2c_open(section, Name) != 0) { -	error("%s: could not initialize i2c attached device!", Name); -	return -1; -    } - -    if ((SIGNAL_RS = drv_generic_i2c_wire("RS", "DB4")) == 0xff) -	return -1; -    if ((SIGNAL_RW = drv_generic_i2c_wire("RW", "DB5")) == 0xff) -	return -1; -    if ((SIGNAL_ENABLE = drv_generic_i2c_wire("ENABLE", "DB6")) == 0xff) -	return -1; -    if ((SIGNAL_ENABLE2 = drv_generic_i2c_wire("ENABLE2", "GND")) == 0xff) -	return -1; -    if ((SIGNAL_GPO = drv_generic_i2c_wire("GPO", "GND")) == 0xff) -	return -1; - -    /* initialize display */ -    drv_HD_I2C_nibble(allControllers, 0x03); -    udelay(T_INIT1);		/* 4 Bit mode, wait 4.1 ms */ -    drv_HD_I2C_nibble(allControllers, 0x03); -    udelay(T_INIT2);		/* 4 Bit mode, wait 100 us */ -    drv_HD_I2C_nibble(allControllers, 0x03); -    udelay(T_INIT2);		/* 4 Bit mode, wait 4.1 ms */ -    drv_HD_I2C_nibble(allControllers, 0x02); -    udelay(T_INIT2);		/* 4 Bit mode, wait 100 us */ -    drv_HD_I2C_command(allControllers, 0x28, T_EXEC);	/* 4 Bit mode, 1/16 duty cycle, 5x8 font */ - -    info("%s: I2C initialization done", Name); - -    return 0; -} - - -static void drv_HD_I2C_stop(void) -{ -    /* clear all signals */ -    drv_generic_i2c_data(0); - -    /* close port */ -    drv_generic_i2c_close(); -} - -#endif				/* WITH_I2C */ - - -/****************************************/ -/***  display dependant functions     ***/ -/****************************************/ - -static void drv_HD_clear(void) -{ -    drv_HD_command(allControllers, 0x01, T_CLEAR);	/* clear *all* displays */ -} - - -static int drv_HD_goto(int row, int col) -{ -    int pos, controller; - -    /* handle multiple controllers */ -    for (pos = 0, controller = 0; controller < numControllers; controller++) { -	pos += CROWS[controller]; -	if (row < pos) { -	    currController = (1 << controller); -	    break; -	} -	row -= CROWS[controller]; -    } - -    /* column outside of current display's width */ -    if (col >= CCOLS[controller]) -	return -1; - -    if (0) { -	debug("goto: [%d,%d] mask=%d, controller=%d, size:%dx%d", row, col, currController, controller, CROWS[controller], CCOLS[controller]); -    } - -    /* 16x1 Displays are organized as 8x2 :-( */ -    if (CCOLS[controller] == 16 && CROWS[controller] == 1 && col > 7) { -	row++; -	col -= 8; -    } - -    if (Capabilities & CAP_HD66712) { -	/* the HD66712 doesn't have a braindamadged RAM layout */ -	pos = row * 32 + col; -    } else { -	/* 16x4 Controllers use a slightly different layout */ -	if (CCOLS[controller] == 16 && CROWS[controller] == 4) { -	    pos = (row % 2) * 64 + (row / 2) * 16 + col; -	} else { -	    pos = (row % 2) * 64 + (row / 2) * 20 + col; -	} -    } -    drv_HD_command(currController, (0x80 | pos), T_EXEC); - -    /* return columns left on current display */ -    return CCOLS[controller] - col; - -} - - -static void drv_HD_write(const int row, const int col, const char *data, const int len) -{ -    int space = drv_HD_goto(row, col); -    if (space > 0) { -	drv_HD_data(currController, data, len > space ? space : len, T_EXEC); -    } -} - - -static void drv_HD_defchar(const int ascii, const unsigned char *matrix) -{ -    int i; -    char buffer[8]; - -    for (i = 0; i < 8; i++) { -	buffer[i] = matrix[i] & 0x1f; -    } - -    /* define chars on *all* controllers! */ -    drv_HD_command(allControllers, 0x40 | 8 * ascii, T_EXEC); -    drv_HD_data(allControllers, buffer, 8, T_WRCG); -} - - -static int drv_HD_backlight(int backlight) -{ -    if (!(Capabilities & CAP_BACKLIGHT)) -	return -1; - -    if (backlight < 0) -	backlight = 0; -    if (backlight > 1) -	backlight = 1; - -    drv_generic_parport_control(SIGNAL_BACKLIGHT, backlight ? SIGNAL_BACKLIGHT : 0); - -    return backlight; -} - - -static int drv_HD_brightness(int brightness) -{ -    char cmd; - -    if (!(Capabilities & CAP_BRIGHTNESS)) -	return -1; - -    if (brightness < 0) -	brightness = 0; -    if (brightness > 3) -	brightness = 3; - -    cmd = '0' + brightness; - -    drv_HD_command(allControllers, 0x38, T_EXEC);	/* enable function */ -    drv_HD_data(allControllers, &cmd, 1, T_WRCG);	/* set brightness */ - -    return brightness; -} - - -/* Fixme: GPO's */ -#if 0 -static void drv_HD_setGPO(const int bits) -{ -    if (Lcd.gpos > 0) { - -	/* put data on DB1..DB8 */ -	drv_generic_parport_data(bits); - -	/* 74HCT573 set-up time */ -	ndelay(20); - -	/* send data */ -	/* 74HCT573 enable pulse width = 24ns */ -	drv_generic_parport_toggle(SIGNAL_GPO, 1, 230); -    } -} -#endif - - -static void drv_HD_LCM162_timer(void __attribute__ ((unused)) * notused) -{ -    static unsigned char data = 0x00; - -    /* Bit 3+5 : key number */ -    /* Bit 6   : key press/release */ -    unsigned char mask3 = 1 << 3; -    unsigned char mask5 = 1 << 5; -    unsigned char mask6 = 1 << 6; -    unsigned char mask = mask3 | mask5 | mask6; - -    int keynum; -    int updown; - -    unsigned char temp; - -    temp = drv_generic_parport_status() & mask; - -    if (data != temp) { -	data = temp; - -	keynum = (data & mask3 ? 1 : 0) + (data & mask5 ? 2 : 0); -	updown = (data & mask6 ? 1 : 0); - -	debug("key %d press %d", keynum, updown); -    } -} - - -static int drv_HD_start(const char *section, const int quiet) -{ -    char *model, *size, *bus; -    int rows = -1, cols = -1, gpos = -1, i; -    int size_defined = 0; -    int size_missing = 0; - -    model = cfg_get(section, "Model", "generic"); -    if (model != NULL && *model != '\0') { -	int i; -	for (i = 0; Models[i].type != 0xff; i++) { -	    if (strcasecmp(Models[i].name, model) == 0) -		break; -	} -	if (Models[i].type == 0xff) { -	    error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source()); -	    return -1; -	} -	Model = i; -	Capabilities = Models[Model].capabilities; -	info("%s: using model '%s'", Name, Models[Model].name); -    } else { -	error("%s: empty '%s.Model' entry from %s", Name, section, cfg_source()); -	if (model) -	    free(model); -	return -1; -    } -    free(model); - -    bus = cfg_get(section, "Bus", "parport"); -    if (bus == NULL && *bus == '\0') { -	error("%s: empty '%s.Bus' entry from %s", Name, section, cfg_source()); -	if (bus) -	    free(bus); -	return -1; -    } - -    if (strcasecmp(bus, "parport") == 0) { -	info("%s: using parallel port", Name); -	Bus = BUS_PP; -	drv_HD_load = drv_HD_PP_load; -	drv_HD_command = drv_HD_PP_command; -	drv_HD_data = drv_HD_PP_data; -	drv_HD_stop = drv_HD_PP_stop; - -    } else if (strcasecmp(bus, "i2c") == 0) { -#ifdef WITH_I2C -	info("%s: using I2C bus", Name); -	Bus = BUS_I2C; -	drv_HD_load = drv_HD_I2C_load; -	drv_HD_command = drv_HD_I2C_command; -	drv_HD_data = drv_HD_I2C_data; -	drv_HD_stop = drv_HD_I2C_stop; -#else -	error("%s: %s.Bus '%s' from %s not available:", Name, section, bus, cfg_source()); -	error("%s: lcd4linux was compiled without i2c support!", Name); -	free(bus); -	return -1; -#endif - -    } else { -	error("%s: bad %s.Bus '%s' from %s, should be 'parport' or 'i2c'", Name, section, bus, cfg_source()); -	free(bus); -	return -1; -    } - -    /* sanity check: Model can use bus */ -    if (!(Capabilities & Bus)) { -	error("%s: Model '%s' cannot be used on the %s bus!", Name, Models[Model].name, bus); -	free(bus); -	return -1; -    } -    free(bus); - -    if (cfg_number(section, "Controllers", 1, 1, 4, (int *) &numControllers) < 0) -	return -1; -    info("%s: using %d Controller(s)", Name, numControllers); - -    /* current Controller */ -    currController = 1; - -    /* Bitmask for *all* Controllers */ -    allControllers = (1 << numControllers) - 1; - - -    DCOLS = 0; -    DROWS = 0; - -    for (i = 0; i < numControllers; i++) { -	char key[6]; -	qprintf(key, sizeof(key), "Size%d", i + 1); -	size = cfg_get(section, key, NULL); -	if (size == NULL || *size == '\0') { -	    size_missing++; -	    free(size); -	    continue; -	} -	if (sscanf(size, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) { -	    error("%s: bad %s.%s '%s' from %s", Name, section, key, size, cfg_source()); -	    free(size); -	    return -1; -	} -	free(size); -	CCOLS[i] = cols; -	CROWS[i] = rows; -	size_defined++; -	info("%s: Controller %d: %dx%d", Name, i + 1, cols, rows); -	/* grow the size */ -	if (cols > DCOLS) -	    DCOLS = cols; -	DROWS += rows; -    } -    if (size_defined && size_missing) { -	error("%s: bad %s.Size* definition in %s:", Name, section, cfg_source()); -	error("%s: either you specify the size for *all* controllers or for none.", Name); -	return -1; -    } - -    size = cfg_get(section, "Size", NULL); -    if (size != NULL && *size != '\0') { -	if (sscanf(size, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) { -	    error("%s: bad %s.Size '%s' from %s", Name, section, size, cfg_source()); -	    free(size); -	    return -1; -	} -	if (DCOLS == 0 && DROWS == 0) { -	    for (i = 0; i < numControllers; i++) { -		CCOLS[i] = cols; -		CROWS[i] = rows / numControllers; -		DCOLS = CCOLS[i]; -		DROWS += CROWS[i]; -	    } -	} -	if (rows != DROWS || cols != DCOLS) { -	    error("%s: bad %s.Size definition in %s:", Name, section, cfg_source()); -	    error("%s: Size %dx%d should be %dx%d", Name, cols, rows, DCOLS, DROWS); -	    return -1; -	} -    } -    free(size); - - -    if (cfg_number(section, "GPOs", 0, 0, 8, &gpos) < 0) -	return -1; -    if (gpos > 0 && !(Capabilities & CAP_GPO)) { -	error("%s: Model '%s' does not support GPO's!", Name, Models[Model].name); -	gpos = 0; -    } -    GPOS = gpos; -    if (gpos > 0) { -	info("%s: using %d GPO's", Name, GPOS); -    } - -    if (drv_HD_load(section) < 0) { -	error("%s: start display failed!", Name); -	return -1; -    } - -    drv_HD_command(allControllers, 0x08, T_EXEC);	/* Controller off, cursor off, blink off */ -    drv_HD_command(allControllers, 0x0c, T_CLEAR);	/* Display on, cursor off, blink off, wait 1.64 ms */ -    drv_HD_command(allControllers, 0x06, T_EXEC);	/* curser moves to right, no shift */ - -    if ((Capabilities & CAP_HD66712) && DROWS > 2) { -	drv_HD_command(allControllers, Bits == 8 ? 0x3c : 0x2c, T_EXEC);	/* set extended register enable bit */ -	drv_HD_command(allControllers, 0x09, T_EXEC);	/* set 4-line mode */ -	drv_HD_command(allControllers, Bits == 8 ? 0x38 : 0x28, T_EXEC);	/* clear extended register enable bit */ -    } - -    drv_HD_clear();		/* clear *all* displays */ -    drv_HD_command(allControllers, 0x03, T_CLEAR);	/* return home */ - -    /* maybe set backlight */ -    if (Capabilities & CAP_BACKLIGHT) { -	int backlight; -	if (cfg_number(section, "Backlight", 0, 0, 1, &backlight) > 0) { -	    info("%s: backlight %s", Name, backlight ? "enabled" : "disabled"); -	    drv_HD_backlight(backlight); -	} -    } - -    /* maybe set brightness */ -    if (Capabilities & CAP_BRIGHTNESS) { -	int brightness; -	if (cfg_number(section, "Brightness", 0, 0, 3, &brightness) > 0) { -	    info("%s: brightness level %d", Name, brightness); -	    drv_HD_brightness(brightness); -	} -    } - -    /* install keypad polling timer for LCM-162 */ -    if (Capabilities & CAP_LCM162) { -	timer_add(drv_HD_LCM162_timer, NULL, 10, 0); -    } - -    if (!quiet) { -	char buffer[40]; -	qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); -	if (drv_generic_text_greet(buffer, NULL)) { -	    sleep(3); -	    drv_HD_clear(); -	} -    } - -    return 0; -} - - -/****************************************/ -/***            plugins               ***/ -/****************************************/ - - -static void plugin_backlight(RESULT * result, RESULT * arg1) -{ -    double backlight; - -    backlight = drv_HD_backlight(R2N(arg1)); -    SetResult(&result, R_NUMBER, &backlight); -} - - -static void plugin_brightness(RESULT * result, RESULT * arg1) -{ -    double brightness; - -    brightness = drv_HD_brightness(R2N(arg1)); -    SetResult(&result, R_NUMBER, &brightness); -} - - -/****************************************/ -/***        widget callbacks          ***/ -/****************************************/ - - -/* using drv_generic_text_draw(W) */ -/* using drv_generic_text_icon_draw(W) */ -/* using drv_generic_text_bar_draw(W) */ - - -/****************************************/ -/***        exported functions        ***/ -/****************************************/ - - -/* list models */ -int drv_HD_list(void) -{ -    int i; - -    for (i = 0; Models[i].type != 0xff; i++) { -	printf("%s ", Models[i].name); -    } -    return 0; -} - - -/* initialize driver & display */ -int drv_HD_init(const char *section, const int quiet) -{ -    WIDGET_CLASS wc; -    int asc255bug; -    int ret; - -    /* display preferences */ -    XRES = 5;			/* pixel width of one char  */ -    YRES = 8;			/* pixel height of one char  */ -    CHARS = 8;			/* number of user-defineable characters */ -    CHAR0 = 0;			/* ASCII of first user-defineable char */ -    GOTO_COST = 1;		/* number of bytes a goto command requires */ - -    /* real worker functions */ -    drv_generic_text_real_write = drv_HD_write; -    drv_generic_text_real_defchar = drv_HD_defchar; - - -    /* start display */ -    if ((ret = drv_HD_start(section, quiet)) != 0) -	return ret; - -    /* initialize generic text driver */ -    if ((ret = drv_generic_text_init(section, Name)) != 0) -	return ret; - -    /* initialize generic icon driver */ -    if ((ret = drv_generic_text_icon_init()) != 0) -	return ret; - -    /* initialize generic bar driver */ -    if ((ret = drv_generic_text_bar_init(0)) != 0) -	return ret; - -    /* add fixed chars to the bar driver */ -    /* most displays have a full block on ascii 255, but some have kind of  */ -    /* an 'inverted P'. If you specify 'asc255bug 1 in the config, this */ -    /* char will not be used, but rendered by the bar driver */ -    cfg_number(section, "asc255bug", 0, 0, 1, &asc255bug); -    drv_generic_text_bar_add_segment(0, 0, 255, 32);	/* ASCII  32 = blank */ -    if (!asc255bug) -	drv_generic_text_bar_add_segment(255, 255, 255, 255);	/* ASCII 255 = block */ - -    /* register text widget */ -    wc = Widget_Text; -    wc.draw = drv_generic_text_draw; -    widget_register(&wc); - -    /* register icon widget */ -    wc = Widget_Icon; -    wc.draw = drv_generic_text_icon_draw; -    widget_register(&wc); - -    /* register bar widget */ -    wc = Widget_Bar; -    wc.draw = drv_generic_text_bar_draw; -    widget_register(&wc); - -    /* register plugins */ -    if (Capabilities & CAP_BACKLIGHT) { -	AddFunction("LCD::backlight", 1, plugin_backlight); -    } -    if (Capabilities & CAP_BRIGHTNESS) { -	AddFunction("LCD::brightness", 1, plugin_brightness); -    } - -    return 0; -} - - -/* close driver & display */ -int drv_HD_quit(const int quiet) -{ - -    info("%s: shutting down.", Name); - -    drv_generic_text_quit(); - -    /* clear display */ -    drv_HD_clear(); - -    /* say goodbye... */ -    if (!quiet) { -	drv_generic_text_greet("goodbye!", NULL); -    } - -    drv_HD_stop(); - -    return (0); -} - - -DRIVER drv_HD44780 = { -  name:Name, -  list:drv_HD_list, -  init:drv_HD_init, -  quit:drv_HD_quit, -}; + * Revision 1.50  2005/05/31 20:42:55  lfcorreia + * new file: lcd4linux_i2c.h + * avoid the problems detecting the proper I2C kernel include files + * + * rearrange all the other autoconf stuff to remove I2C detection + * + * new method by Paul Kamphuis to write to the I2C device + *
 + * Revision 1.49  2005/05/08 04:32:44  reinelt
 + * CodingStyle added and applied
 + *
 + * Revision 1.48  2005/05/05 08:36:12  reinelt
 + * changed SELECT to SLCTIN
 + *
 + * Revision 1.47  2005/03/28 22:29:23  reinelt
 + * HD44780 multiple displays patch from geronet
 + *
 + * Revision 1.46  2005/03/28 19:39:23  reinelt
 + * HD44780/I2C patch from Luis merged (still does not work for me)
 + *
 + * Revision 1.45  2005/03/25 15:44:43  reinelt
 + * HD44780 Backlight fixed (thanks to geronet)
 + *
 + * Revision 1.44  2005/01/29 09:30:56  reinelt
 + * minor HD44780 cleanups
 + *
 + * Revision 1.43  2005/01/18 06:30:23  reinelt
 + * added (C) to all copyright statements
 + *
 + * Revision 1.42  2005/01/17 06:38:48  reinelt
 + * info about backlight and brightness
 + *
 + * Revision 1.41  2005/01/17 06:29:24  reinelt
 + * added software-controlled backlight support to HD44780
 + *
 + * Revision 1.40  2004/11/30 05:01:25  reinelt
 + * removed compiler warnings for deactivated i2c bus
 + *
 + * Revision 1.39  2004/10/17 09:24:31  reinelt
 + * I2C support for HD44780 displays by Luis (does not work by now)
 + *
 + * Revision 1.38  2004/09/19 09:31:19  reinelt
 + * HD44780 busy flag checking improved: fall back to busy-waiting if too many errors occur
 + *
 + * Revision 1.37  2004/09/18 15:58:57  reinelt
 + * even more HD44780 cleanups, hardwiring for LCM-162
 + *
 + * Revision 1.36  2004/09/18 10:57:29  reinelt
 + * more parport/i2c cleanups
 + *
 + * Revision 1.35  2004/09/18 09:48:29  reinelt
 + * HD44780 cleanup and prepararation for I2C backend
 + * LCM-162 submodel framework
 + *
 + * Revision 1.34  2004/09/18 08:22:59  reinelt
 + * drv_generic_parport_status() to read status lines
 + *
 + * Revision 1.33  2004/08/29 13:03:41  reinelt
 + *
 + * added RouterBoard driver
 + *
 + * Revision 1.32  2004/06/26 12:04:59  reinelt
 + *
 + * uh-oh... the last CVS log message messed up things a lot...
 + *
 + * Revision 1.31  2004/06/26 09:27:20  reinelt
 + *
 + * added '-W' to CFLAGS
 + * changed all C++ comments to C ones
 + * cleaned up a lot of signed/unsigned mistakes
 + *
 + * Revision 1.30  2004/06/20 10:09:54  reinelt
 + *
 + * 'const'ified the whole source
 + *
 + * Revision 1.29  2004/06/06 06:51:59  reinelt
 + *
 + * do not display end splash screen if quiet=1
 + *
 + * Revision 1.28  2004/06/05 06:41:39  reinelt
 + *
 + * chancged splash screen again
 + *
 + * Revision 1.27  2004/06/05 06:13:11  reinelt
 + *
 + * splash screen for all text-based display drivers
 + *
 + * Revision 1.26  2004/06/02 10:09:22  reinelt
 + *
 + * splash screen for HD44780
 + *
 + * Revision 1.25  2004/06/02 09:41:19  reinelt
 + *
 + * prepared support for startup splash screen
 + *
 + * Revision 1.24  2004/06/01 06:45:29  reinelt
 + *
 + * some Fixme's processed
 + * documented some code
 + *
 + * Revision 1.23  2004/05/31 05:38:02  reinelt
 + *
 + * fixed possible bugs with user-defined chars (clear high bits)
 + * thanks to Andy Baxter for debugging the MilfordInstruments driver!
 + *
 + * Revision 1.22  2004/05/27 03:39:47  reinelt
 + *
 + * changed function naming scheme to plugin::function
 + *
 + * Revision 1.21  2004/05/26 11:37:36  reinelt
 + *
 + * Curses driver ported.
 + *
 + * Revision 1.20  2004/05/22 04:23:49  reinelt
 + *
 + * removed 16*x fix again (next time think before commit :-)
 + *
 + * Revision 1.19  2004/05/22 04:21:02  reinelt
 + *
 + * fix for display RAM layout on 16x4 displays (thanks to toxicated101)
 + *
 + * Revision 1.18  2004/03/20 07:31:32  reinelt
 + * support for HD66712 (which has a different RAM layout)
 + * further threading development
 + *
 + * Revision 1.17  2004/03/19 09:17:46  reinelt
 + *
 + * removed the extra 'goto' function, row and col are additional parameters
 + * of the write() function now.
 + *
 + * Revision 1.16  2004/03/11 06:39:58  reinelt
 + * big patch from Martin:
 + * - reuse filehandles
 + * - memory leaks fixed
 + * - earlier busy-flag checking with HD44780
 + * - reuse memory for strings in RESULT and hash
 + * - netdev_fast to wavid time-consuming regex
 + *
 + * Revision 1.15  2004/03/03 03:47:04  reinelt
 + * big patch from Martin Hejl:
 + * - use qprintf() where appropriate
 + * - save CPU cycles on gettimeofday()
 + * - add quit() functions to free allocated memory
 + * - fixed lots of memory leaks
 + *
 + * Revision 1.14  2004/03/01 04:29:51  reinelt
 + * cfg_number() returns -1 on error, 0 if value not found (but default val used),
 + *  and 1 if value was used from the configuration.
 + * HD44780 driver adopted to new cfg_number()
 + * Crystalfontz 631 driver nearly finished
 + *
 + * Revision 1.13  2004/02/15 21:43:43  reinelt
 + * T6963 driver nearly finished
 + * framework for graphic displays done
 + * i2c_sensors patch from Xavier
 + * some more old generation files removed
 + *
 + * Revision 1.12  2004/02/14 11:56:17  reinelt
 + * M50530 driver ported
 + * changed lots of 'char' to 'unsigned char'
 + *
 + * Revision 1.11  2004/02/04 19:10:51  reinelt
 + * Crystalfontz driver nearly finished
 + *
 + * Revision 1.10  2004/02/02 05:22:16  reinelt
 + * Brightness fpr Noritake Displays avaliable as a plugin
 + *
 + * Revision 1.9  2004/02/01 11:51:22  hejl
 + * Fixes for busy flag
 + *
 + * Revision 1.8  2004/02/01 08:05:12  reinelt
 + * Crystalfontz 633 extensions (CRC checking and stuff)
 + * Models table for HD44780
 + * Noritake VFD BVrightness patch from Bill Paxton
 + *
 + * Revision 1.7  2004/01/30 07:12:35  reinelt
 + * HD44780 busy-flag support from Martin Hejl
 + * loadavg() uClibc replacement from Martin Heyl
 + * round() uClibc replacement from Martin Hejl
 + * warning in i2c_sensors fixed
 + * [
 + *
 + * Revision 1.6  2004/01/29 04:40:02  reinelt
 + * every .c file includes "config.h" now
 + *
 + * Revision 1.5  2004/01/23 07:04:17  reinelt
 + * icons finished!
 + *
 + * Revision 1.4  2004/01/23 04:53:48  reinelt
 + * icon widget added (not finished yet!)
 + *
 + * Revision 1.3  2004/01/22 07:57:45  reinelt
 + * several bugs fixed where segfaulting on layout>display
 + * Crystalfontz driver optimized, 632 display already works
 + *
 + * Revision 1.2  2004/01/21 06:39:27  reinelt
 + * HD44780 missed the "clear display' sequence
 + * asc255bug handling added
 + * HD44780 tested, works here!
 + *
 + * Revision 1.1  2004/01/20 15:32:49  reinelt
 + * first version of Next Generation HD44780 (untested! but it compiles...)
 + * some cleanup in the other drivers
 + *
 + */
 +
 +/* 
 + *
 + * exported fuctions:
 + *
 + * struct DRIVER drv_HD44780
 + *
 + */
 +
 +#include "config.h"
 +
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <errno.h>
 +#include <unistd.h>
 +#include <termios.h>
 +#include <fcntl.h>
 +#include <sys/time.h>
 +#include <sys/ioctl.h>
 +
 +#include "debug.h"
 +#include "cfg.h"
 +#include "udelay.h"
 +#include "qprintf.h"
 +#include "timer.h"
 +#include "plugin.h"
 +#include "widget.h"
 +#include "widget_text.h"
 +#include "widget_icon.h"
 +#include "widget_bar.h"
 +#include "drv.h"
 +#include "drv_generic_text.h"
 +#include "drv_generic_parport.h"
 +
 +#ifdef WITH_I2C
 +#include "drv_generic_i2c.h"
 +#endif
 +
 +static char Name[] = "HD44780";
 +
 +static int Bus;
 +static int Model;
 +static int Capabilities;
 +
 +
 +/* low level communication timings [nanoseconds]
 + * as these values differ from spec to spec,
 + * we use the worst-case values.
 + */
 +
 +#define T_CYCLE 1000		/* Enable cycle time */
 +#define T_PW     450		/* Enable pulse width */
 +#define T_AS      60		/* Address setup time */
 +#define T_H       40		/* Data hold time */
 +#define T_AH      20		/* Address hold time */
 +
 +
 +/* HD44780 execution timings [microseconds]
 + * as these values differ from spec to spec,
 + * we use the worst-case values.
 + */
 +
 +#define T_INIT1 4100		/* first init sequence:  4.1 msec */
 +#define T_INIT2  100		/* second init sequence: 100 usec */
 +#define T_EXEC    80		/* normal execution time */
 +#define T_WRCG   120		/* CG RAM Write */
 +#define T_CLEAR 2250		/* Clear Display */
 +
 +
 +static int Bits = 0;
 +static int numControllers = 0;
 +static int allControllers = 0;
 +static int currController = 0;
 +
 +/* size of every single controller */
 +static int CROWS[4];
 +static int CCOLS[4];
 +
 +static unsigned char SIGNAL_RW;
 +static unsigned char SIGNAL_RS;
 +static unsigned char SIGNAL_ENABLE;
 +static unsigned char SIGNAL_ENABLE2;
 +static unsigned char SIGNAL_ENABLE3;
 +static unsigned char SIGNAL_ENABLE4;
 +static unsigned char SIGNAL_BACKLIGHT;
 +static unsigned char SIGNAL_GPO;
 +
 +/* maximum time to wait for the busy-flag (in usec) */
 +#define MAX_BUSYFLAG_WAIT 10000
 +
 +/* maximum busy flag errors before falling back to busy-waiting */
 +#define MAX_BUSYFLAG_ERRORS 20
 +
 +/* flag for busy-waiting vs. busy flag checking */
 +static int UseBusy = 0;
 +
 +
 +/* Fixme: GPO's not yet implemented */
 +static int GPOS;
 +/* static int GPO=0; */
 +
 +
 +typedef struct {
 +    int type;
 +    char *name;
 +    int capabilities;
 +} MODEL;
 +
 +#define CAP_PARPORT    (1<<0)
 +#define CAP_I2C        (1<<1)
 +#define CAP_GPO        (1<<2)
 +#define CAP_BACKLIGHT  (1<<3)
 +#define CAP_BRIGHTNESS (1<<4)
 +#define CAP_BUSY4BIT   (1<<5)
 +#define CAP_HD66712    (1<<6)
 +#define CAP_LCM162     (1<<7)
 +
 +#define BUS_PP  CAP_PARPORT
 +#define BUS_I2C CAP_I2C
 +
 +
 +static MODEL Models[] = {
 +    {0x01, "generic", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BACKLIGHT},
 +    {0x02, "Noritake", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BRIGHTNESS},
 +    {0x03, "Soekris", CAP_PARPORT | CAP_BUSY4BIT},
 +    {0x04, "HD66712", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BACKLIGHT | CAP_HD66712},
 +    {0x05, "LCM-162", CAP_PARPORT | CAP_LCM162},
 +    {0xff, "Unknown", 0}
 +};
 +
 +
 +/****************************************/
 +/***  generic functions               ***/
 +/****************************************/
 +
 +static int (*drv_HD_load) (const char *section);
 +static void (*drv_HD_command) (const unsigned char controller, const unsigned char cmd, const int delay);
 +static void (*drv_HD_data) (const unsigned char controller, const char *string, const int len, const int delay);
 +static void (*drv_HD_stop) (void);
 +
 +
 +
 +/****************************************/
 +/***  parport dependant functions     ***/
 +/****************************************/
 +
 +static void drv_HD_PP_busy(const int controller)
 +{
 +    static unsigned int errors = 0;
 +
 +    unsigned char enable;
 +    unsigned char data = 0xFF;
 +    unsigned char busymask;
 +    unsigned char ctrlmask;
 +    unsigned int counter;
 +
 +    if (Bits == 8) {
 +	busymask = 0x80;
 +    } else {
 +	/* Since in 4-Bit mode DB0 on the parport is mapped to DB4 on the LCD
 +	 * (and consequently, DB3 on the partport is mapped to DB7 on the LCD)
 +	 * we need to listen for DB3 on the parport to go low
 +	 */
 +	busymask = 0x08;
 +    }
 +
 +    ctrlmask = 0x08;
 +    while (ctrlmask > 0) {
 +
 +	if (controller & ctrlmask) {
 +
 +	    enable = 0;
 +	    if (ctrlmask & 0x01)
 +		enable = SIGNAL_ENABLE;
 +	    else if (ctrlmask & 0x02)
 +		enable = SIGNAL_ENABLE2;
 +	    else if (ctrlmask & 0x04)
 +		enable = SIGNAL_ENABLE3;
 +	    else if (ctrlmask & 0x08)
 +		enable = SIGNAL_ENABLE4;
 +
 +	    /* set data-lines to input */
 +	    drv_generic_parport_direction(1);
 +
 +	    if (Bits == 8) {
 +		/* Set RW, clear RS */
 +		drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RW);
 +	    } else {
 +		drv_generic_parport_data(SIGNAL_RW);
 +	    }
 +
 +	    /* Address set-up time */
 +	    ndelay(T_AS);
 +
 +	    /* rise ENABLE */
 +	    if (Bits == 8) {
 +		drv_generic_parport_control(enable, enable);
 +	    } else {
 +		drv_generic_parport_data(SIGNAL_RW | enable);
 +	    }
 +
 +	    counter = 0;
 +	    while (1) {
 +		/* read the busy flag */
 +		data = drv_generic_parport_read();
 +		if ((data & busymask) == 0) {
 +		    errors = 0;
 +		    break;
 +		}
 +
 +		/* make sure we don't wait forever
 +		 * - but only check after 5 iterations
 +		 * that way, we won't slow down normal mode
 +		 * (where we don't need the timeout anyway) 
 +		 */
 +		counter++;
 +
 +		if (counter >= 5) {
 +		    struct timeval now, end;
 +
 +		    if (counter == 5) {
 +			/* determine the time when the timeout has expired */
 +			gettimeofday(&end, NULL);
 +			end.tv_usec += MAX_BUSYFLAG_WAIT;
 +			while (end.tv_usec > 1000000) {
 +			    end.tv_usec -= 1000000;
 +			    end.tv_sec++;
 +			}
 +		    }
 +
 +		    /* get the current time */
 +		    gettimeofday(&now, NULL);
 +		    if (now.tv_sec == end.tv_sec ? now.tv_usec >= end.tv_usec : now.tv_sec >= end.tv_sec) {
 +			error("%s: timeout waiting for busy flag on controller %x (%x)", Name, ctrlmask, data);
 +			if (++errors >= MAX_BUSYFLAG_ERRORS) {
 +			    error("%s: too many busy flag failures, turning off busy flag checking.", Name);
 +			    UseBusy = 0;
 +			}
 +			break;
 +		    }
 +		}
 +	    }
 +
 +	    /* RS=low, RW=low, EN=low */
 +	    if (Bits == 8) {
 +		/* Lower EN */
 +		drv_generic_parport_control(enable, 0);
 +
 +		/* Address hold time */
 +		ndelay(T_AH);
 +
 +		drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, 0);
 +	    } else {
 +		/* Lower EN */
 +		drv_generic_parport_data(SIGNAL_RW);
 +		ndelay(T_AH);
 +		drv_generic_parport_data(0);
 +	    }
 +
 +	    /* set data-lines to output */
 +	    drv_generic_parport_direction(0);
 +	}
 +	ctrlmask >>= 1;
 +    }
 +}
 +
 +
 +static void drv_HD_PP_nibble(const unsigned char controller, const unsigned char nibble)
 +{
 +    unsigned char enable;
 +
 +    /* enable signal: 'controller' is a bitmask */
 +    /* bit n .. send to controller #n */
 +    /* so we can send a byte to more controllers at the same time! */
 +    enable = 0;
 +    if (controller & 0x01)
 +	enable |= SIGNAL_ENABLE;
 +    if (controller & 0x02)
 +	enable |= SIGNAL_ENABLE2;
 +    if (controller & 0x04)
 +	enable |= SIGNAL_ENABLE3;
 +    if (controller & 0x08)
 +	enable |= SIGNAL_ENABLE4;
 +
 +    /* clear ENABLE */
 +    /* put data on DB1..DB4 */
 +    /* nibble already contains RS bit! */
 +    drv_generic_parport_data(nibble);
 +
 +    /* Address set-up time */
 +    ndelay(T_AS);
 +
 +    /* rise ENABLE */
 +    drv_generic_parport_data(nibble | enable);
 +
 +    /* Enable pulse width */
 +    ndelay(T_PW);
 +
 +    /* lower ENABLE */
 +    drv_generic_parport_data(nibble);
 +}
 +
 +
 +static void drv_HD_PP_byte(const unsigned char controller, const unsigned char data, const unsigned char RS)
 +{
 +    /* send high nibble of the data */
 +    drv_HD_PP_nibble(controller, ((data >> 4) & 0x0f) | RS);
 +
 +    /* Make sure we honour T_CYCLE */
 +    ndelay(T_CYCLE - T_AS - T_PW);
 +
 +    /* send low nibble of the data */
 +    drv_HD_PP_nibble(controller, (data & 0x0f) | RS);
 +}
 +
 +
 +static void drv_HD_PP_command(const unsigned char controller, const unsigned char cmd, const int delay)
 +{
 +    unsigned char enable;
 +
 +    if (UseBusy)
 +	drv_HD_PP_busy(controller);
 +
 +    if (Bits == 8) {
 +
 +	/* enable signal: 'controller' is a bitmask */
 +	/* bit n .. send to controller #n */
 +	/* so we can send a byte to more controllers at the same time! */
 +	enable = 0;
 +	if (controller & 0x01)
 +	    enable |= SIGNAL_ENABLE;
 +	if (controller & 0x02)
 +	    enable |= SIGNAL_ENABLE2;
 +	if (controller & 0x04)
 +	    enable |= SIGNAL_ENABLE3;
 +	if (controller & 0x08)
 +	    enable |= SIGNAL_ENABLE4;
 +
 +	/* put data on DB1..DB8 */
 +	drv_generic_parport_data(cmd);
 +
 +	/* clear RW and RS */
 +	drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, 0);
 +
 +	/* Address set-up time */
 +	ndelay(T_AS);
 +
 +	/* send command */
 +	drv_generic_parport_toggle(enable, 1, T_PW);
 +
 +    } else {
 +
 +	drv_HD_PP_byte(controller, cmd, 0);
 +
 +    }
 +
 +    /* wait for command completion */
 +    if (!UseBusy)
 +	udelay(delay);
 +
 +}
 +
 +
 +static void drv_HD_PP_data(const unsigned char controller, const char *string, const int len, const int delay)
 +{
 +    int l = len;
 +    unsigned char enable;
 +
 +    /* sanity check */
 +    if (len <= 0)
 +	return;
 +
 +    if (Bits == 8) {
 +
 +	/* enable signal: 'controller' is a bitmask */
 +	/* bit n .. send to controller #n */
 +	/* so we can send a byte to more controllers at the same time! */
 +	enable = 0;
 +	if (controller & 0x01)
 +	    enable |= SIGNAL_ENABLE;
 +	if (controller & 0x02)
 +	    enable |= SIGNAL_ENABLE2;
 +	if (controller & 0x04)
 +	    enable |= SIGNAL_ENABLE3;
 +	if (controller & 0x08)
 +	    enable |= SIGNAL_ENABLE4;
 +
 +	if (!UseBusy) {
 +	    /* clear RW, set RS */
 +	    drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RS);
 +	    /* Address set-up time */
 +	    ndelay(T_AS);
 +	}
 +
 +	while (l--) {
 +
 +	    if (UseBusy) {
 +		drv_HD_PP_busy(controller);
 +		/* clear RW, set RS */
 +		drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RS);
 +		/* Address set-up time */
 +		ndelay(T_AS);
 +	    }
 +
 +	    /* put data on DB1..DB8 */
 +	    drv_generic_parport_data(*(string++));
 +
 +	    /* send command */
 +	    drv_generic_parport_toggle(enable, 1, T_PW);
 +
 +	    /* wait for command completion */
 +	    if (!UseBusy)
 +		udelay(delay);
 +	}
 +
 +    } else {			/* 4 bit mode */
 +
 +	while (l--) {
 +	    if (UseBusy)
 +		drv_HD_PP_busy(controller);
 +
 +	    /* send data with RS enabled */
 +	    drv_HD_PP_byte(controller, *(string++), SIGNAL_RS);
 +
 +	    /* wait for command completion */
 +	    if (!UseBusy)
 +		udelay(delay);
 +	}
 +    }
 +}
 +
 +
 +static int drv_HD_PP_load(const char *section)
 +{
 +    if (cfg_number(section, "Bits", 8, 4, 8, &Bits) < 0)
 +	return -1;
 +
 +    if (Bits != 4 && Bits != 8) {
 +	error("%s: bad %s.Bits '%d' from %s, should be '4' or '8'", Name, section, Bits, cfg_source());
 +	return -1;
 +    }
 +
 +    /* LCM-162 only supports 8-bit-mode */
 +    if (Capabilities & CAP_LCM162 && Bits != 8) {
 +	error("%s: Model '%s' does not support %d bit mode!", Name, Models[Model].name, Bits);
 +	Bits = 8;
 +    }
 +    info("%s: using %d bit mode", Name, Bits);
 +
 +    if (drv_generic_parport_open(section, Name) != 0) {
 +	error("%s: could not initialize parallel port!", Name);
 +	return -1;
 +    }
 +
 +    /* Soft-Wiring */
 +    if (Capabilities & CAP_LCM162) {
 +	/* the LCM-162 is hardwired */
 +	if ((SIGNAL_RS = drv_generic_parport_hardwire_ctrl("RS", "SLCTIN")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_RW = drv_generic_parport_hardwire_ctrl("RW", "INIT")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_ENABLE = drv_generic_parport_hardwire_ctrl("ENABLE", "AUTOFD")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_ENABLE2 = drv_generic_parport_hardwire_ctrl("ENABLE2", "GND")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_ENABLE3 = drv_generic_parport_hardwire_ctrl("ENABLE3", "GND")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_ENABLE4 = drv_generic_parport_hardwire_ctrl("ENABLE4", "GND")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_BACKLIGHT = drv_generic_parport_hardwire_ctrl("BACKLIGHT", "GND")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_GPO = drv_generic_parport_hardwire_ctrl("GPO", "GND")) == 0xff)
 +	    return -1;
 +    } else {
 +	if (Bits == 8) {
 +	    if ((SIGNAL_RS = drv_generic_parport_wire_ctrl("RS", "AUTOFD")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_RW = drv_generic_parport_wire_ctrl("RW", "GND")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE = drv_generic_parport_wire_ctrl("ENABLE", "STROBE")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_ctrl("ENABLE2", "GND")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE3 = drv_generic_parport_wire_ctrl("ENABLE3", "GND")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE4 = drv_generic_parport_wire_ctrl("ENABLE4", "GND")) == 0xff)
 +		return -1;
 +	} else {
 +	    if ((SIGNAL_RS = drv_generic_parport_wire_data("RS", "DB4")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_RW = drv_generic_parport_wire_data("RW", "DB5")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE = drv_generic_parport_wire_data("ENABLE", "DB6")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_data("ENABLE2", "GND")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE3 = drv_generic_parport_wire_data("ENABLE3", "GND")) == 0xff)
 +		return -1;
 +	    if ((SIGNAL_ENABLE4 = drv_generic_parport_wire_data("ENABLE4", "GND")) == 0xff)
 +		return -1;
 +	}
 +	/* backlight and GPO are always control signals */
 +	if ((SIGNAL_BACKLIGHT = drv_generic_parport_wire_ctrl("BACKLIGHT", "GND")) == 0xff)
 +	    return -1;
 +	if ((SIGNAL_GPO = drv_generic_parport_wire_ctrl("GPO", "GND")) == 0xff)
 +	    return -1;
 +    }
 +
 +    /* clear capabilities if corresponding signal is GND */
 +    if (SIGNAL_BACKLIGHT == 0) {
 +	Capabilities &= ~CAP_BACKLIGHT;
 +    }
 +    if (SIGNAL_GPO == 0) {
 +	Capabilities &= ~CAP_GPO;
 +    }
 +
 +
 +    /* clear all signals */
 +    if (Bits == 8) {
 +	drv_generic_parport_control(SIGNAL_RS |
 +				    SIGNAL_RW | SIGNAL_ENABLE | SIGNAL_ENABLE2 | SIGNAL_ENABLE3 | SIGNAL_ENABLE4 | SIGNAL_BACKLIGHT | SIGNAL_GPO, 0);
 +    } else {
 +	drv_generic_parport_data(0);
 +    }
 +
 +    /* set direction: write */
 +    drv_generic_parport_direction(0);
 +
 +    /* initialize *all* controllers */
 +    if (Bits == 8) {
 +	drv_HD_PP_command(allControllers, 0x30, T_INIT1);	/* 8 Bit mode, wait 4.1 ms */
 +	drv_HD_PP_command(allControllers, 0x30, T_INIT2);	/* 8 Bit mode, wait 100 us */
 +	drv_HD_PP_command(allControllers, 0x38, T_EXEC);	/* 8 Bit mode, 1/16 duty cycle, 5x8 font */
 +    } else {
 +	drv_HD_PP_nibble(allControllers, 0x03);
 +	udelay(T_INIT1);	/* 4 Bit mode, wait 4.1 ms */
 +	drv_HD_PP_nibble(allControllers, 0x03);
 +	udelay(T_INIT2);	/* 4 Bit mode, wait 100 us */
 +	drv_HD_PP_nibble(allControllers, 0x03);
 +	udelay(T_INIT1);	/* 4 Bit mode, wait 4.1 ms */
 +	drv_HD_PP_nibble(allControllers, 0x02);
 +	udelay(T_INIT2);	/* 4 Bit mode, wait 100 us */
 +	drv_HD_PP_command(allControllers, 0x28, T_EXEC);	/* 4 Bit mode, 1/16 duty cycle, 5x8 font */
 +    }
 +
 +    /* maybe use busy-flag from now on  */
 +    /* (we can't use the busy flag during the init sequence) */
 +    cfg_number(section, "UseBusy", 0, 0, 1, &UseBusy);
 +
 +    /* make sure we don't use the busy flag with RW wired to GND */
 +    if (UseBusy && !SIGNAL_RW) {
 +	error("%s: busy-flag checking is impossible with RW wired to GND!", Name);
 +	UseBusy = 0;
 +    }
 +
 +    /* make sure the display supports busy-flag checking in 4-Bit-Mode */
 +    /* at the moment this is inly possible with Martin Hejl's gpio driver, */
 +    /* which allows to use 4 bits as input and 4 bits as output */
 +    if (UseBusy && Bits == 4 && !(Capabilities & CAP_BUSY4BIT)) {
 +	error("%s: Model '%s' does not support busy-flag checking in 4 bit mode", Name, Models[Model].name);
 +	UseBusy = 0;
 +    }
 +
 +    info("%s: %susing busy-flag checking", Name, UseBusy ? "" : "not ");
 +
 +    /* The LCM-162 should really use BusyFlag checking */
 +    if (!UseBusy && (Capabilities & CAP_LCM162)) {
 +	error("%s: Model '%s' should definitely use busy-flag checking!", Name, Models[Model].name);
 +    }
 +
 +    return 0;
 +}
 +
 +
 +static void drv_HD_PP_stop(void)
 +{
 +    /* clear all signals */
 +    if (Bits == 8) {
 +	drv_generic_parport_control(SIGNAL_RS |
 +				    SIGNAL_RW | SIGNAL_ENABLE | SIGNAL_ENABLE2 | SIGNAL_ENABLE3 | SIGNAL_ENABLE4 | SIGNAL_BACKLIGHT | SIGNAL_GPO, 0);
 +    } else {
 +	drv_generic_parport_data(0);
 +    }
 +
 +    drv_generic_parport_close();
 +
 +}
 +
 +
 +#ifdef WITH_I2C
 +
 +/****************************************/
 +/***  i2c dependant functions         ***/
 +/****************************************/
 +
 +    /*
 +        DISCLAIMER!!!!
 +		
 +		The following code is WORK IN PROGRESS, since it basicly 'works for us...'
 +
 +		(C) 2005 Paul Kamphuis & Luis Correia
 +
 +		We have removed all of the delays from this code, as the I2C bus is slow enough...
 +		(maximum possible speed is 100KHz only)
 +
 +	*/
 +
 +static void drv_HD_I2C_nibble(unsigned char controller, unsigned char nibble)
 +{
 +    unsigned char enable;
 +    unsigned char command; /* this is actually the first data byte on the PCF8574 */
 +    unsigned char data_block[2];
 +    /* enable signal: 'controller' is a bitmask */
 +    /* bit n .. send to controller #n */
 +    /* so we can send a byte to more controllers at the same time! */
 +    enable = 0;
 +    if (controller & 0x01)
 +	enable |= SIGNAL_ENABLE;
 +    if (controller & 0x02)
 +	enable |= SIGNAL_ENABLE2;
 +    if (controller & 0x04)
 +	enable |= SIGNAL_ENABLE3;
 +    if (controller & 0x08)
 +	enable |= SIGNAL_ENABLE4;
 +
 +    /*
 +        The new method Paul Kamphuis has concocted places the 3 needed writes to the I2C device
 +	    as a single operation, using the 'i2c_smbus_write_block_data' function.
 +		These actual writes are performed by putting the nibble along with the 'EN' signal.
 +
 +		command = first byte to be written, which contains the nibble (DB0..DB3)
 +		data [0]   = second byte to be written, which contains the nibble plus the EN signal
 +		data [1]   = third byte to be written, which contains the nibble (DB0..DB3)
 +
 +		Then we write the block as a whole.
 +
 +		The main advantage we see is that we do 2 less IOCTL's from our driver.
 +	*/
 +
 +    command		= nibble;
 +    data_block[0] = nibble | enable;
 +    data_block[1] = nibble;
 +
 +	drv_generic_i2c_command(command,data_block,2);
 +}
 +
 +
 +static void drv_HD_I2C_byte(const unsigned char controller, const unsigned char data)
 +{
 +    /* send data with RS enabled */
 +    drv_HD_I2C_nibble(controller, ((data >> 4) & 0x0f) | SIGNAL_RS);
 +    drv_HD_I2C_nibble(controller, (data & 0x0f) | SIGNAL_RS);
 +}
 +
 +
 +static void drv_HD_I2C_command(const unsigned char controller, const unsigned char cmd, const int delay)
 +{
 +    /* send data with RS disabled */
 +    drv_HD_I2C_nibble(controller, ((cmd >> 4) & 0x0f));
 +    drv_HD_I2C_nibble(controller, ((cmd) & 0x0f));
 +}
 +
 +static void drv_HD_I2C_data(const unsigned char controller, const char *string, const int len, const int delay)
 +{
 +    int l = len;
 +
 +    /* sanity check */
 +    if (len <= 0)
 +	return;
 +
 +    while (l--) {
 +	drv_HD_I2C_byte(controller, *(string++));
 +    }
 +}
 +
 +
 +static int drv_HD_I2C_load(const char *section)
 +{
 +    if (cfg_number(section, "Bits", 8, 4, 8, &Bits) < 0)
 +	return -1;
 +    if (Bits != 4) {
 +	error("%s: bad %s.Bits '%d' from %s, should be '4'", Name, section, Bits, cfg_source());
 +	return -1;
 +    }
 +
 +    info("%s: using %d bit mode", Name, Bits);
 +
 +    if (drv_generic_i2c_open(section, Name) != 0) {
 +	error("%s: could not initialize i2c attached device!", Name);
 +	return -1;
 +    }
 +
 +    if ((SIGNAL_RS = drv_generic_i2c_wire("RS", "DB4")) == 0xff)
 +	return -1;
 +    if ((SIGNAL_RW = drv_generic_i2c_wire("RW", "DB5")) == 0xff)
 +	return -1;
 +    if ((SIGNAL_ENABLE = drv_generic_i2c_wire("ENABLE", "DB6")) == 0xff)
 +	return -1;
 +    if ((SIGNAL_ENABLE2 = drv_generic_i2c_wire("ENABLE2", "GND")) == 0xff)
 +	return -1;
 +    if ((SIGNAL_GPO = drv_generic_i2c_wire("GPO", "GND")) == 0xff)
 +	return -1;
 +
 +    /* initialize display */
 +    drv_HD_I2C_nibble(allControllers, 0x03);
 +    udelay(T_INIT1);		/* 4 Bit mode, wait 4.1 ms */
 +    drv_HD_I2C_nibble(allControllers, 0x03);
 +    udelay(T_INIT2);		/* 4 Bit mode, wait 100 us */
 +    drv_HD_I2C_nibble(allControllers, 0x03);
 +    udelay(T_INIT2);		/* 4 Bit mode, wait 4.1 ms */
 +    drv_HD_I2C_nibble(allControllers, 0x02);
 +    udelay(T_INIT2);		/* 4 Bit mode, wait 100 us */
 +    drv_HD_I2C_command(allControllers, 0x28, T_EXEC);	/* 4 Bit mode, 1/16 duty cycle, 5x8 font */
 +
 +    info("%s: I2C initialization done", Name);
 +
 +    return 0;
 +}
 +
 +
 +static void drv_HD_I2C_stop(void)
 +{
 +    /* clear all signals */
 +    drv_generic_i2c_data(0);
 +
 +    /* close port */
 +    drv_generic_i2c_close();
 +}
 +
 +/* END OF DISCLAIMER */
 +
 +#endif				/* WITH_I2C */
 +
 +
 +/****************************************/
 +/***  display dependant functions     ***/
 +/****************************************/
 +
 +static void drv_HD_clear(void)
 +{
 +    drv_HD_command(allControllers, 0x01, T_CLEAR);	/* clear *all* displays */
 +}
 +
 +
 +static int drv_HD_goto(int row, int col)
 +{
 +    int pos, controller;
 +
 +    /* handle multiple controllers */
 +    for (pos = 0, controller = 0; controller < numControllers; controller++) {
 +	pos += CROWS[controller];
 +	if (row < pos) {
 +	    currController = (1 << controller);
 +	    break;
 +	}
 +	row -= CROWS[controller];
 +    }
 +
 +    /* column outside of current display's width */
 +    if (col >= CCOLS[controller])
 +	return -1;
 +
 +    if (0) {
 +	debug("goto: [%d,%d] mask=%d, controller=%d, size:%dx%d", row, col, currController, controller, CROWS[controller], CCOLS[controller]);
 +    }
 +
 +    /* 16x1 Displays are organized as 8x2 :-( */
 +    if (CCOLS[controller] == 16 && CROWS[controller] == 1 && col > 7) {
 +	row++;
 +	col -= 8;
 +    }
 +
 +    if (Capabilities & CAP_HD66712) {
 +	/* the HD66712 doesn't have a braindamadged RAM layout */
 +	pos = row * 32 + col;
 +    } else {
 +	/* 16x4 Controllers use a slightly different layout */
 +	if (CCOLS[controller] == 16 && CROWS[controller] == 4) {
 +	    pos = (row % 2) * 64 + (row / 2) * 16 + col;
 +	} else {
 +	    pos = (row % 2) * 64 + (row / 2) * 20 + col;
 +	}
 +    }
 +    drv_HD_command(currController, (0x80 | pos), T_EXEC);
 +
 +    /* return columns left on current display */
 +    return CCOLS[controller] - col;
 +
 +}
 +
 +
 +static void drv_HD_write(const int row, const int col, const char *data, const int len)
 +{
 +    int space = drv_HD_goto(row, col);
 +    if (space > 0) {
 +	drv_HD_data(currController, data, len > space ? space : len, T_EXEC);
 +    }
 +}
 +
 +
 +static void drv_HD_defchar(const int ascii, const unsigned char *matrix)
 +{
 +    int i;
 +    char buffer[8];
 +
 +    for (i = 0; i < 8; i++) {
 +	buffer[i] = matrix[i] & 0x1f;
 +    }
 +
 +    /* define chars on *all* controllers! */
 +    drv_HD_command(allControllers, 0x40 | 8 * ascii, T_EXEC);
 +    drv_HD_data(allControllers, buffer, 8, T_WRCG);
 +}
 +
 +
 +static int drv_HD_backlight(int backlight)
 +{
 +    if (!(Capabilities & CAP_BACKLIGHT))
 +	return -1;
 +
 +    if (backlight < 0)
 +	backlight = 0;
 +    if (backlight > 1)
 +	backlight = 1;
 +
 +    drv_generic_parport_control(SIGNAL_BACKLIGHT, backlight ? SIGNAL_BACKLIGHT : 0);
 +
 +    return backlight;
 +}
 +
 +
 +static int drv_HD_brightness(int brightness)
 +{
 +    char cmd;
 +
 +    if (!(Capabilities & CAP_BRIGHTNESS))
 +	return -1;
 +
 +    if (brightness < 0)
 +	brightness = 0;
 +    if (brightness > 3)
 +	brightness = 3;
 +
 +    cmd = '0' + brightness;
 +
 +    drv_HD_command(allControllers, 0x38, T_EXEC);	/* enable function */
 +    drv_HD_data(allControllers, &cmd, 1, T_WRCG);	/* set brightness */
 +
 +    return brightness;
 +}
 +
 +
 +/* Fixme: GPO's */
 +#if 0
 +static void drv_HD_setGPO(const int bits)
 +{
 +    if (Lcd.gpos > 0) {
 +
 +	/* put data on DB1..DB8 */
 +	drv_generic_parport_data(bits);
 +
 +	/* 74HCT573 set-up time */
 +	ndelay(20);
 +
 +	/* send data */
 +	/* 74HCT573 enable pulse width = 24ns */
 +	drv_generic_parport_toggle(SIGNAL_GPO, 1, 230);
 +    }
 +}
 +#endif
 +
 +
 +static void drv_HD_LCM162_timer(void __attribute__ ((unused)) * notused)
 +{
 +    static unsigned char data = 0x00;
 +
 +    /* Bit 3+5 : key number */
 +    /* Bit 6   : key press/release */
 +    unsigned char mask3 = 1 << 3;
 +    unsigned char mask5 = 1 << 5;
 +    unsigned char mask6 = 1 << 6;
 +    unsigned char mask = mask3 | mask5 | mask6;
 +
 +    int keynum;
 +    int updown;
 +
 +    unsigned char temp;
 +
 +    temp = drv_generic_parport_status() & mask;
 +
 +    if (data != temp) {
 +	data = temp;
 +
 +	keynum = (data & mask3 ? 1 : 0) + (data & mask5 ? 2 : 0);
 +	updown = (data & mask6 ? 1 : 0);
 +
 +	debug("key %d press %d", keynum, updown);
 +    }
 +}
 +
 +
 +static int drv_HD_start(const char *section, const int quiet)
 +{
 +    char *model, *size, *bus;
 +    int rows = -1, cols = -1, gpos = -1, i;
 +    int size_defined = 0;
 +    int size_missing = 0;
 +
 +    model = cfg_get(section, "Model", "generic");
 +    if (model != NULL && *model != '\0') {
 +	int i;
 +	for (i = 0; Models[i].type != 0xff; i++) {
 +	    if (strcasecmp(Models[i].name, model) == 0)
 +		break;
 +	}
 +	if (Models[i].type == 0xff) {
 +	    error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
 +	    return -1;
 +	}
 +	Model = i;
 +	Capabilities = Models[Model].capabilities;
 +	info("%s: using model '%s'", Name, Models[Model].name);
 +    } else {
 +	error("%s: empty '%s.Model' entry from %s", Name, section, cfg_source());
 +	if (model)
 +	    free(model);
 +	return -1;
 +    }
 +    free(model);
 +
 +    bus = cfg_get(section, "Bus", "parport");
 +    if (bus == NULL && *bus == '\0') {
 +	error("%s: empty '%s.Bus' entry from %s", Name, section, cfg_source());
 +	if (bus)
 +	    free(bus);
 +	return -1;
 +    }
 +
 +    if (strcasecmp(bus, "parport") == 0) {
 +	info("%s: using parallel port", Name);
 +	Bus = BUS_PP;
 +	drv_HD_load = drv_HD_PP_load;
 +	drv_HD_command = drv_HD_PP_command;
 +	drv_HD_data = drv_HD_PP_data;
 +	drv_HD_stop = drv_HD_PP_stop;
 +
 +    } else if (strcasecmp(bus, "i2c") == 0) {
 +#ifdef WITH_I2C
 +	info("%s: using I2C bus", Name);
 +	Bus = BUS_I2C;
 +	drv_HD_load = drv_HD_I2C_load;
 +	drv_HD_command = drv_HD_I2C_command;
 +	drv_HD_data = drv_HD_I2C_data;
 +	drv_HD_stop = drv_HD_I2C_stop;
 +#else
 +	error("%s: %s.Bus '%s' from %s not available:", Name, section, bus, cfg_source());
 +	error("%s: lcd4linux was compiled without i2c support!", Name);
 +	free(bus);
 +	return -1;
 +#endif
 +
 +    } else {
 +	error("%s: bad %s.Bus '%s' from %s, should be 'parport' or 'i2c'", Name, section, bus, cfg_source());
 +	free(bus);
 +	return -1;
 +    }
 +
 +    /* sanity check: Model can use bus */
 +    if (!(Capabilities & Bus)) {
 +	error("%s: Model '%s' cannot be used on the %s bus!", Name, Models[Model].name, bus);
 +	free(bus);
 +	return -1;
 +    }
 +    free(bus);
 +
 +    if (cfg_number(section, "Controllers", 1, 1, 4, (int *) &numControllers) < 0)
 +	return -1;
 +    info("%s: using %d Controller(s)", Name, numControllers);
 +
 +    /* current Controller */
 +    currController = 1;
 +
 +    /* Bitmask for *all* Controllers */
 +    allControllers = (1 << numControllers) - 1;
 +
 +
 +    DCOLS = 0;
 +    DROWS = 0;
 +
 +    for (i = 0; i < numControllers; i++) {
 +	char key[6];
 +	qprintf(key, sizeof(key), "Size%d", i + 1);
 +	size = cfg_get(section, key, NULL);
 +	if (size == NULL || *size == '\0') {
 +	    size_missing++;
 +	    free(size);
 +	    continue;
 +	}
 +	if (sscanf(size, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
 +	    error("%s: bad %s.%s '%s' from %s", Name, section, key, size, cfg_source());
 +	    free(size);
 +	    return -1;
 +	}
 +	free(size);
 +	CCOLS[i] = cols;
 +	CROWS[i] = rows;
 +	size_defined++;
 +	info("%s: Controller %d: %dx%d", Name, i + 1, cols, rows);
 +	/* grow the size */
 +	if (cols > DCOLS)
 +	    DCOLS = cols;
 +	DROWS += rows;
 +    }
 +    if (size_defined && size_missing) {
 +	error("%s: bad %s.Size* definition in %s:", Name, section, cfg_source());
 +	error("%s: either you specify the size for *all* controllers or for none.", Name);
 +	return -1;
 +    }
 +
 +    size = cfg_get(section, "Size", NULL);
 +    if (size != NULL && *size != '\0') {
 +	if (sscanf(size, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
 +	    error("%s: bad %s.Size '%s' from %s", Name, section, size, cfg_source());
 +	    free(size);
 +	    return -1;
 +	}
 +	if (DCOLS == 0 && DROWS == 0) {
 +	    for (i = 0; i < numControllers; i++) {
 +		CCOLS[i] = cols;
 +		CROWS[i] = rows / numControllers;
 +		DCOLS = CCOLS[i];
 +		DROWS += CROWS[i];
 +	    }
 +	}
 +	if (rows != DROWS || cols != DCOLS) {
 +	    error("%s: bad %s.Size definition in %s:", Name, section, cfg_source());
 +	    error("%s: Size %dx%d should be %dx%d", Name, cols, rows, DCOLS, DROWS);
 +	    return -1;
 +	}
 +    }
 +    free(size);
 +
 +
 +    if (cfg_number(section, "GPOs", 0, 0, 8, &gpos) < 0)
 +	return -1;
 +    if (gpos > 0 && !(Capabilities & CAP_GPO)) {
 +	error("%s: Model '%s' does not support GPO's!", Name, Models[Model].name);
 +	gpos = 0;
 +    }
 +    GPOS = gpos;
 +    if (gpos > 0) {
 +	info("%s: using %d GPO's", Name, GPOS);
 +    }
 +
 +    if (drv_HD_load(section) < 0) {
 +	error("%s: start display failed!", Name);
 +	return -1;
 +    }
 +
 +    drv_HD_command(allControllers, 0x08, T_EXEC);	/* Controller off, cursor off, blink off */
 +    drv_HD_command(allControllers, 0x0c, T_CLEAR);	/* Display on, cursor off, blink off, wait 1.64 ms */
 +    drv_HD_command(allControllers, 0x06, T_EXEC);	/* curser moves to right, no shift */
 +
 +    if ((Capabilities & CAP_HD66712) && DROWS > 2) {
 +	drv_HD_command(allControllers, Bits == 8 ? 0x3c : 0x2c, T_EXEC);	/* set extended register enable bit */
 +	drv_HD_command(allControllers, 0x09, T_EXEC);	/* set 4-line mode */
 +	drv_HD_command(allControllers, Bits == 8 ? 0x38 : 0x28, T_EXEC);	/* clear extended register enable bit */
 +    }
 +
 +    drv_HD_clear();		/* clear *all* displays */
 +    drv_HD_command(allControllers, 0x03, T_CLEAR);	/* return home */
 +
 +    /* maybe set backlight */
 +    if (Capabilities & CAP_BACKLIGHT) {
 +	int backlight;
 +	if (cfg_number(section, "Backlight", 0, 0, 1, &backlight) > 0) {
 +	    info("%s: backlight %s", Name, backlight ? "enabled" : "disabled");
 +	    drv_HD_backlight(backlight);
 +	}
 +    }
 +
 +    /* maybe set brightness */
 +    if (Capabilities & CAP_BRIGHTNESS) {
 +	int brightness;
 +	if (cfg_number(section, "Brightness", 0, 0, 3, &brightness) > 0) {
 +	    info("%s: brightness level %d", Name, brightness);
 +	    drv_HD_brightness(brightness);
 +	}
 +    }
 +
 +    /* install keypad polling timer for LCM-162 */
 +    if (Capabilities & CAP_LCM162) {
 +	timer_add(drv_HD_LCM162_timer, NULL, 10, 0);
 +    }
 +
 +    if (!quiet) {
 +	char buffer[40];
 +	qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
 +	if (drv_generic_text_greet(buffer, NULL)) {
 +	    sleep(3);
 +	    drv_HD_clear();
 +	}
 +    }
 +
 +    return 0;
 +}
 +
 +
 +/****************************************/
 +/***            plugins               ***/
 +/****************************************/
 +
 +
 +static void plugin_backlight(RESULT * result, RESULT * arg1)
 +{
 +    double backlight;
 +
 +    backlight = drv_HD_backlight(R2N(arg1));
 +    SetResult(&result, R_NUMBER, &backlight);
 +}
 +
 +
 +static void plugin_brightness(RESULT * result, RESULT * arg1)
 +{
 +    double brightness;
 +
 +    brightness = drv_HD_brightness(R2N(arg1));
 +    SetResult(&result, R_NUMBER, &brightness);
 +}
 +
 +
 +/****************************************/
 +/***        widget callbacks          ***/
 +/****************************************/
 +
 +
 +/* using drv_generic_text_draw(W) */
 +/* using drv_generic_text_icon_draw(W) */
 +/* using drv_generic_text_bar_draw(W) */
 +
 +
 +/****************************************/
 +/***        exported functions        ***/
 +/****************************************/
 +
 +
 +/* list models */
 +int drv_HD_list(void)
 +{
 +    int i;
 +
 +    for (i = 0; Models[i].type != 0xff; i++) {
 +	printf("%s ", Models[i].name);
 +    }
 +    return 0;
 +}
 +
 +
 +/* initialize driver & display */
 +int drv_HD_init(const char *section, const int quiet)
 +{
 +    WIDGET_CLASS wc;
 +    int asc255bug;
 +    int ret;
 +
 +    /* display preferences */
 +    XRES = 5;			/* pixel width of one char  */
 +    YRES = 8;			/* pixel height of one char  */
 +    CHARS = 8;			/* number of user-defineable characters */
 +    CHAR0 = 0;			/* ASCII of first user-defineable char */
 +    GOTO_COST = 1;		/* number of bytes a goto command requires */
 +
 +    /* real worker functions */
 +    drv_generic_text_real_write = drv_HD_write;
 +    drv_generic_text_real_defchar = drv_HD_defchar;
 +
 +
 +    /* start display */
 +    if ((ret = drv_HD_start(section, quiet)) != 0)
 +	return ret;
 +
 +    /* initialize generic text driver */
 +    if ((ret = drv_generic_text_init(section, Name)) != 0)
 +	return ret;
 +
 +    /* initialize generic icon driver */
 +    if ((ret = drv_generic_text_icon_init()) != 0)
 +	return ret;
 +
 +    /* initialize generic bar driver */
 +    if ((ret = drv_generic_text_bar_init(0)) != 0)
 +	return ret;
 +
 +    /* add fixed chars to the bar driver */
 +    /* most displays have a full block on ascii 255, but some have kind of  */
 +    /* an 'inverted P'. If you specify 'asc255bug 1 in the config, this */
 +    /* char will not be used, but rendered by the bar driver */
 +    cfg_number(section, "asc255bug", 0, 0, 1, &asc255bug);
 +    drv_generic_text_bar_add_segment(0, 0, 255, 32);	/* ASCII  32 = blank */
 +    if (!asc255bug)
 +	drv_generic_text_bar_add_segment(255, 255, 255, 255);	/* ASCII 255 = block */
 +
 +    /* register text widget */
 +    wc = Widget_Text;
 +    wc.draw = drv_generic_text_draw;
 +    widget_register(&wc);
 +
 +    /* register icon widget */
 +    wc = Widget_Icon;
 +    wc.draw = drv_generic_text_icon_draw;
 +    widget_register(&wc);
 +
 +    /* register bar widget */
 +    wc = Widget_Bar;
 +    wc.draw = drv_generic_text_bar_draw;
 +    widget_register(&wc);
 +
 +    /* register plugins */
 +    if (Capabilities & CAP_BACKLIGHT) {
 +	AddFunction("LCD::backlight", 1, plugin_backlight);
 +    }
 +    if (Capabilities & CAP_BRIGHTNESS) {
 +	AddFunction("LCD::brightness", 1, plugin_brightness);
 +    }
 +
 +    return 0;
 +}
 +
 +
 +/* close driver & display */
 +int drv_HD_quit(const int quiet)
 +{
 +
 +    info("%s: shutting down.", Name);
 +
 +    drv_generic_text_quit();
 +
 +    /* clear display */
 +    drv_HD_clear();
 +
 +    /* say goodbye... */
 +    if (!quiet) {
 +	drv_generic_text_greet("goodbye!", NULL);
 +    }
 +
 +    drv_HD_stop();
 +
 +    return (0);
 +}
 +
 +
 +DRIVER drv_HD44780 = {
 +  name:Name,
 +  list:drv_HD_list,
 +  init:drv_HD_init,
 +  quit:drv_HD_quit,
 +};
 diff --git a/drv_generic_i2c.c b/drv_generic_i2c.c index 538b19a..22b4c72 100644 --- a/drv_generic_i2c.c +++ b/drv_generic_i2c.c @@ -1,164 +1,192 @@ -/* $Id: drv_generic_i2c.c,v 1.3 2005/05/08 04:32:44 reinelt Exp $ - * - * generic driver helper for i2c displays - * - * Copyright (C) 2005 Luis F. Correia <luis.f.correia@seg-social.pt> - * Copyright (C) 2005 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> - * - * This file is part of LCD4Linux. - * - * LCD4Linux 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, or (at your option) - * any later version. - * - * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * +/* $Id: drv_generic_i2c.c,v 1.4 2005/05/31 20:42:55 lfcorreia Exp $
 + *
 + * generic driver helper for i2c displays
 + *
 + * Copyright (C) 2005 Luis Correia <lfcorreia@users.sf.net>
 + * Copyright (C) 2005 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 + *
 + * This file is part of LCD4Linux.
 + *
 + * LCD4Linux 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, or (at your option)
 + * any later version.
 + *
 + * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 + *
 + *
   * $Log: drv_generic_i2c.c,v $ - * Revision 1.3  2005/05/08 04:32:44  reinelt - * CodingStyle added and applied - * - * Revision 1.2  2005/04/05 05:12:57  reinelt - * i2c patch from Paul (still does not work here :-( - * - * Revision 1.1  2005/03/28 19:39:23  reinelt - * HD44780/I2C patch from Luis merged (still does not work for me) + * Revision 1.4  2005/05/31 20:42:55  lfcorreia + * new file: lcd4linux_i2c.h + * avoid the problems detecting the proper I2C kernel include files   * + * rearrange all the other autoconf stuff to remove I2C detection   * - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <termios.h> -#include <fcntl.h> -#include <time.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -#include <linux/compiler.h> -#include <linux/i2c.h> -#include <linux/i2c-dev.h> - -#include "debug.h" -#include "qprintf.h" -#include "cfg.h" -#include "udelay.h" -#include "drv_generic_i2c.h" - -static char *Driver = ""; -static char *Section = ""; -static int i2c_device; - -static void my_i2c_smbus_write_byte_data(const int device, const unsigned char data) -{ -    struct i2c_smbus_ioctl_data args; -    args.read_write = I2C_SMBUS_WRITE; -    args.command = data; -    args.size = I2C_SMBUS_BYTE; -    args.data = 0; -    ioctl(device, I2C_SMBUS, &args); -} - -static void my_i2c_smbus_read_byte_data(const int device, const unsigned char data) -{ -    struct i2c_smbus_ioctl_data args; -    args.read_write = I2C_SMBUS_READ; -    args.command = data; -    args.size = I2C_SMBUS_BYTE; -    args.data = 0; -    ioctl(device, I2C_SMBUS, &args); -} - -int drv_generic_i2c_open(const char *section, const char *driver) -{ -    int dev; -    char *bus, *device; - -    //SIGNAL_ENABLE = 0x40; -    //SIGNAL_RW = 0x10; -    //SIGNAL_RS = 0x20; - -    udelay_init(); - -    Section = (char *) section; -    Driver = (char *) driver; - -    bus = cfg_get(Section, "Port", NULL); -    device = cfg_get(Section, "Device", NULL); -    dev = atoi(device); -    info("%s: initializing I2C bus %s", Driver, bus); -    info("device %d", dev); -    if ((i2c_device = open(bus, O_WRONLY)) < 0) { -	error("%s: I2C bus %s open failed !\n", Driver, bus); -	return -1; -    } - -    info("%s: initializing I2C slave device 0x%x", Driver, dev); -    if (ioctl(i2c_device, I2C_SLAVE, dev) < 0) { -	error("%s: error initializing device 0x%x\n", Driver, dev); -	close(i2c_device); -	return -1; -    } - -    return 0; -} - - -int drv_generic_i2c_close(void) -{ - -    close(i2c_device); - -    return 0; -} - -unsigned char drv_generic_i2c_wire(const char *name, const char *deflt) -{ -    unsigned char w; -    char wire[256]; -    char *s; - -    qprintf(wire, sizeof(wire), "Wire.%s", name); -    s = cfg_get(Section, wire, deflt); -    if (strlen(s) == 3 && strncasecmp(s, "DB", 2) == 0 && s[2] >= '0' && s[2] <= '7') { -	w = s[2] - '0'; -    } else if (strcasecmp(s, "GND") == 0) { -	w = 0; -    } else { -	error("%s: unknown signal <%s> for wire <%s>", Driver, s, name); -	error("%s: should be DB0..7 or GND", Driver); -	return 0xff; -    } -    free(s); -    if (w == 0) { -	info("%s: wiring: [DISPLAY:%s]<==>[i2c:GND]", Driver, name); -    } else { -	info("%s: wiring: [DISPLAY:%s]<==>[i2c:DB%d]", Driver, name, w); -    } - -    w = 1 << w; - -    return w; -} - -void drv_generic_i2c_data(const unsigned char data) -{ - -    my_i2c_smbus_write_byte_data(i2c_device, data); - -} + * new method by Paul Kamphuis to write to the I2C device + *
 + * Revision 1.3  2005/05/08 04:32:44  reinelt
 + * CodingStyle added and applied
 + *
 + * Revision 1.2  2005/04/05 05:12:57  reinelt
 + * i2c patch from Paul (still does not work here :-(
 + *
 + * Revision 1.1  2005/03/28 19:39:23  reinelt
 + * HD44780/I2C patch from Luis merged (still does not work for me)
 + *
 + *
 + */
 +
 +
 +    /*
 +        DISCLAIMER!!!!
 +		
 +		The following code is WORK IN PROGRESS, since it basicly 'works for us...'
 +
 +		(C) 2005 Paul Kamphuis & Luis Correia
 +
 +		We have removed all of the delays from this code, as the I2C bus is slow enough...
 +		(maximum possible speed is 100KHz only)
 +
 +	*/
 +
 +
 +#include "config.h"
 +
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <errno.h>
 +#include <unistd.h>
 +#include <termios.h>
 +#include <fcntl.h>
 +#include <time.h>
 +#include <signal.h>
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <sys/ioctl.h>
 +
 +#include "lcd4linux_i2c.h"
 +#include "debug.h"
 +#include "qprintf.h"
 +#include "cfg.h"
 +#include "udelay.h"
 +#include "drv_generic_i2c.h"
 +
 +static char *Driver = "";
 +static char *Section = "";
 +static int i2c_device;
 +
 +static void my_i2c_smbus_write_byte_data(const int device, const unsigned char val)
 +{
 +    struct i2c_smbus_ioctl_data args;
 +    union i2c_smbus_data data;
 +    args.read_write = I2C_SMBUS_WRITE;
 +    args.command = val;
 +    args.size = I2C_SMBUS_BYTE_DATA;
 +    data.byte = val;
 +    args.data = &data;
 +
 +    if (ioctl(device, I2C_SMBUS, &args) < 0) {
 +	info("I2C: device %s IOCTL failed !\n", device);
 +	}
 +
 +}
 +
 +static void my_i2c_smbus_read_byte_data(const int device, const unsigned char data)
 +{
 +    struct i2c_smbus_ioctl_data args;
 +    args.read_write = I2C_SMBUS_READ;
 +    args.command = data;
 +    args.size = I2C_SMBUS_BYTE;
 +    args.data = 0;
 +    ioctl(device, I2C_SMBUS, &args);
 +}
 +
 +int drv_generic_i2c_open(const char *section, const char *driver)
 +{
 +    int dev;
 +    char *bus, *device;
 +
 +    udelay_init();
 +
 +    Section = (char *) section;
 +    Driver = (char *) driver;
 +
 +    bus = cfg_get(Section, "Port", NULL);
 +    device = cfg_get(Section, "Device", NULL);
 +    dev = atoi(device);
 +    info("%s: initializing I2C bus %s", Driver, bus);
 +    info("device %d", dev);
 +    if ((i2c_device = open(bus, O_WRONLY)) < 0) {
 +	error("%s: I2C bus %s open failed !\n", Driver, bus);
 +	return -1;
 +    }
 +
 +    info("%s: initializing I2C slave device 0x%x", Driver, dev);
 +    if (ioctl(i2c_device, I2C_SLAVE, dev) < 0) {
 +	error("%s: error initializing device 0x%x\n", Driver, dev);
 +	close(i2c_device);
 +	return -1;
 +    }
 +
 +    return 0;
 +}
 +
 +
 +int drv_generic_i2c_close(void)
 +{
 +
 +    close(i2c_device);
 +
 +    return 0;
 +}
 +
 +unsigned char drv_generic_i2c_wire(const char *name, const char *deflt)
 +{
 +    unsigned char w;
 +    char wire[256];
 +    char *s;
 +
 +    qprintf(wire, sizeof(wire), "Wire.%s", name);
 +    s = cfg_get(Section, wire, deflt);
 +    if (strlen(s) == 3 && strncasecmp(s, "DB", 2) == 0 && s[2] >= '0' && s[2] <= '7') {
 +	w = s[2] - '0';
 +    } else if (strcasecmp(s, "GND") == 0) {
 +	w = 0;
 +    } else {
 +	error("%s: unknown signal <%s> for wire <%s>", Driver, s, name);
 +	error("%s: should be DB0..7 or GND", Driver);
 +	return 0xff;
 +    }
 +    free(s);
 +    if (w == 0) {
 +	info("%s: wiring: [DISPLAY:%s]<==>[i2c:GND]", Driver, name);
 +    } else {
 +	info("%s: wiring: [DISPLAY:%s]<==>[i2c:DB%d]", Driver, name, w);
 +    }
 +
 +    w = 1 << w;
 +
 +    return w;
 +}
 +
 +void drv_generic_i2c_data(const unsigned char data)
 +{
 +
 +    my_i2c_smbus_write_byte_data(i2c_device, data);
 +
 +}
 +
 +void drv_generic_i2c_command(const unsigned char command, const unsigned char *data, const unsigned char length)
 +{
 +
 +    i2c_smbus_write_block_data(i2c_device,command,length,(unsigned char *)data);
 +
 +}
 diff --git a/drv_generic_i2c.h b/drv_generic_i2c.h index 64f4ed0..dd885be 100644 --- a/drv_generic_i2c.h +++ b/drv_generic_i2c.h @@ -1,64 +1,77 @@ -/* $Id: drv_generic_i2c.h,v 1.2 2005/05/08 04:32:44 reinelt Exp $ - * - * generic driver helper for i2c displays - * - * Copyright (C) 2005 Luis F. Correia <luis.f.correia@seg-social.pt> - * Copyright (C) 2005 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> - * - * This file is part of LCD4Linux. - * - * LCD4Linux 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, or (at your option) - * any later version. - * - * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * +/* $Id: drv_generic_i2c.h,v 1.3 2005/05/31 20:42:55 lfcorreia Exp $
 + *
 + * generic driver helper for i2c displays
 + *
 + * Copyright (C) 2005 Luis F. Correia <luis.f.correia@seg-social.pt>
 + * Copyright (C) 2005 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 + *
 + * This file is part of LCD4Linux.
 + *
 + * LCD4Linux 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, or (at your option)
 + * any later version.
 + *
 + * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 + *
 + *
   * $Log: drv_generic_i2c.h,v $ - * Revision 1.2  2005/05/08 04:32:44  reinelt - * CodingStyle added and applied - * - * Revision 1.1  2005/03/28 19:39:23  reinelt - * HD44780/I2C patch from Luis merged (still does not work for me) - * - * - */ - -/*  - * - * exported fuctions: - * - * int drv_generic_i2c_open (void) - *   reads 'Port' entry from config and opens - *   the i2c port - *   returns 0 if ok, -1 on failure - * - * int drv_generic_i2c_close (void) - *   closes i2c port - *   returns 0 if ok, -1 on failure - * - * unsigned char drv_generic_i2c_wire (char *name, char *deflt) - *   reads wiring for one data signal from config - *   returns 1<<bitpos or 255 on error - * - * void drv_generic_i2c_data (unsigned char value) - *   put data bits on DB1..DB8 - */ - -#ifndef _DRV_GENERIC_I2C_H_ -#define _DRV_GENERIC_I2C_H_ - -int drv_generic_i2c_open(const char *section, const char *driver); -int drv_generic_i2c_close(void); -unsigned char drv_generic_i2c_wire(const char *name, const char *deflt); -void drv_generic_i2c_data(const unsigned char data); - -#endif + * Revision 1.3  2005/05/31 20:42:55  lfcorreia + * new file: lcd4linux_i2c.h + * avoid the problems detecting the proper I2C kernel include files + * + * rearrange all the other autoconf stuff to remove I2C detection + * + * new method by Paul Kamphuis to write to the I2C device + *
 + * Revision 1.2  2005/05/08 04:32:44  reinelt
 + * CodingStyle added and applied
 + *
 + * Revision 1.1  2005/03/28 19:39:23  reinelt
 + * HD44780/I2C patch from Luis merged (still does not work for me)
 + *
 + *
 + */
 +
 +/* 
 + *
 + * exported fuctions:
 + *
 + * int drv_generic_i2c_open (void)
 + *   reads 'Port' entry from config and opens
 + *   the i2c port
 + *   returns 0 if ok, -1 on failure
 + *
 + * int drv_generic_i2c_close (void)
 + *   closes i2c port
 + *   returns 0 if ok, -1 on failure
 + *
 + * unsigned char drv_generic_i2c_wire (char *name, char *deflt)
 + *   reads wiring for one data signal from config
 + *   returns 1<<bitpos or 255 on error
 + *
 + * void drv_generic_i2c_data (unsigned char value)
 + *   put data bits on DB1..DB8
 + *
 + * void drv_generic_i2c_command(unsigned char command, unsigned char *data,unsigned char length)
 + *   send command and the data to the i2c device
 + * 
 + */
 +
 +#ifndef _DRV_GENERIC_I2C_H_
 +#define _DRV_GENERIC_I2C_H_
 +
 +int drv_generic_i2c_open(const char *section, const char *driver);
 +int drv_generic_i2c_close(void);
 +unsigned char drv_generic_i2c_wire(const char *name, const char *deflt);
 +void drv_generic_i2c_data(const unsigned char data);
 +void drv_generic_i2c_command(const unsigned char command, const unsigned char *data, const unsigned char length);
 +
 +#endif
 diff --git a/lcd4linux_i2c.h b/lcd4linux_i2c.h new file mode 100644 index 0000000..6980419 --- /dev/null +++ b/lcd4linux_i2c.h @@ -0,0 +1,643 @@ +/* $Id: lcd4linux_i2c.h,v 1.1 2005/05/31 20:42:55 lfcorreia Exp $
 + *
 + * user space i2c sturctures and defines, taken from the official kernel i2c 
 + * includes to solve the problem when compiling user space application
 + * (lcd4linux) with kernel space includes.
 + * Should be removed when the kernel team decides on how to solve this
 + * user space/kernel space compilation problem in kernel 2.8 or so.
 + *
 + * Copyright (C) 2005 Paul Kamphuis <pk_richman@users.sourceforge.net>
 + * Copyright (C) 2005 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 + *
 + * taken from kernel includes i2c.h and i2c-dev.h to prevent using kernel includes
 + *   Copyright (C) 1995-2000 Simon G. Vogl
 + * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
 + *  Frodo Looijaard <frodol@dds.nl>
 + *
 + * This file is part of LCD4Linux.
 + *
 + * LCD4Linux 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, or (at your option)
 + * any later version.
 + *
 + * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 + *
 + *
 + * $Log: lcd4linux_i2c.h,v $ + * Revision 1.1  2005/05/31 20:42:55  lfcorreia + * new file: lcd4linux_i2c.h + * avoid the problems detecting the proper I2C kernel include files + * + * rearrange all the other autoconf stuff to remove I2C detection + * + * new method by Paul Kamphuis to write to the I2C device + *
 + */
 +
 +#ifndef _LCD4LINUX_I2C_H
 +#define _LCD4LINUX_I2C_H
 +
 +typedef signed int s32;
 +typedef signed int __s32;
 +typedef unsigned char u8;
 +typedef unsigned short u16;
 +typedef unsigned char __u8;
 +typedef unsigned short __u16;
 +typedef unsigned int u32;
 +typedef unsigned int __u32;
 +
 +/* --- General options ------------------------------------------------	*/
 +
 +struct i2c_msg;
 +struct i2c_algorithm;
 +struct i2c_adapter;
 +struct i2c_client;
 +struct i2c_driver;
 +struct i2c_client_address_data;
 +union i2c_smbus_data;
 +
 +/*
 + * The master routines are the ones normally used to transmit data to devices
 + * on a bus (or read from them). Apart from two basic transfer functions to 
 + * transmit one message at a time, a more complex version can be used to 
 + * transmit an arbitrary number of messages without interruption.
 + */
 +extern int i2c_master_send(struct i2c_client *,const char* ,int);
 +extern int i2c_master_recv(struct i2c_client *,char* ,int);
 +
 +/* Transfer num messages.
 + */
 +extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num);
 +
 +/*
 + * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor. 
 + * This is not tested/implemented yet and will change in the future.
 + */
 +extern int i2c_slave_send(struct i2c_client *,char*,int);
 +extern int i2c_slave_recv(struct i2c_client *,char*,int);
 +
 +
 +
 +/* This is the very generalized SMBus access routine. You probably do not
 +   want to use this, though; one of the functions below may be much easier,
 +   and probably just as fast. 
 +   Note that we use i2c_adapter here, because you do not need a specific
 +   smbus adapter to call this function. */
 +extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr, 
 +                           unsigned short flags,
 +                           char read_write, u8 command, int size,
 +                           union i2c_smbus_data * data);
 +
 +/* Now follow the 'nice' access routines. These also document the calling
 +   conventions of smbus_access. */
 +/*
 +extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
 +extern s32 i2c_smbus_read_byte(struct i2c_client * client);
 +extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value);
 +extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command);
 +extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
 +                                     u8 command, u8 value);
 +extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
 +extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
 +                                     u8 command, u16 value);
 +*/
 +/* Returns the number of bytes transferred */
 +/*
 +extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
 +				      u8 command, u8 length,
 +				      u8 *values);
 +extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
 +					 u8 command, u8 *values);
 +*/
 +
 +/*
 + * A driver is capable of handling one or more physical devices present on
 + * I2C adapters. This information is used to inform the driver of adapter
 + * events.
 + */
 +
 +/*flags for the driver struct: */
 +#define I2C_DF_NOTIFY	0x01		/* notify on bus (de/a)ttaches 	*/
 +
 +/*flags for the client struct: */
 +#define I2C_CLIENT_ALLOW_USE		0x01	/* Client allows access */
 +#define I2C_CLIENT_ALLOW_MULTIPLE_USE 	0x02  	/* Allow multiple access-locks */
 +						/* on an i2c_client */
 +#define I2C_CLIENT_PEC  0x04			/* Use Packet Error Checking */
 +#define I2C_CLIENT_TEN	0x10			/* we have a ten bit chip address	*/
 +						/* Must equal I2C_M_TEN below */
 +
 +/* i2c adapter classes (bitmask) */
 +#define I2C_CLASS_HWMON		(1<<0)	/* lm_sensors, ... */
 +#define I2C_CLASS_TV_ANALOG	(1<<1)	/* bttv + friends */
 +#define I2C_CLASS_TV_DIGITAL	(1<<2)	/* dvb cards */
 +#define I2C_CLASS_DDC		(1<<3)	/* i2c-matroxfb ? */
 +#define I2C_CLASS_CAM_ANALOG	(1<<4)	/* camera with analog CCD */
 +#define I2C_CLASS_CAM_DIGITAL	(1<<5)	/* most webcams */
 +#define I2C_CLASS_SOUND		(1<<6)	/* sound devices */
 +#define I2C_CLASS_ALL		(UINT_MAX) /* all of the above */
 +
 +/* i2c_client_address_data is the struct for holding default client
 + * addresses for a driver and for the parameters supplied on the
 + * command line
 + */
 +struct i2c_client_address_data {
 +	unsigned short *normal_i2c;
 +	unsigned short *normal_i2c_range;
 +	unsigned short *probe;
 +	unsigned short *probe_range;
 +	unsigned short *ignore;
 +	unsigned short *ignore_range;
 +	unsigned short *force;
 +};
 +
 +/* Internal numbers to terminate lists */
 +#define I2C_CLIENT_END		0xfffe
 +#define I2C_CLIENT_ISA_END	0xfffefffe
 +
 +/* The numbers to use to set I2C bus address */
 +#define ANY_I2C_BUS		0xffff
 +#define ANY_I2C_ISA_BUS		9191
 +
 +/* The length of the option lists */
 +#define I2C_CLIENT_MAX_OPTS 48
 +
 +
 +/* ----- functions exported by i2c.o */
 +
 +/* administration...
 + */
 +extern int i2c_add_adapter(struct i2c_adapter *);
 +extern int i2c_del_adapter(struct i2c_adapter *);
 +
 +extern int i2c_add_driver(struct i2c_driver *);
 +extern int i2c_del_driver(struct i2c_driver *);
 +
 +extern int i2c_attach_client(struct i2c_client *);
 +extern int i2c_detach_client(struct i2c_client *);
 +
 +/* New function: This is to get an i2c_client-struct for controlling the 
 +   client either by using i2c_control-function or having the 
 +   client-module export functions that can be used with the i2c_client
 +   -struct. */
 +extern struct i2c_client *i2c_get_client(int driver_id, int adapter_id, 
 +					struct i2c_client *prev);
 +
 +/* Should be used with new function
 +   extern struct i2c_client *i2c_get_client(int,int,struct i2c_client *);
 +   to make sure that client-struct is valid and that it is okay to access
 +   the i2c-client. 
 +   returns -EACCES if client doesn't allow use (default)
 +   returns -EBUSY if client doesn't allow multiple use (default) and 
 +   usage_count >0 */
 +extern int i2c_use_client(struct i2c_client *);
 +extern int i2c_release_client(struct i2c_client *);
 +
 +/* call the i2c_client->command() of all attached clients with
 + * the given arguments */
 +extern void i2c_clients_command(struct i2c_adapter *adap,
 +				unsigned int cmd, void *arg);
 +
 +/* returns -EBUSY if address has been taken, 0 if not. Note that the only
 +   other place at which this is called is within i2c_attach_client; so
 +   you can cheat by simply not registering. Not recommended, of course! */
 +extern int i2c_check_addr (struct i2c_adapter *adapter, int addr);
 +
 +/* Detect function. It iterates over all possible addresses itself.
 + * It will only call found_proc if some client is connected at the
 + * specific address (unless a 'force' matched);
 + */
 +extern int i2c_probe(struct i2c_adapter *adapter, 
 +		struct i2c_client_address_data *address_data,
 +		int (*found_proc) (struct i2c_adapter *, int, int));
 +
 +/* An ioctl like call to set div. parameters of the adapter.
 + */
 +extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
 +
 +/* This call returns a unique low identifier for each registered adapter,
 + * or -1 if the adapter was not registered. 
 + */
 +extern int i2c_adapter_id(struct i2c_adapter *adap);
 +extern struct i2c_adapter* i2c_get_adapter(int id);
 +extern void i2c_put_adapter(struct i2c_adapter *adap);
 +
 +
 +/* Return the functionality mask */
 +extern u32 i2c_get_functionality (struct i2c_adapter *adap);
 +
 +/* Return 1 if adapter supports everything we need, 0 if not. */
 +extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func);
 +
 +/*
 + * I2C Message - used for pure i2c transaction, also from /dev interface
 + */
 +struct i2c_msg {
 +	__u16 addr;	/* slave address			*/
 + 	__u16 flags;		
 +#define I2C_M_TEN	0x10	/* we have a ten bit chip address	*/
 +#define I2C_M_RD	0x01
 +#define I2C_M_NOSTART	0x4000
 +#define I2C_M_REV_DIR_ADDR	0x2000
 +#define I2C_M_IGNORE_NAK	0x1000
 +#define I2C_M_NO_RD_ACK		0x0800
 + 	__u16 len;		/* msg length				*/
 + 	__u8 *buf;		/* pointer to msg data			*/
 +};
 +
 +/* To determine what functionality is present */
 +
 +#define I2C_FUNC_I2C			0x00000001
 +#define I2C_FUNC_10BIT_ADDR		0x00000002
 +#define I2C_FUNC_PROTOCOL_MANGLING	0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
 +#define I2C_FUNC_SMBUS_HWPEC_CALC	0x00000008 /* SMBus 2.0 */
 +#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC  0x00000800 /* SMBus 2.0 */ 
 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */ 
 +#define I2C_FUNC_SMBUS_PROC_CALL_PEC	0x00002000 /* SMBus 2.0 */
 +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */
 +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL	0x00008000 /* SMBus 2.0 */
 +#define I2C_FUNC_SMBUS_QUICK		0x00010000 
 +#define I2C_FUNC_SMBUS_READ_BYTE	0x00020000 
 +#define I2C_FUNC_SMBUS_WRITE_BYTE	0x00040000 
 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA	0x00080000 
 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA	0x00100000 
 +#define I2C_FUNC_SMBUS_READ_WORD_DATA	0x00200000 
 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA	0x00400000 
 +#define I2C_FUNC_SMBUS_PROC_CALL	0x00800000 
 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA	0x01000000 
 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 
 +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK	0x04000000 /* I2C-like block xfer  */
 +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK	0x08000000 /* w/ 1-byte reg. addr. */
 +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2	 0x10000000 /* I2C-like block xfer  */
 +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC  0x40000000 /* SMBus 2.0 */
 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
 +
 +#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
 +                            I2C_FUNC_SMBUS_WRITE_BYTE
 +#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \
 +                                 I2C_FUNC_SMBUS_WRITE_BYTE_DATA
 +#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \
 +                                 I2C_FUNC_SMBUS_WRITE_WORD_DATA
 +#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
 +                                  I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
 +#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
 +                                  I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
 +#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
 +                                   I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2
 +#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
 +                                      I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC
 +#define I2C_FUNC_SMBUS_WORD_DATA_PEC  I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
 +                                      I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC
 +
 +#define I2C_FUNC_SMBUS_READ_BYTE_PEC		I2C_FUNC_SMBUS_READ_BYTE_DATA
 +#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC		I2C_FUNC_SMBUS_WRITE_BYTE_DATA
 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC	I2C_FUNC_SMBUS_READ_WORD_DATA
 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC	I2C_FUNC_SMBUS_WRITE_WORD_DATA
 +#define I2C_FUNC_SMBUS_BYTE_PEC			I2C_FUNC_SMBUS_BYTE_DATA
 +#define I2C_FUNC_SMBUS_BYTE_DATA_PEC		I2C_FUNC_SMBUS_WORD_DATA
 +
 +#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
 +                            I2C_FUNC_SMBUS_BYTE | \
 +                            I2C_FUNC_SMBUS_BYTE_DATA | \
 +                            I2C_FUNC_SMBUS_WORD_DATA | \
 +                            I2C_FUNC_SMBUS_PROC_CALL | \
 +                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
 +                            I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
 +                            I2C_FUNC_SMBUS_I2C_BLOCK
 +
 +/* 
 + * Data for SMBus Messages 
 + */
 +#define I2C_SMBUS_BLOCK_MAX	32	/* As specified in SMBus standard */	
 +#define I2C_SMBUS_I2C_BLOCK_MAX	32	/* Not specified but we use same structure */
 +union i2c_smbus_data {
 +	__u8 byte;
 +	__u16 word;
 +	__u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */
 +                          /* one more for read length in block process call */
 +	                                            /* and one more for PEC */
 +};
 +
 +/* smbus_access read or write markers */
 +#define I2C_SMBUS_READ	1
 +#define I2C_SMBUS_WRITE	0
 +
 +/* SMBus transaction types (size parameter in the above functions) 
 +   Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
 +#define I2C_SMBUS_QUICK		    0
 +#define I2C_SMBUS_BYTE		    1
 +#define I2C_SMBUS_BYTE_DATA	    2 
 +#define I2C_SMBUS_WORD_DATA	    3
 +#define I2C_SMBUS_PROC_CALL	    4
 +#define I2C_SMBUS_BLOCK_DATA	    5
 +#define I2C_SMBUS_I2C_BLOCK_DATA    6
 +#define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
 +#define I2C_SMBUS_BLOCK_DATA_PEC    8		/* SMBus 2.0 */
 +#define I2C_SMBUS_PROC_CALL_PEC     9		/* SMBus 2.0 */
 +#define I2C_SMBUS_BLOCK_PROC_CALL_PEC  10	/* SMBus 2.0 */
 +#define I2C_SMBUS_WORD_DATA_PEC	   11		/* SMBus 2.0 */
 +
 +
 +/* ----- commands for the ioctl like i2c_command call:
 + * note that additional calls are defined in the algorithm and hw 
 + *	dependent layers - these can be listed here, or see the 
 + *	corresponding header files.
 + */
 +				/* -> bit-adapter specific ioctls	*/
 +#define I2C_RETRIES	0x0701	/* number of times a device address      */
 +				/* should be polled when not            */
 +                                /* acknowledging 			*/
 +#define I2C_TIMEOUT	0x0702	/* set timeout - call with int 		*/
 +
 +
 +/* this is for i2c-dev.c	*/
 +#define I2C_SLAVE	0x0703	/* Change slave address			*/
 +				/* Attn.: Slave address is 7 or 10 bits */
 +#define I2C_SLAVE_FORCE	0x0706	/* Change slave address			*/
 +				/* Attn.: Slave address is 7 or 10 bits */
 +				/* This changes the address, even if it */
 +				/* is already taken!			*/
 +#define I2C_TENBIT	0x0704	/* 0 for 7 bit addrs, != 0 for 10 bit	*/
 +
 +#define I2C_FUNCS	0x0705	/* Get the adapter functionality */
 +#define I2C_RDWR	0x0707	/* Combined R/W transfer (one stop only)*/
 +#define I2C_PEC		0x0708	/* != 0 for SMBus PEC                   */
 +#if 0
 +#define I2C_ACK_TEST	0x0710	/* See if a slave is at a specific address */
 +#endif
 +
 +#define I2C_SMBUS	0x0720	/* SMBus-level access */
 +
 +/* ... algo-bit.c recognizes */
 +#define I2C_UDELAY	0x0705	/* set delay in microsecs between each	*/
 +				/* written byte (except address)	*/
 +#define I2C_MDELAY	0x0706	/* millisec delay between written bytes */
 +
 +/* ----- I2C-DEV: char device interface stuff ------------------------- */
 +
 +#define I2C_MAJOR	89		/* Device major number		*/
 +
 +/* These defines are used for probing i2c client addresses */
 +/* Default fill of many variables */
 +#define I2C_CLIENT_DEFAULTS {I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END, \
 +                          I2C_CLIENT_END, I2C_CLIENT_END, I2C_CLIENT_END}
 +
 +/* This is ugly. We need to evaluate I2C_CLIENT_MAX_OPTS before it is 
 +   stringified */
 +#define I2C_CLIENT_MODPARM_AUX1(x) "1-" #x "h"
 +#define I2C_CLIENT_MODPARM_AUX(x) I2C_CLIENT_MODPARM_AUX1(x)
 +#define I2C_CLIENT_MODPARM I2C_CLIENT_MODPARM_AUX(I2C_CLIENT_MAX_OPTS)
 +
 +/* I2C_CLIENT_MODULE_PARM creates a module parameter, and puts it in the
 +   module header */
 +
 +#define I2C_CLIENT_MODULE_PARM(var,desc) \
 +  static unsigned short var[I2C_CLIENT_MAX_OPTS] = I2C_CLIENT_DEFAULTS; \
 +  static unsigned int var##_num; \
 +  /*MODULE_PARM(var,I2C_CLIENT_MODPARM);*/ \
 +  module_param_array(var, short, &var##_num, 0); \
 +  MODULE_PARM_DESC(var,desc)
 +
 +/* This is the one you want to use in your own modules */
 +#define I2C_CLIENT_INSMOD \
 +  I2C_CLIENT_MODULE_PARM(probe, \
 +                      "List of adapter,address pairs to scan additionally"); \
 +  I2C_CLIENT_MODULE_PARM(probe_range, \
 +                      "List of adapter,start-addr,end-addr triples to scan " \
 +                      "additionally"); \
 +  I2C_CLIENT_MODULE_PARM(ignore, \
 +                      "List of adapter,address pairs not to scan"); \
 +  I2C_CLIENT_MODULE_PARM(ignore_range, \
 +                      "List of adapter,start-addr,end-addr triples not to " \
 +                      "scan"); \
 +  I2C_CLIENT_MODULE_PARM(force, \
 +                      "List of adapter,address pairs to boldly assume " \
 +                      "to be present"); \
 +	static struct i2c_client_address_data addr_data = {		\
 +			.normal_i2c = 		normal_i2c,		\
 +			.normal_i2c_range =	normal_i2c_range,	\
 +			.probe =		probe,			\
 +			.probe_range =		probe_range,		\
 +			.ignore =		ignore,			\
 +			.ignore_range =		ignore_range,		\
 +			.force =		force,			\
 +		}
 +
 +/* Detect whether we are on the isa bus. If this returns true, all i2c
 +   access will fail! */
 +#define i2c_is_isa_client(clientptr) \
 +        ((clientptr)->adapter->algo->id == I2C_ALGO_ISA)
 +#define i2c_is_isa_adapter(adapptr) \
 +        ((adapptr)->algo->id == I2C_ALGO_ISA)
 +
 +
 +/* Some IOCTL commands are defined in <linux/i2c.h> */
 +/* Note: 10-bit addresses are NOT supported! */
 +
 +/* This is the structure as used in the I2C_SMBUS ioctl call */
 +struct i2c_smbus_ioctl_data {
 +        __u8 read_write;
 +        __u8 command;
 +        __u32 size;
 +        union i2c_smbus_data *data;
 +};
 +
 +/* This is the structure as used in the I2C_RDWR ioctl call */
 +struct i2c_rdwr_ioctl_data {
 +        struct i2c_msg *msgs;    /* pointers to i2c_msgs */
 +        __u32 nmsgs;                    /* number of i2c_msgs */
 +};
 +
 +#define  I2C_RDRW_IOCTL_MAX_MSGS        42
 +
 +#include <sys/ioctl.h>
 +
 +static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
 +                                     int size, union i2c_smbus_data *data)
 +{
 +	struct i2c_smbus_ioctl_data args;
 +
 +	args.read_write = read_write;
 +	args.command = command;
 +	args.size = size;
 +	args.data = data;
 +	return ioctl(file,I2C_SMBUS,&args);
 +}
 +
 +
 +static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
 +{
 +	return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
 +}
 +	
 +static inline __s32 i2c_smbus_read_byte(int file)
 +{
 +	union i2c_smbus_data data;
 +	if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
 +		return -1;
 +	else
 +		return 0x0FF & data.byte;
 +}
 +
 +static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
 +{
 +	return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
 +	                        I2C_SMBUS_BYTE,NULL);
 +}
 +
 +static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
 +{
 +	union i2c_smbus_data data;
 +	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
 +	                     I2C_SMBUS_BYTE_DATA,&data))
 +		return -1;
 +	else
 +		return 0x0FF & data.byte;
 +}
 +
 +static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
 +                                              __u8 value)
 +{
 +	union i2c_smbus_data data;
 +	data.byte = value;
 +	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 +	                        I2C_SMBUS_BYTE_DATA, &data);
 +}
 +
 +static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
 +{
 +	union i2c_smbus_data data;
 +	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
 +	                     I2C_SMBUS_WORD_DATA,&data))
 +		return -1;
 +	else
 +		return 0x0FFFF & data.word;
 +}
 +
 +static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
 +                                              __u16 value)
 +{
 +	union i2c_smbus_data data;
 +	data.word = value;
 +	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 +	                        I2C_SMBUS_WORD_DATA, &data);
 +}
 +
 +static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
 +{
 +	union i2c_smbus_data data;
 +	data.word = value;
 +	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 +	                     I2C_SMBUS_PROC_CALL,&data))
 +		return -1;
 +	else
 +		return 0x0FFFF & data.word;
 +}
 +
 +
 +/* Returns the number of read bytes */
 +static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
 +                                              __u8 *values)
 +{
 +	union i2c_smbus_data data;
 +	int i;
 +	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
 +	                     I2C_SMBUS_BLOCK_DATA,&data))
 +		return -1;
 +	else {
 +		for (i = 1; i <= data.block[0]; i++)
 +			values[i-1] = data.block[i];
 +		return data.block[0];
 +	}
 +}
 +
 +static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
 +                                               __u8 length, __u8 *values)
 +{
 +	union i2c_smbus_data data;
 +	int i;
 +	if (length > 32)
 +		length = 32;
 +	for (i = 1; i <= length; i++)
 +		data.block[i] = values[i-1];
 +	data.block[0] = length;
 +	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 +	                        I2C_SMBUS_BLOCK_DATA, &data);
 +}
 +
 +/* Returns the number of read bytes */
 +static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
 +                                                  __u8 *values)
 +{
 +	union i2c_smbus_data data;
 +	int i;
 +	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
 +	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))
 +		return -1;
 +	else {
 +		for (i = 1; i <= data.block[0]; i++)
 +			values[i-1] = data.block[i];
 +		return data.block[0];
 +	}
 +}
 +
 +static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
 +                                               __u8 length, __u8 *values)
 +{
 +	union i2c_smbus_data data;
 +	int i;
 +	if (length > 32)
 +		length = 32;
 +	for (i = 1; i <= length; i++)
 +		data.block[i] = values[i-1];
 +	data.block[0] = length;
 +	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 +	                        I2C_SMBUS_I2C_BLOCK_DATA, &data);
 +}
 +
 +/* Returns the number of read bytes */
 +static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
 +                                                 __u8 length, __u8 *values)
 +{
 +	union i2c_smbus_data data;
 +	int i;
 +	if (length > 32)
 +		length = 32;
 +	for (i = 1; i <= length; i++)
 +		data.block[i] = values[i-1];
 +	data.block[0] = length;
 +	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
 +	                     I2C_SMBUS_BLOCK_PROC_CALL,&data))
 +		return -1;
 +	else {
 +		for (i = 1; i <= data.block[0]; i++)
 +			values[i-1] = data.block[i];
 +		return data.block[0];
 +	}
 +}
 +
 +
 +#endif /* _LCD4LINUX_I2C_H */
 | 
