dirk@altger.UUCP (dirk) (03/12/88)
Since today I became four IBM AT parallel device drivers for the Interactive 386/ix UNIX from Interactive. None of them worked the way I wanted to have it. The new 1.0.4 release update driver seems very good, but it stops after each line and waits long times between lines. The release update paper says that this new driver does not stop at end of line, but the driver does. Due to this I rewrote the lp driver some time before. Posted here, you'll find an older version which was limited to one port only. But you can easy append code to it. The one I am using supports 128 ports and includes mapping tables to translate control-sequences. This driver should work on XENIX and Microport as well, if you change some code or append facilities to it, pls. send me a mail. cu, dirk :-) Dirk Koeppen, DK-SOFT, West Germany, ..!unido!cosa!dirk INSTALLATION ON 386/ix: 1. Create a directory /etc/atconf/modules/lpt 2. Copy this file into the directory and unbundle it 3. Run the Makefile 4. Run kconfig - Use the remove driver option and remove the lp driver - Use the add driver option to select the new driver ---------------------------> CUT HERE <-------------------------------- # To unbundle, sh(ell) this file # ============================== echo README 1>&2 cat >README <<'End of ===README===' Sine today I became four IBM AT parallel device drivers for the Interactive 386/ix UNIX from Interactive. None of them worked the way I wanted to have it. The new 1.0.4 release update driver seems very good, but it stops after each line and waits long times between lines. The release update paper says that this new driver does not stop at end of line, but the driver does. Due to this I rewrote the lp driver some time before. Posted here, you'll find an older version which was limited to one port only. But you can easy append code to it. The one I am using supports 128 ports and includes mapping tables to translate control-sequences. This driver should work on XENIX and Microport as well, if you change some code or append facilities to it, pls. send me a mail. cu, dirk :-) Dirk Koeppen, DK-SOFT, West Germany, ..!unido!cosa!dirk INSTALLATION ON 386/ix: 1. Create a directory /etc/atconf/modules/lpt 2. Copy this file into the directory and unbundle it 3. Run the Makefile 4. Run kconfig - Use the remove driver option and remove the lp driver - Use the add driver option to select the new driver End of ===README=== echo Makefile 1>&2 cat >Makefile <<'End of ===Makefile===' #ident @(#) Makefile v1.0 of 88/12/03 , dirk # Makefile for lpt.o # Copyright (c) 1987, 1988 DK-Soft, Dirk Koeppen, .. unido!cosa!dirk # All Rights Reserved SHELL =/bin/sh CFLAGS =-O -c -DLIMITED SILENTCC =YES all: lpt.o ../description lpt.o: lpt.c config cc $(CFLAGS) lpt.c ../description: description mv ../description ../description- cat ../description- description > ../description clean: rm -f foo Mout Lout a.out core *.i *.obj *.o rm -f lpt.o End of ===Makefile=== echo config 1>&2 cat >config <<'End of ===config===' * 1 "lpt/config" * Copyright (c) 1987, 1988 DK-Soft, Dirk Koeppen, .. unido!cosa!dirk * All Rights Reserved *ident "@(#)config 1.0 - 87/12/23" character(7) prefix = lpt intvec = 7 intpri = SPL3 functions = open, close, write, start, intr, init End of ===config=== echo description 1>&2 cat >description <<'End of ===description===' lpt - - io - The DK-Soft AT Line Printer Driver End of ===description=== echo lpt.c 1>&2 cat >lpt.c <<'End of ===lpt.c===' /* * COPYRIGHT (c) 1987-88, dksoft, .. unido!cosa!dirk * char SCCS_id[]= "%Z% %M% v%I% of %D% %Q%, dirk" * LPT line printer driver * * delta date modification done by * ----- --------- --------------------------------------------- ------------- * 1.3 25.Dec'87 up to 128 ports support dirk * 1.2 24.Dec'87 device polling on lost intr. dirk * 1.1 23.Dec'87 first steps dirk */ #include <sys/types.h> #include <sys/param.h> #include <sys/tty.h> /* * The registers for the printer port */ struct lptdevice { unsigned data; /* lpt data port */ unsigned status; /* lpt status port */ unsigned control; /* lpt control port */ unsigned flags; /* driver status flag */ struct clist queue; /* clist head */ }; /************************* tuneable parameters ****************************/ #define LPTINTR 7 /* Interrupt, at least one */ #define MINORTYPE unsigned char /* type of the minor number */ #define LPTSPL spl3 () /* task-time interrupt disab. */ #define LPPRI PZERO+3 /* priority of the driver */ #define LOWAT 50 /* wakeup if clist below 50 */ #define HIWAT 150 /* go to sleep if more 150 */ #ifndef LIMITED # define MAXPORT 3 /* number of ports */ #else # define MAXPORT 1 /* number of ports */ #endif /* LIMITED */ struct lptdevice lptdev[MAXPORT]= { { /* Monochrome Card port */ 0x3bc, /* 1. port data address */ 0x3bd, /* 1. port status address */ 0x3be, /* 1. port control address */ 0, /* 1. port initial status */ /* 1. port initial queue */ } #ifndef LIMITED , { /* First parallel port */ 0x378, /* 2. port data address */ 0x379, /* 2. port status address */ 0x37a, /* 2. port control address */ 0, /* 2. port initial status */ /* 2. port initial queue */ }, { /* Second parallel port */ 0x278, /* 3. port data address */ 0x279, /* 3. port status address */ 0x27a, /* 3. port control address */ 0, /* 3. port initial status */ /* 3. port initial queue */ } #endif /* LIMITED */ }; /**************************************************************************/ /* * The bits in the printer status port */ #define LPERROR 0x08 /* lpt error detected * zero on error */ #define LPSELECT 0x10 /* lpt is powered and selected * zero on power fail or * not selected */ #define LPPAPEROUT 0x20 /* lpt is out of paper * zero if paper out * only regarded if together * with LPERROR */ #define LPACKNLG 0x40 /* lpt acknowledged data * goes zero for appr. 7 usec */ #define LPBUSY 0x80 /* lpt is busy * zero if free for more data */ /* * The bits in the printer control port */ #define LPSTROBE 0x01 /* strobe lpt to accept data */ #define LPLF 0x02 /* line feed is remote */ #define LPINIT 0x04 /* init the lpt port */ #define LPSELIN 0x08 /* select lpt */ #define LPIENB 0x10 /* intr. enable */ /* * lpt_flags definitions (lpt_flags is an internal status flag variable) */ #define LPTSLEEPING 0x001 /* is sleeping */ #define LPTBUSY 0x002 /* is busy */ #define LPTTOPENDING 0x004 /* timeout flag */ #define LPTNOPAPER 0x008 /* paper is out */ #define LPTNOSELECT 0x010 /* printer not selected */ #define LPTNOPRINTER 0x020 /* no printer or cable */ #define LPTNOPORT 0x040 /* no printer port */ #define LPTERROR 0x080 /* error on printer */ #define LPTOFFLINE 0x100 /* printer is offline */ /* * current printing printer for sheduling */ MINORTYPE lpt_curr; /* * LPTSTATUS * Get the status of the printerport * * BUSY ACKNLG PAPEROUT SELECT ERROR * normal + + - + + * paper end + + + + + LPTNOPAPAPER * printer turned off + - - - - LPTNOSELECT * no printer cable - + + + - LPTNOPRINTER * offline - + - + - LPTOFFLINE */ unsigned lptstatus(dev) MINORTYPE dev; { extern struct lptdevice lptdev[MAXPORT]; register int status; if (! (lptdev[dev].flags & LPTNOPORT)) { status= inb (lptdev[dev].status); lptdev[dev].flags&= (LPTSLEEPING | LPTBUSY | LPTTOPENDING); if (status & LPPAPEROUT) lptdev[dev].flags|= LPTNOPAPER; if (~status & LPERROR) { lptdev[dev].flags|= LPTERROR; switch (status & (LPBUSY | LPACKNLG | LPPAPEROUT | LPSELECT | LPERROR)) { case LPBUSY : lptdev[dev].flags|= LPTNOSELECT; case (LPACKNLG | LPPAPEROUT | LPSELECT ) : lptdev[dev].flags|= LPTNOPRINTER; case (LPACKNLG | LPSELECT ) : lptdev[dev].flags|= LPTOFFLINE; } } } return (lptdev[dev].flags); } /* * LPTINIT * Look for printer ports and reset them at boot time */ lptinit() { extern struct lptdevice lptdev[MAXPORT]; register int status; int i, try; printf ("Parallel Port Driver Copyright (c) 1987, 1988 Dirk Koeppen\n"); printf ("All Rights Reserved\n"); lpt_curr= 0; for (i= 0; i < MAXPORT; i++) { printf (" port #%d:", i); printf ("(0x%X:0x%X:0x%X) ", lptdev[i].data, lptdev[i].status, lptdev[i].control); lptdev[i].flags= 0; for (try= 0; try < 3; try++) { outb (lptdev[i].data, 0xaa); if (inb (lptdev[i].data) != 0xaa) lptdev[i].flags|= (LPTERROR | LPTNOPORT); outb (lptdev[i].data, 0x55); if (inb (lptdev[i].data) != 0x55) lptdev[i].flags|= (LPTERROR | LPTNOPORT); } status= lptstatus(i); if (status & LPTERROR) printf ("Error "); if (status & LPTNOPAPER) printf ("No_paper "); if (status & LPTNOSELECT) printf ("No_select "); if (status & LPTNOPRINTER) printf ("No_printer "); if (status & LPTNOPORT) printf ("No_port "); if (status & LPTERROR) printf ("check_printer_!\n"); else printf ("passed\n"); } printf ("\n"); } /* * LPTOPEN * Open the device by reseting the data port */ lptopen(dev, flag, id) MINORTYPE dev; int flag, id; { extern struct lptdevice lptdev[MAXPORT]; #ifdef LIMITED if (dev >= MAXPORT) dev= MAXPORT - 1; #endif /* LIMITED */ outb (lptdev[dev].data, 0); outb (lptdev[dev].control, (LPLF | LPSELIN | LPIENB)); outb (lptdev[dev].control, (LPLF | LPINIT | LPSELIN | LPIENB)); } /* * LPTCLOSE * Close the device */ lptclose(dev, flag) MINORTYPE dev; int flag; { lptopen(dev, flag, 0); } /* * LPTWRITE * Write to the printer queue */ lptwrite(dev) MINORTYPE dev; { extern struct lptdevice lptdev[MAXPORT]; register int c; int x; #ifdef LIMITED if (dev >= MAXPORT) dev= MAXPORT - 1; #endif /* LIMITED */ /* get a char from the process's memory until no more */ while ((c= cpass ()) >= 0) { /* is the clist filling up ? */ if (lptdev[dev].queue.c_cc > HIWAT) { /* yes...start the device and go to sleep */ x= LPTSPL; while (lptdev[dev].queue.c_cc > HIWAT) { lptstart(); lptdev[dev].flags|= LPTSLEEPING; sleep (&lptdev[dev].queue, LPPRI); } splx (x); } /* put the char on the clist */ putc (c, &lptdev[dev].queue); } /* summon lptstart to start the printer */ x= LPTSPL; lptstart(); splx (x); } /* * LPTRESTART * Restart the printer when timing out */ lptrestart() { extern struct lptdevice lptdev[MAXPORT]; extern MINORTYPE lpt_curr; int x; lptdev[lpt_curr].flags&= ~LPTTOPENDING; x= LPTSPL; lptintr(LPTINTR); splx (x); } /* * LPTSTART * Print out from the queue */ lptstart() { extern struct lptdevice lptdev[MAXPORT]; extern MINORTYPE lpt_curr; int tmp; lptdev[lpt_curr].flags|= LPTBUSY; /* while the printer is READY and there is stuff on the clist */ while (((inb (lptdev[lpt_curr].status) & (LPERROR | LPSELECT | LPACKNLG | LPBUSY | LPPAPEROUT)) == (LPERROR | LPSELECT | LPACKNLG | LPBUSY)) && ((tmp=getc(&lptdev[lpt_curr].queue)) >= 0)) { outb (lptdev[lpt_curr].data, tmp); /* 0.5 usecs for drain data */ outb (lptdev[lpt_curr].control, (LPSTROBE | LPLF | LPINIT | LPSELIN | LPIENB)); /* 0.5 usecs for settling strobe pulse */ outb (lptdev[lpt_curr].control, ( LPLF | LPINIT | LPSELIN | LPIENB)); /* 0.5 usecs min. here */ /* Acknowledge will be checked by interrupt */ } /* time to wake up the lptwrite routine ? */ if ((lptdev[lpt_curr].queue.c_cc < LOWAT) && (lptdev[lpt_curr].flags & LPTSLEEPING)) { lptdev[lpt_curr].flags&= ~LPTSLEEPING; wakeup (&lptdev[lpt_curr].queue); } if (lptdev[lpt_curr].queue.c_cc <= 0) lptdev[lpt_curr].flags &= ~LPTBUSY; else if ((lptdev[lpt_curr].flags & LPTTOPENDING) == 0) { timeout (lptrestart, 0, 1); lptdev[lpt_curr].flags|= LPTTOPENDING; } } /* * LPTINTR * Catch the interrupt if there is one coming */ lptintr(vec) int vec; { extern struct lptdevice lptdev[MAXPORT]; int i; for (i= 0; i < MAXPORT; i++) { if ((lptdev[i].flags & LPTBUSY) != 0) if (lptdev[i].queue.c_cc > 0) lptstart(); } return; } End of ===lpt.c===