From 5985c204a32bd6b9f69646dbe6110ffa0c55651b Mon Sep 17 00:00:00 2001
From: reinelt <reinelt@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>
Date: Mon, 28 Mar 2005 22:29:23 +0000
Subject: [lcd4linux @ 2005-03-28 22:29:23 by reinelt] HD44780 multiple
 displays patch from geronet

git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@520 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
---
 drv_HD44780.c | 596 ++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 346 insertions(+), 250 deletions(-)

diff --git a/drv_HD44780.c b/drv_HD44780.c
index 0771aa2..c47370a 100644
--- a/drv_HD44780.c
+++ b/drv_HD44780.c
@@ -1,4 +1,4 @@
-/* $Id: drv_HD44780.c,v 1.46 2005/03/28 19:39:23 reinelt Exp $
+/* $Id: drv_HD44780.c,v 1.47 2005/03/28 22:29:23 reinelt Exp $
  *
  * new style driver for HD44780-based displays
  *
@@ -32,6 +32,9 @@
  *
  *
  * $Log: drv_HD44780.c,v $
+ * 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)
  *
@@ -287,7 +290,7 @@ static int Capabilities;
 #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 1680 /* Clear Display */
+#define T_CLEAR 2250 /* Clear Display */
 
 
 static int Bits=0;
@@ -295,10 +298,16 @@ 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;
 
@@ -361,17 +370,17 @@ static void (*drv_HD_stop)    (void);
 /***  parport dependant functions     ***/
 /****************************************/
 
