From 77d259034099fff8737a1d5af47e8edf8d84efc0 Mon Sep 17 00:00:00 2001 From: reinelt <> 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 --- drv_HD44780.c | 596 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 346 insertions(+), 250 deletions(-) (limited to 'drv_HD44780.c') 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