diff options
author | reinelt <> | 2003-04-04 06:02:04 +0000 |
---|---|---|
committer | reinelt <> | 2003-04-04 06:02:04 +0000 |
commit | 43f6cfacf15926a6538fc8c8a7e46430851aaa67 (patch) | |
tree | deb1bbf2bbb8fb7a9d610520b2d1453c91d0da20 | |
parent | 898186678d7b2680f915cd1c3cca57bd27333f72 (diff) | |
download | lcd4linux-43f6cfacf15926a6538fc8c8a7e46430851aaa67.tar.gz |
[lcd4linux @ 2003-04-04 06:01:59 by reinelt]
new parallel port abstraction scheme
-rw-r--r-- | HD44780.c | 311 | ||||
-rw-r--r-- | M50530.c | 149 | ||||
-rw-r--r-- | USBLCD.c | 6 | ||||
-rwxr-xr-x | configure | 18 | ||||
-rw-r--r-- | configure.in | 16 | ||||
-rw-r--r-- | parport.c | 346 | ||||
-rw-r--r-- | parport.h | 38 | ||||
-rw-r--r-- | udelay.c | 7 |
8 files changed, 516 insertions, 375 deletions
@@ -1,4 +1,4 @@ -/* $Id: HD44780.c,v 1.26 2003/02/22 07:53:09 reinelt Exp $ +/* $Id: HD44780.c,v 1.27 2003/04/04 06:01:59 reinelt Exp $ * * driver for display modules based on the HD44780 chip * @@ -20,6 +20,9 @@ * * * $Log: HD44780.c,v $ + * Revision 1.27 2003/04/04 06:01:59 reinelt + * new parallel port abstraction scheme + * * Revision 1.26 2003/02/22 07:53:09 reinelt * cfg_get(key,defval) * @@ -150,38 +153,12 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <errno.h> -#include <sys/ioctl.h> - -#ifdef HAVE_SYS_IO_H -#include <sys/io.h> -#define WITH_OUTB -#else -#ifdef HAVE_ASM_IO_H -#include <asm/io.h> -#define WITH_OUTB -#endif -#endif - -#if defined (HAVE_LINUX_PARPORT_H) && defined (HAVE_LINUX_PPDEV_H) -#define WITH_PPDEV -#include <linux/parport.h> -#include <linux/ppdev.h> -#endif - - -#if !defined(WITH_OUTB) && !defined(WITH_PPDEV) -#error neither outb() nor ppdev() possible -#error cannot compile HD44780 driver -#endif #include "debug.h" #include "cfg.h" #include "display.h" #include "bar.h" +#include "parport.h" #include "udelay.h" #define XRES 5 @@ -190,203 +167,75 @@ static LCD Lcd; - -static unsigned short Port=0; - -static char *PPdev=NULL; - -#ifdef WITH_PPDEV -static int PPfd=-1; -#endif - static char Txt[4][40]; static int GPO=0; -#ifdef WITH_PPDEV -static void HD_toggle (int bit, int inv, int delay) -{ - struct ppdev_frob_struct frob; - frob.mask=bit; - - // rise - frob.val=inv?0:bit; - ioctl (PPfd, PPFCONTROL, &frob); - - // pulse width - ndelay(delay); +static unsigned char SIGNAL_RS; +static unsigned char SIGNAL_ENABLE; +static unsigned char SIGNAL_ENABLE_GPO; - // lower - frob.val=inv?bit:0; - ioctl (PPfd, PPFCONTROL, &frob); -} -#endif static void HD_command (unsigned char cmd, int delay) { -#ifdef WITH_PPDEV - if (PPdev) { - - struct ppdev_frob_struct frob; - - // put data on DB1..DB8 - ioctl(PPfd, PPWDATA, &cmd); - // clear RS (inverted) - frob.mask=PARPORT_CONTROL_AUTOFD; - frob.val=PARPORT_CONTROL_AUTOFD; - ioctl (PPfd, PPFCONTROL, &frob); + // put data on DB1..DB8 + parport_data (cmd); + + // clear RS + parport_control (SIGNAL_RS, 0); - // Address set-up time - ndelay(40); + // Address set-up time + ndelay(40); - // send command - // Enable cycle time = 230ns - HD_toggle(PARPORT_CONTROL_STROBE, 1, 230); + // send command + // Enable cycle time = 230ns + parport_toggle (SIGNAL_ENABLE, 1, 230); - // wait for command completion - udelay(delay); - - } else + // wait for command completion + udelay(delay); -#endif - - { - outb (cmd, Port); // put data on DB1..DB8 - outb (0x03, Port+2); // clear RS = bit 2 invertet - ndelay(40); // Address set-up time - outb (0x02, Port+2); // set Enable = bit 0 invertet - ndelay(230); // Enable cycle time - outb (0x03, Port+2); // clear Enable - udelay (delay); // wait for command completion - } } + static void HD_write (char *string, int len, int delay) { -#ifdef WITH_PPDEV - if (PPdev) { + // set RS + parport_control (SIGNAL_RS, SIGNAL_RS); - struct ppdev_frob_struct frob; - - // set RS (inverted) - frob.mask=PARPORT_CONTROL_AUTOFD; - frob.val=0; - ioctl (PPfd, PPFCONTROL, &frob); + // Address set-up time + ndelay(40); + + while (len--) { - // Address set-up time - ndelay(40); + // put data on DB1..DB8 + parport_data (*(string++)); - while (len--) { - - // put data on DB1..DB8 - ioctl(PPfd, PPWDATA, string++); - - // send command - HD_toggle(PARPORT_CONTROL_STROBE, 1, 230); - - // wait for command completion - udelay(delay); - } + // send command + // Enable cycle time = 230ns + parport_toggle (SIGNAL_ENABLE, 1, 230); - } else - -#endif - - { - outb (0x01, Port+2); // set RS = bit 2 invertet - ndelay(40); // Address set-up time - while (len--) { - outb (*string++, Port); // put data on DB1..DB8 - outb (0x00, Port+2); // set Enable = bit 0 invertet - ndelay(230); // Enable cycle time - outb (0x01, Port+2); // clear Enable - udelay (delay); - } - } + // wait for command completion + udelay(delay); + } } static void HD_setGPO (int bits) { if (Lcd.gpos>0) { - -#ifdef WITH_PPDEV - - - if (PPdev) { - - // put data on DB1..DB8 - ioctl(PPfd, PPWDATA, &bits); - - // 74HCT573 set-up time - ndelay(20); - - // toggle INIT - // 74HCT573 enable pulse width = 24ns - HD_toggle(PARPORT_CONTROL_INIT, 0, 24); - - } else - -#endif - - { - outb (bits, Port); // put data on DB1..DB8 - ndelay(20); // 74HCT573 set-up time - outb (0x05, Port+2); // set INIT = bit 2 invertet - ndelay(24); // 74HCT573 enable pulse width - outb (0x03, Port+2); // clear INIT - } + + // put data on DB1..DB8 + parport_data (bits); + + // 74HCT573 set-up time + ndelay(20); + + // send data + // 74HCT573 enable pulse width = 24ns + parport_toggle (SIGNAL_ENABLE_GPO, 1, 230); } } -static int HD_open (void) -{ -#ifdef WITH_PPDEV - - if (PPdev) { - debug ("using ppdev %s", PPdev); - PPfd=open(PPdev, O_RDWR); - if (PPfd==-1) { - error ("HD44780: open(%s) failed: %s", PPdev, strerror(errno)); - return -1; - } - -#if 0 - if (ioctl(PPfd, PPEXCL)) { - debug ("ioctl(%s, PPEXCL) failed: %s", PPdev, strerror(errno)); - } else { - debug ("ioctl(%s, PPEXCL) succeded."); - } -#endif - - if (ioctl(PPfd, PPCLAIM)) { - error ("HD44780: ioctl(%s, PPCLAIM) failed: %d %s", PPdev, errno, strerror(errno)); - return -1; - } - } else - -#endif - - { - debug ("using raw port 0x%x", Port); - if (ioperm(Port, 3, 1)!=0) { - error ("HD44780: ioperm(0x%x) failed: %s", Port, strerror(errno)); - return -1; - } - } - - HD_command (0x30, 4100); // 8 Bit mode, wait 4.1 ms - HD_command (0x30, 100); // 8 Bit mode, wait 100 us - HD_command (0x30, 4100); // 8 Bit mode, wait 4.1 ms - HD_command (0x38, 40); // 8 Bit mode, 1/16 duty cycle, 5x8 font - HD_command (0x08, 40); // Display off, cursor off, blink off - HD_command (0x0c, 1640); // Display on, cursor off, blink off, wait 1.64 ms - HD_command (0x06, 40); // curser moves to right, no shift - - return 0; -} - - static void HD_define_char (int ascii, char *buffer) { HD_command (0x40|8*ascii, 40); @@ -418,34 +267,6 @@ int HD_init (LCD *Self) int rows=-1, cols=-1, gpos=-1; char *s, *e; - s=cfg_get ("Port",NULL); - if (s==NULL || *s=='\0') { - error ("HD44780: no 'Port' entry in %s", cfg_file()); - return -1; - } - PPdev=NULL; - if ((Port=strtol(s, &e, 0))==0 || *e!='\0') { -#ifdef WITH_PPDEV - Port=0; - PPdev=s; -#else - error ("HD44780: bad port '%s' in %s", s, cfg_file()); - return -1; -#endif - } - -#ifdef USE_OLD_UDELAY - s=cfg_get ("Delay",NULL); - if (s==NULL || *s=='\0') { - error ("HD44780: no 'Delay' entry in %s", cfg_file()); - return -1; - } - if ((loops_per_usec=strtol(s, &e, 0))==0 || *e!='\0') { - error ("HD44780: bad delay '%s' in %s", s, cfg_file()); - return -1; - } -#endif - s=cfg_get("Size",NULL); if (s==NULL || *s=='\0') { error ("HD44780: no 'Size' entry in %s", cfg_file()); @@ -470,13 +291,24 @@ int HD_init (LCD *Self) Self->gpos=gpos; Lcd=*Self; -#ifndef USE_OLD_UDELAY - udelay_init(); -#endif + SIGNAL_RS=parport_wire ("RS", "AUTOFD"); + SIGNAL_ENABLE=parport_wire ("ENABLE", "STROBE"); + SIGNAL_ENABLE_GPO=parport_wire ("ENABLE_GPO", "INIT"); - if (HD_open()!=0) + if (parport_open() != 0) { + error ("HD44780: could not initialize parallel port!"); return -1; - + } + + HD_command (0x30, 4100); // 8 Bit mode, wait 4.1 ms + HD_command (0x30, 100); // 8 Bit mode, wait 100 us + HD_command (0x30, 4100); // 8 Bit mode, wait 4.1 ms + HD_command (0x38, 40); // 8 Bit mode, 1/16 duty cycle, 5x8 font + HD_command (0x08, 40); // Display off, cursor off, blink off + HD_command (0x0c, 1640); // Display on, cursor off, blink off, wait 1.64 ms + HD_command (0x06, 40); // curser moves to right, no shift + + bar_init(rows, cols, XRES, YRES, CHARS); bar_add_segment( 0, 0,255, 32); // ASCII 32 = blank bar_add_segment(255,255,255,255); // ASCII 255 = block @@ -562,26 +394,7 @@ int HD_flush (void) int HD_quit (void) { -#ifdef WITH_PPDEV - if (PPdev) { - debug ("closing ppdev %s", PPdev); - if (ioctl(PPfd, PPRELEASE)) { - error ("HD44780: ioctl(%s, PPRELEASE) failed: %s", PPdev, strerror(errno)); - } - if (close(PPfd)==-1) { - error ("HD44780: close(%s) failed: %s", PPdev, strerror(errno)); - return -1; - } - } else -#endif - { - debug ("closing raw port 0x%x", Port); - if (ioperm(Port, 3, 0)!=0) { - error ("HD44780: ioperm(0x%x) failed: %s", Port, strerror(errno)); - return -1; - } - } - return 0; + return parport_close(); } @@ -1,4 +1,4 @@ -/* $Id: M50530.c,v 1.6 2003/02/22 07:53:10 reinelt Exp $ +/* $Id: M50530.c,v 1.7 2003/04/04 06:01:59 reinelt Exp $ * * driver for display modules based on the M50530 chip * @@ -20,6 +20,9 @@ * * * $Log: M50530.c,v $ + * Revision 1.7 2003/04/04 06:01:59 reinelt + * new parallel port abstraction scheme + * * Revision 1.6 2003/02/22 07:53:10 reinelt * cfg_get(key,defval) * @@ -56,25 +59,12 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <errno.h> -#include <sys/ioctl.h> - -#if defined (HAVE_LINUX_PARPORT_H) && defined (HAVE_LINUX_PPDEV_H) -#define WITH_PPDEV -#include <linux/parport.h> -#include <linux/ppdev.h> -#else -#error The M50530 driver needs ppdev -#error cannot compile M50530 driver -#endif #include "debug.h" #include "cfg.h" #include "display.h" #include "bar.h" +#include "parport.h" #include "udelay.h" #define XRES 5 @@ -83,52 +73,34 @@ static LCD Lcd; - -static char *PPdev=NULL; -static int PPfd=-1; - static char Txt[8][40]; static int GPO=0; +static unsigned char SIGNAL_EX; +static unsigned char SIGNAL_IOC1; +static unsigned char SIGNAL_IOC2; +static unsigned char SIGNAL_ENABLE_GPO; static void M5_command (unsigned int cmd, int delay) { - unsigned char data; - struct ppdev_frob_struct frob; // put data on DB1..DB8 - data=cmd&0xff; - ioctl(PPfd, PPWDATA, &data); + parport_data (cmd&0xff); // set I/OC1 (Select inverted) // set I/OC2 (AutoFeed inverted) - frob.mask=PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD; - frob.val=0; - if (!(cmd & 0x200)) { - frob.val|=PARPORT_CONTROL_SELECT; - } - if (!(cmd & 0x100)) { - frob.val|=PARPORT_CONTROL_AUTOFD; - } - ioctl (PPfd, PPFCONTROL, &frob); + parport_control (SIGNAL_IOC1|SIGNAL_IOC2, + (cmd&0x200?SIGNAL_IOC1:0) | + (cmd&0x100?SIGNAL_IOC2:0)); // Control data setup time ndelay(200); - // rise EX (Strobe, inverted) - frob.mask=PARPORT_CONTROL_STROBE; - frob.val=0; - ioctl (PPfd, PPFCONTROL, &frob); - - // EX signal pulse width + // send command + // EX signal pulse width = 500ns // Fixme: why 500 ns? Datasheet says 200ns - ndelay(500); + parport_toggle (SIGNAL_EX, 1, 500); - // lower EX (Strobe, inverted) - frob.mask=PARPORT_CONTROL_STROBE; - frob.val=PARPORT_CONTROL_STROBE; - ioctl (PPfd, PPFCONTROL, &frob); - // wait udelay(delay); @@ -150,61 +122,19 @@ static void M5_setGPO (int bits) { if (Lcd.gpos>0) { - struct ppdev_frob_struct frob; - // put data on DB1..DB8 - ioctl(PPfd, PPWDATA, &bits); + parport_data (bits); // 74HCT573 set-up time ndelay(20); - // toggle INIT - frob.mask=PARPORT_CONTROL_INIT; - frob.val=PARPORT_CONTROL_INIT; // rise - ioctl (PPfd, PPFCONTROL, &frob); - - // 74HCT573 enable pulse width - ndelay(24); - - frob.val=0; // lower - ioctl (PPfd, PPFCONTROL, &frob); + // send data + // 74HCT573 enable pulse width = 24ns + parport_toggle (SIGNAL_ENABLE_GPO, 1, 24); } } -static int M5_open (void) -{ - - debug ("using ppdev %s", PPdev); - PPfd=open(PPdev, O_RDWR); - if (PPfd==-1) { - error ("open(%s) failed: %s", PPdev, strerror(errno)); - return -1; - } - -#if 0 - if (ioctl(PPfd, PPEXCL)) { - debug ("ioctl(%s, PPEXCL) failed: %s", PPdev, strerror(errno)); - } else { - debug ("ioctl(%s, PPEXCL) succeded."); - } -#endif - - if (ioctl(PPfd, PPCLAIM)) { - error ("ioctl(%s, PPCLAIM) failed: %d %s", PPdev, errno, strerror(errno)); - return -1; - } - - M5_command (0x00FA, 20); // set function mode - M5_command (0x0020, 20); // set display mode - M5_command (0x0050, 20); // set entry mode - M5_command (0x0030, 20); // set display mode - M5_command (0x0001, 1250); // clear display - - return 0; -} - - static void M5_define_char (int ascii, char *buffer) { M5_command (0x300+192+8*ascii, 20); @@ -237,18 +167,6 @@ int M5_init (LCD *Self) int rows=-1, cols=-1, gpos=-1; char *s, *e; - if (PPdev) { - free (PPdev); - PPdev=NULL; - } - - s=cfg_get ("Port",NULL); - if (s==NULL || *s=='\0') { - error ("M50530: no 'Port' entry in %s", cfg_file()); - return -1; - } - PPdev=strdup(s); - s=cfg_get("Size",NULL); if (s==NULL || *s=='\0') { error ("M50530: no 'Size' entry in %s", cfg_file()); @@ -275,14 +193,25 @@ int M5_init (LCD *Self) Self->gpos=gpos; Lcd=*Self; - udelay_init(); + SIGNAL_EX=parport_wire ("EX", "STROBE"); + SIGNAL_EX=parport_wire ("IOC1", "SELECT"); + SIGNAL_EX=parport_wire ("IOC2", "AUTOFD"); + SIGNAL_EX=parport_wire ("ENABLE_GPO", "INIT"); - if (M5_open()!=0) + if (parport_open() != 0) { + error ("M50530: could not initialize parallel port!"); return -1; + } + + M5_command (0x00FA, 20); // set function mode + M5_command (0x0020, 20); // set display mode + M5_command (0x0050, 20); // set entry mode + M5_command (0x0030, 20); // set display mode + M5_command (0x0001, 1250); // clear display bar_init(rows, cols, XRES, YRES, CHARS); bar_add_segment(0,0,255,32); // ASCII 32 = blank - + M5_clear(); return 0; @@ -366,15 +295,7 @@ int M5_flush (void) int M5_quit (void) { - debug ("closing ppdev %s", PPdev); - if (ioctl(PPfd, PPRELEASE)) { - error ("ioctl(%s, PPRELEASE) failed: %s", PPdev, strerror(errno)); - } - if (close(PPfd)==-1) { - error ("close(%s) failed: %s", PPdev, strerror(errno)); - return -1; - } - return 0; + return parport_close(); } @@ -1,4 +1,4 @@ -/* $Id: USBLCD.c,v 1.8 2003/02/22 07:53:10 reinelt Exp $ +/* $Id: USBLCD.c,v 1.9 2003/04/04 06:01:59 reinelt Exp $ * * Driver for USBLCD ( see http://www.usblcd.de ) * This Driver is based on HD44780.c @@ -22,6 +22,9 @@ * * * $Log: USBLCD.c,v $ + * Revision 1.9 2003/04/04 06:01:59 reinelt + * new parallel port abstraction scheme + * * Revision 1.8 2003/02/22 07:53:10 reinelt * cfg_get(key,defval) * @@ -79,7 +82,6 @@ #include "cfg.h" #include "display.h" #include "bar.h" -#include "udelay.h" #define GET_HARD_VERSION 1 #define GET_DRV_VERSION 2 @@ -4573,6 +4573,7 @@ echo "$as_me:$LINENO: result: done" >&5 echo "${ECHO_T}done" >&6 RASTER="no" +PARPORT="no" if test "$BECKMANNEGLE" = "yes"; then DRIVERS="$DRIVERS BeckmannEgle.o" @@ -4602,6 +4603,7 @@ _ACEOF fi if test "$HD44780" = "yes"; then + PARPORT="yes" DRIVERS="$DRIVERS HD44780.o" cat >>confdefs.h <<\_ACEOF @@ -4611,6 +4613,7 @@ _ACEOF fi if test "$M50530" = "yes"; then + PARPORT="yes" DRIVERS="$DRIVERS M50530.o" cat >>confdefs.h <<\_ACEOF @@ -4620,6 +4623,7 @@ _ACEOF fi if test "$T6963" = "yes"; then + PARPORT="yes" DRIVERS="$DRIVERS T6963.o" cat >>confdefs.h <<\_ACEOF @@ -4724,16 +4728,20 @@ _ACEOF fi fi +if test "$DRIVERS" = ""; then + { { echo "$as_me:$LINENO: error: You should include at least one driver..." >&5 +echo "$as_me: error: You should include at least one driver..." >&2;} + { (exit 1); exit 1; }; } +fi + # Raster.o depends on PPM or PNG if test "$RASTER" = "yes"; then DRIVERS="$DRIVERS Raster.o" fi - -if test "$DRIVERS" = ""; then - { { echo "$as_me:$LINENO: error: You should include at least one driver..." >&5 -echo "$as_me: error: You should include at least one driver..." >&2;} - { (exit 1); exit 1; }; } +# parport driver +if test "$PARPORT" = "yes"; then + DRIVERS="$DRIVERS parport.o" fi diff --git a/configure.in b/configure.in index 3d052a4..8648538 100644 --- a/configure.in +++ b/configure.in @@ -121,6 +121,7 @@ done AC_MSG_RESULT([done]) RASTER="no" +PARPORT="no" if test "$BECKMANNEGLE" = "yes"; then DRIVERS="$DRIVERS BeckmannEgle.o" @@ -138,16 +139,19 @@ if test "$CWLINUX" = "yes"; then fi if test "$HD44780" = "yes"; then + PARPORT="yes" DRIVERS="$DRIVERS HD44780.o" AC_DEFINE(WITH_HD44780,1,[junk]) fi if test "$M50530" = "yes"; then + PARPORT="yes" DRIVERS="$DRIVERS M50530.o" AC_DEFINE(WITH_M50530,1,[junk]) fi if test "$T6963" = "yes"; then + PARPORT="yes" DRIVERS="$DRIVERS T6963.o" AC_DEFINE(WITH_T6963,1,[junk]) fi @@ -209,16 +213,20 @@ if test "$X11" = "yes"; then fi fi +if test "$DRIVERS" = ""; then + AC_MSG_ERROR([You should include at least one driver...]) +fi + # Raster.o depends on PPM or PNG if test "$RASTER" = "yes"; then DRIVERS="$DRIVERS Raster.o" fi - -if test "$DRIVERS" = ""; then - AC_MSG_ERROR([You should include at least one driver...]) +# parport driver +if test "$PARPORT" = "yes"; then + DRIVERS="$DRIVERS parport.o" fi - + AC_SUBST(DRIVERS) AC_SUBST(DRVLIBS) diff --git a/parport.c b/parport.c new file mode 100644 index 0000000..6e7cbe4 --- /dev/null +++ b/parport.c @@ -0,0 +1,346 @@ +/* $Id: parport.c,v 1.1 2003/04/04 06:02:03 reinelt Exp $ + * + * generic parallel port handling + * + * Copyright 2003 by Michael Reinelt (reinelt@eunet.at) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * $Log: parport.c,v $ + * Revision 1.1 2003/04/04 06:02:03 reinelt + * new parallel port abstraction scheme + * + */ + +/* + * exported functions: + * + * int parport_open (void) + * reads 'Port' entry from config and opens + * the parallel port + * returns 0 if ok, -1 on failure + * + * int parport_close (void) + * closes parallel port + * returns 0 if ok, -1 on failure + * + * unsigned char parport_wire (char *name, char *deflt) + * reads wiring for one control signal from config + * returns PARPORT_CONTROL_* or 255 on error + * + * void parport_control (unsigned char mask, unsigned char value) + * frobs control line and takes care of inverted signals + * + * void parport_toggle (unsigned char bit, int level, int delay) + * toggles the line <bit> to <level> for <delay> nanoseconds + * + * void parport_data (unsigned char value) + * put data bits on DB1..DB8 + * + */ + + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <errno.h> +#include <sys/ioctl.h> + + +#ifdef HAVE_SYS_IO_H +#include <sys/io.h> +#define WITH_OUTB +#else +#ifdef HAVE_ASM_IO_H +#include <asm/io.h> +#define WITH_OUTB +#endif +#endif + +#if defined (HAVE_LINUX_PARPORT_H) && defined (HAVE_LINUX_PPDEV_H) +#define WITH_PPDEV +#include <linux/parport.h> +#include <linux/ppdev.h> +#else +#define PARPORT_CONTROL_STROBE 0x1 +#define PARPORT_CONTROL_AUTOFD 0x2 +#define PARPORT_CONTROL_INIT 0x4 +#define PARPORT_CONTROL_SELECT 0x8 +#endif + +#if !defined(WITH_OUTB) && !defined(WITH_PPDEV) +#error neither outb() nor ppdev() possible +#error cannot compile parallel port driver +#endif + + +#include "debug.h" +#include "cfg.h" +#include "udelay.h" +#include "parport.h" + + +static unsigned short Port=0; +static char *PPdev=NULL; + +// initial value taken from linux/parport_pc.c +static unsigned char ctr = 0xc; + +#ifdef WITH_PPDEV +static int PPfd=-1; +#endif + +int parport_open (void) +{ + char *s, *e; + +#ifdef USE_OLD_UDELAY + s=cfg_get ("Delay",NULL); + if (s==NULL || *s=='\0') { + error ("parport: no 'Delay' entry in %s", cfg_file()); + return -1; + } + if ((loops_per_usec=strtol(s, &e, 0))==0 || *e!='\0') { + error ("parport: bad delay '%s' in %s", s, cfg_file()); + return -1; + } +#else + udelay_init(); +#endif + + s=cfg_get ("Port",NULL); + if (s==NULL || *s=='\0') { + error ("parport: no 'Port' entry in %s", cfg_file()); + return -1; + } + PPdev=NULL; + if ((Port=strtol(s, &e, 0))==0 || *e!='\0') { +#ifdef WITH_PPDEV + Port=0; + PPdev=s; +#else + error ("parport: bad Port '%s' in %s", s, cfg_file()); + return -1; +#endif + } + + +#ifdef WITH_PPDEV + + if (PPdev) { + debug ("using ppdev %s", PPdev); + PPfd=open(PPdev, O_RDWR); + if (PPfd==-1) { + error ("parport: open(%s) failed: %s", PPdev, strerror(errno)); + return -1; + } + +#if 0 + // Fixme + if (ioctl(PPfd, PPEXCL)) { + debug ("ioctl(%s, PPEXCL) failed: %s", PPdev, strerror(errno)); + } else { + debug ("ioctl(%s, PPEXCL) succeded."); + } +#endif + + if (ioctl(PPfd, PPCLAIM)) { + error ("parport: ioctl(%s, PPCLAIM) failed: %d %s", PPdev, errno, strerror(errno)); + return -1; + } + } else + +#endif + + { + debug ("using raw port 0x%x", Port); + if (ioperm(Port, 3, 1)!=0) { + error ("parport: ioperm(0x%x) failed: %s", Port, strerror(errno)); + return -1; + } + } + return 0; +} + + +int parport_close (void) +{ +#ifdef WITH_PPDEV + if (PPdev) { + debug ("closing ppdev %s", PPdev); + if (ioctl(PPfd, PPRELEASE)) { + error ("parport: ioctl(%s, PPRELEASE) failed: %s", PPdev, strerror(errno)); + } + if (close(PPfd)==-1) { + error ("parport: close(%s) failed: %s", PPdev, strerror(errno)); + return -1; + } + } else +#endif + { + debug ("closing raw port 0x%x", Port); + if (ioperm(Port, 3, 0)!=0) { + error ("parport: ioperm(0x%x) failed: %s", Port, strerror(errno)); + return -1; + } + } + return 0; +} + + +unsigned char parport_wire (char *name, unsigned char *deflt) +{ + unsigned char w; + char wire[256]; + char *s; + int n; + + snprintf (wire, sizeof(wire), "Wire.%s", name); + s=cfg_get (wire,deflt); + if (strcasecmp(s,"STROBE")==0) { + w=PARPORT_CONTROL_STROBE; + } else if(strcasecmp(s,"AUTOFD")==0) { + w=PARPORT_CONTROL_AUTOFD; + } else if(strcasecmp(s,"INIT")==0) { + w=PARPORT_CONTROL_INIT; + } else if(strcasecmp(s,"SELECT")==0) { + w=PARPORT_CONTROL_SELECT; + } else { + error ("parport: unknown signal <%s> for wire <%s>", s, name); + error (" should be STROBE, AUTOFD, INIT or SELECT"); + return 255; + } + + n=0; + if (w&PARPORT_CONTROL_STROBE) { + n++; + info ("wiring: [DISPLAY:%s]==[PARPORT:STROBE]", name); + } + if (w&PARPORT_CONTROL_AUTOFD) { + n++; + info ("wiring: [DISPLAY:%s]==[PARPORT:AUTOFD]", name); + } + if (w&PARPORT_CONTROL_INIT) { + n++; + info ("wiring: [DISPLAY:%s]==[PARPORT:INIT]", name); + } + if (w&PARPORT_CONTROL_SELECT) { + n++; + info ("wiring: [DISPLAY:%s]==[PARPORT:SELECT]", name); + } + if (n<1) { + error ("parport: no signal for wire <%s> found!", name); + return 255; + } + if (n>1) { + error ("parport: more than one signal for wire <%s> found!", name); + return 255; + } + return w; +} + + +void parport_control (unsigned char mask, unsigned char value) +{ + + // sanity check + if (mask==0) { + error ("parport: internal error: control without signal called!"); + return; + } + + // Strobe, Select and AutoFeed are inverted! + value ^= PARPORT_CONTROL_STROBE|PARPORT_CONTROL_SELECT|PARPORT_CONTROL_AUTOFD; + +#ifdef WITH_PPDEV + if (PPdev) { + struct ppdev_frob_struct frob; + frob.mask=mask; + frob.val=value; + ioctl (PPfd, PPFCONTROL, &frob); + } else +#endif + { + // code stolen from linux/parport_pc.h + ctr = (ctr & ~mask) ^ value; + outb (ctr, Port+2); + } +} + + +void parport_toggle (unsigned char bit, int level, int delay) +{ + + // sanity check + if (bit==0) { + error ("parport: internal error: toggle without signal called!"); + return; + } + + // Strobe, Select and AutoFeed are inverted! + if (bit & (PARPORT_CONTROL_STROBE|PARPORT_CONTROL_SELECT|PARPORT_CONTROL_AUTOFD)) { + level=!level; + } + +#ifdef WITH_PPDEV + if (PPdev) { + struct ppdev_frob_struct frob; + frob.mask=bit; + + // rise + frob.val=level?bit:0; + ioctl (PPfd, PPFCONTROL, &frob); + + // pulse width + ndelay(delay); + + // lower + frob.val=level?0:bit; + ioctl (PPfd, PPFCONTROL, &frob); + } else +#endif + { + // rise + ctr = (ctr & ~bit) ^ (level?bit:0); + outb (ctr, Port+2); + + // pulse width + ndelay(delay); + + // lower + ctr = (ctr & ~bit) ^ (level?0:bit); + outb (ctr, Port+2); + } +} + + +void parport_data (unsigned char data) +{ +#ifdef WITH_PPDEV + if (PPdev) { + ioctl(PPfd, PPWDATA, &data); + } else +#endif + { + outb (data, Port); + } +} + diff --git a/parport.h b/parport.h new file mode 100644 index 0000000..c8170b2 --- /dev/null +++ b/parport.h @@ -0,0 +1,38 @@ +/* $Id: parport.h,v 1.1 2003/04/04 06:02:03 reinelt Exp $ + * + * generic parallel port handling + * + * Copyright 2003 by Michael Reinelt (reinelt@eunet.at) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * $Log: parport.h,v $ + * Revision 1.1 2003/04/04 06:02:03 reinelt + * new parallel port abstraction scheme + * + */ + +#ifndef _PARPORT_H_ +#define _PARPORT_H_ + +int parport_open (void); +int parport_close (void); +unsigned char parport_wire (char *name, char *deflt); +void parport_control (unsigned char mask, unsigned char value); +void parport_toggle (unsigned char bit, int level, int delay); +void parport_data (unsigned char data); + +#endif @@ -1,4 +1,4 @@ -/* $Id: udelay.c,v 1.10 2003/02/27 07:43:11 reinelt Exp $ +/* $Id: udelay.c,v 1.11 2003/04/04 06:02:04 reinelt Exp $ * * short delays * @@ -20,6 +20,9 @@ * * * $Log: udelay.c,v $ + * Revision 1.11 2003/04/04 06:02:04 reinelt + * new parallel port abstraction scheme + * * Revision 1.10 2003/02/27 07:43:11 reinelt * * asm/msr.h: included hard-coded definition of rdtscl() if msr.h cannot be found. @@ -217,6 +220,7 @@ static void getCPUinfo (int *hasTSC, double *MHz) } + void udelay_init (void) { int tsc; @@ -233,6 +237,7 @@ void udelay_init (void) } } + void ndelay (unsigned long nsec) { |