-static void drv_HD_PP_busy(const int controller)
+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) {
+  if (Bits == 8) {
     busymask = 0x80;
   } else {
     /* Since in 4-Bit mode DB0 on the parport is mapped to DB4 on the LCD
@@ -380,93 +389,96 @@ static void drv_HD_PP_busy(const int controller)
      */
     busymask = 0x08;
   }
-
-  ctrlmask = 0x02;
-  while (ctrlmask > 0 ) {
+  
+  ctrlmask = 0x08;
+  while (ctrlmask > 0) {
     
     if (controller & ctrlmask) {
-
+      
       enable = 0;
-      if      (ctrlmask & 0x01) enable = SIGNAL_ENABLE; 
+      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);
+      if (Bits == 8) {
+	/* Set RW, clear RS */
+	drv_generic_parport_control(SIGNAL_RW|SIGNAL_RS, SIGNAL_RW);
       } else {
-        drv_generic_parport_data(SIGNAL_RW);
+	drv_generic_parport_data(SIGNAL_RW);
       }
       
       /* Address set-up time */
       ndelay(T_AS);
       
       /* rise ENABLE */
-      if (Bits==8) {
-        drv_generic_parport_control(enable,enable);
+      if (Bits == 8) {
+	drv_generic_parport_control(enable,enable);
       } else {
-        drv_generic_parport_data(SIGNAL_RW|enable);
+	drv_generic_parport_data(SIGNAL_RW|enable);
       }
-
+      
       counter=0;
       while (1) {
-        /* read the busy flag */
-        data = drv_generic_parport_read();
-        if ((data & busymask) == 0) {
+	/* 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);
+	
+	/* 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;
-          }
-        }
+	    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);
+	/* 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);
+	/* 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);
     }
@@ -475,23 +487,24 @@ static void drv_HD_PP_busy(const int controller)
 }
 
 
-static void drv_HD_PP_nibble(const unsigned char controller, const unsigned char nibble)
+static void drv_HD_PP_nibble (const unsigned char controller, const unsigned char nibble)
 {
   unsigned char enable;
-
+  
   /* enable signal: 'controller' is a bitmask */
-  /* bit 0 .. send to controller #0 */
-  /* bit 1 .. send to controller #1 */
-  /* so we can send a byte to both controllers at the same time! */
+  /* 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 & 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);
   
@@ -500,7 +513,7 @@ static void drv_HD_PP_nibble(const unsigned char controller, const unsigned char
   
   /* Enable pulse width */
   ndelay(T_PW);
-
+  
   /* lower ENABLE */
   drv_generic_parport_data(nibble);
 }
@@ -509,53 +522,54 @@ static void drv_HD_PP_nibble(const unsigned char controller, const unsigned char
 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);
-
+  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);
+  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) {
+  
+  if (UseBusy) drv_HD_PP_busy (controller);
+  
+  if (Bits == 8) {
     
     /* enable signal: 'controller' is a bitmask */
-    /* bit 0 .. send to controller #0 */
-    /* bit 1 .. send to controller #1 */
-    /* so we can send a byte to both controllers at the same time! */
+    /* 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 & 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);
-
+  if (!UseBusy) udelay (delay);
+  
 }
 
 
@@ -563,19 +577,20 @@ static void drv_HD_PP_data (const unsigned char controller, const char *string,
 {
   int l = len;
   unsigned char enable;
-
+  
   /* sanity check */
-  if (len<=0) return;
-
-  if (Bits==8) {
-
+  if (len <= 0) return;
+  
+  if (Bits == 8) {
+    
     /* enable signal: 'controller' is a bitmask */
-    /* bit 0 .. send to controller #0 */
-    /* bit 1 .. send to controller #1 */
-    /* so we can send a byte to both controllers at the same time! */
+    /* 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 & 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 */
@@ -585,9 +600,9 @@ static void drv_HD_PP_data (const unsigned char controller, const char *string,
     }
     
     while (l--) {
-
+      
       if (UseBusy) {
-	drv_HD_PP_busy(controller);
+	drv_HD_PP_busy (controller);
 	/* clear RW, set RS */
 	drv_generic_parport_control (SIGNAL_RW | SIGNAL_RS, SIGNAL_RS);
 	/* Address set-up time */
@@ -601,19 +616,19 @@ static void drv_HD_PP_data (const unsigned char controller, const char *string,
       drv_generic_parport_toggle (enable, 1, T_PW);
       
       /* wait for command completion */
-      if (!UseBusy) udelay(delay);
+      if (!UseBusy) udelay (delay);
     }
     
   } else { /* 4 bit mode */
     
     while (l--) {
-      if (UseBusy) drv_HD_PP_busy(controller);
-
+      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);
+      if (!UseBusy) udelay (delay);
     }
   }
 }
@@ -621,8 +636,9 @@ static void drv_HD_PP_data (const unsigned char controller, const char *string,
 
 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) {
+  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;
   }    
@@ -634,11 +650,11 @@ static int drv_HD_PP_load (const char *section)
   }
   info ("%s: using %d bit mode", Name, Bits);
   
-  if (drv_generic_parport_open(section, Name) != 0) {
+  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 */
@@ -646,25 +662,31 @@ static int drv_HD_PP_load (const char *section)
     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 (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_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;
+    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;
@@ -672,11 +694,18 @@ static int drv_HD_PP_load (const char *section)
   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_BACKLIGHT|SIGNAL_GPO, 0);
+    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);
   }
@@ -684,41 +713,41 @@ static int drv_HD_PP_load (const char *section)
   /* set direction: write */
   drv_generic_parport_direction (0);
   
-  /* initialize *both* displays */
-  if (Bits==8) {
+  /* 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 */
+    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)   {
+  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)) {
+  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))   {
+  if (!UseBusy && (Capabilities & CAP_LCM162)) {
     error("%s: Model '%s' should definitely use busy-flag checking!", Name, Models[Model].name);
   }
   
@@ -729,12 +758,19 @@ static int drv_HD_PP_load (const char *section)
 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_BACKLIGHT|SIGNAL_GPO, 0);
+  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();
   
 }
@@ -750,16 +786,17 @@ static void drv_HD_PP_stop (void)
 static void drv_HD_I2C_nibble (unsigned char controller, unsigned char nibble)
 {
   unsigned char enable;
-
+  
   /* enable signal: 'controller' is a bitmask */
-  /* bit 0 .. send to controller #0 */
-  /* bit 1 .. send to controller #1 */
-  /* so we can send a byte to both controllers at the same time! */
+  /* 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! */
@@ -769,13 +806,13 @@ static void drv_HD_I2C_nibble (unsigned char controller, unsigned char nibble)
   ndelay(T_AS);
   
   /* rise ENABLE */
-   drv_generic_i2c_data(nibble | enable);
+  drv_generic_i2c_data(nibble | enable);
   
   /* Enable pulse width */
   ndelay(T_PW);
   
   /* lower ENABLE */
-   drv_generic_i2c_data(nibble);
+  drv_generic_i2c_data(nibble);
   
   /* Address hold time */
   ndelay(T_H);
@@ -787,10 +824,10 @@ static void drv_HD_I2C_byte (const unsigned char controller, const unsigned char
   /* 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);
 }
@@ -800,11 +837,11 @@ static void drv_HD_I2C_command (const unsigned char controller, const unsigned c
 {
   /* 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);
 }
@@ -812,14 +849,14 @@ static void drv_HD_I2C_command (const unsigned char controller, const unsigned c
 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);
   }
@@ -840,7 +877,7 @@ static int drv_HD_I2C_load (const char *section)
     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;
@@ -853,9 +890,9 @@ static int drv_HD_I2C_load (const char *section)
   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;
 }
 
@@ -864,7 +901,7 @@ static void drv_HD_I2C_stop (void)
 {
   /* clear all signals */
   drv_generic_i2c_data (0);
-
+  
   /* close port */
   drv_generic_i2c_close();
 }
@@ -878,24 +915,34 @@ static void drv_HD_I2C_stop (void)
 
 static void drv_HD_clear (void)
 {
-  drv_HD_command (allControllers, 0x01, T_CLEAR); /* clear *both* displays */
+  drv_HD_command (allControllers, 0x01, T_CLEAR); /* clear *all* displays */
 }
 
 
-static void drv_HD_goto (int row, int col)
+static int drv_HD_goto (int row, int col)
 {
-  int pos;
-
-  /* handle multiple displays/controllers */
-  if (numControllers > 1 && row >= DROWS/2) {
-    row -= DROWS/2;
-    currController = 2;
-  } else {
-    currController = 1;
+  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 (DCOLS == 16 && DROWS == 1 && col > 7) {
+  if (CCOLS[controller] == 16 && CROWS[controller] == 1 && col > 7) {
     row++;
     col -= 8;
   }
@@ -904,21 +951,27 @@ static void drv_HD_goto (int row, int col)
     /* the HD66712 doesn't have a braindamadged RAM layout */
     pos = row*32 + col;
   } else {
-    /* 16x4 Displays use a slightly different layout */
-    if (DCOLS == 16 && DROWS == 4) {
+    /* 16x4 Controllers use a slightly different layout */
+    if (CCOLS[controller] == 16 && CROWS[controller] == 4) {
       pos = (row%2)*64 + (row/2)*16 + col;
-    } else {  
+    } else {
       pos = (row%2)*64 + (row/2)*20 + col;
     }
   }
-  drv_HD_command (currController, (0x80|pos), T_EXEC);
+  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)
 {
-  drv_HD_goto (row, col);
-  drv_HD_data (currController, data, len, T_EXEC);
+  int space = drv_HD_goto (row, col);
+  if (space > 0) {
+    drv_HD_data (currController, data, len > space ? space : len, T_EXEC);
+  }
 }
 
 
@@ -926,13 +979,13 @@ 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 *both* controllers! */
-  drv_HD_command (allControllers, 0x40|8*ascii, T_EXEC);
+  /* define chars on *all* controllers! */
+  drv_HD_command (allControllers, 0x40 | 8 * ascii, T_EXEC);
   drv_HD_data (allControllers, buffer, 8, T_WRCG);
 }
 
@@ -940,39 +993,39 @@ static void drv_HD_defchar (const int ascii, const unsigned char *matrix)
 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;
-
+  
+  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) {
+  if (Lcd.gpos > 0) {
     
     /* put data on DB1..DB8 */
     drv_generic_parport_data (bits);
@@ -991,27 +1044,27 @@ static void drv_HD_setGPO (const int bits)
 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);
   }
 }
@@ -1020,15 +1073,17 @@ static void drv_HD_LCM162_timer (void __attribute__((unused)) *notused)
 static int drv_HD_start (const char *section, const int quiet)
 {
   char *model, *size, *bus;
-  int rows=-1, cols=-1, gpos=-1;
-  
+  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') {
+  if (model != NULL && *model != '\0') {
     int i;
-    for (i=0; Models[i].type!=0xff; i++) {
-      if (strcasecmp(Models[i].name, model)==0) break;
+    for (i = 0; Models[i].type != 0xff; i++) {
+      if (strcasecmp (Models[i].name, model) == 0) break;
     }
-    if (Models[i].type==0xff) {
+    if (Models[i].type == 0xff) {
       error ("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
       return -1;
     }
@@ -1041,15 +1096,15 @@ static int drv_HD_start (const char *section, const int quiet)
     return -1;
   }
   free (model);
-
+  
   bus=cfg_get(section, "Bus", "parport");
-  if (bus==NULL && *bus=='\0') {
+  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) {
+  
+  if (strcasecmp (bus, "parport") == 0) {
     info ("%s: using parallel port", Name);
     Bus = BUS_PP;
     drv_HD_load    = drv_HD_PP_load;
@@ -1071,13 +1126,13 @@ static int drv_HD_start (const char *section, const int quiet)
     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);
@@ -1086,31 +1141,73 @@ static int drv_HD_start (const char *section, const int quiet)
   }
   free(bus);
   
-  size=cfg_get(section, "Size", NULL);
-  if (size==NULL || *size=='\0') {
-    error ("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
+  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);
-    return -1;
+    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 (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);
+  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;
   }
-  free(size);
-  DROWS = rows;
-  DCOLS = cols;
-  
-  if (cfg_number(section, "Controllers", 1, 1, 2, &numControllers)<0) return -1;
-  info ("%s: using %d controller(s)", Name, numControllers);
   
-  /* current controller */
-  currController=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);
   
-  /* Bitmask for *all* Controllers */
-  allControllers = numControllers==2 ? 3 : 1;
   
-  if (cfg_number(section, "GPOs", 0, 0, 8, &gpos)<0) return -1;
+  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;
@@ -1120,42 +1217,42 @@ static int drv_HD_start (const char *section, const int quiet)
     info ("%s: using %d GPO's", Name, GPOS);
   }
   
-  if (drv_HD_load(section) < 0) {
+  if (drv_HD_load (section) < 0) {
     error ("%s: start display failed!", Name);
     return -1;
   }
   
-  drv_HD_command (allControllers, 0x08, T_EXEC);  /* Display off, cursor off, blink off */
+  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_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 *both* displays */
+  
+  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) {
+    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) {
+    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);
@@ -1169,7 +1266,7 @@ static int drv_HD_start (const char *section, const int quiet)
       drv_HD_clear();
     }
   }
-    
+  
   return 0;
 }
 
@@ -1217,7 +1314,7 @@ int drv_HD_list (void)
 {
   int i;
   
-  for (i=0; Models[i].type!=0xff; i++) {
+  for (i = 0; Models[i].type != 0xff; i++) {
     printf ("%s ", Models[i].name);
   }
   return 0;
@@ -1241,8 +1338,8 @@ int drv_HD_init (const char *section, const int quiet)
   /* 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;
@@ -1250,7 +1347,7 @@ int drv_HD_init (const char *section, const int quiet)
   /* 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;
@@ -1296,13 +1393,14 @@ int drv_HD_init (const char *section, const int quiet)
 
 
 /* close driver & display */
-int drv_HD_quit (const int quiet) {
-
+int drv_HD_quit (const int quiet)
+{
+  
   info("%s: shutting down.", Name);
-
+  
   drv_generic_text_quit();
-
-  /* clear *both* displays */
+  
+  /* clear display */
   drv_HD_clear();
   
   /* say goodbye... */
@@ -1322,5 +1420,3 @@ DRIVER drv_HD44780 = {
   init: drv_HD_init,
   quit: drv_HD_quit, 
 };
-
-
-- 
cgit v1.2.3