Xref: utzoo comp.unix.i386:1402 comp.unix.xenix:8720 comp.sources.wanted:9557 Path: utzoo!attcan!uunet!cs.utexas.edu!usc!brutus.cs.uiuc.edu!uakari.primate.wisc.edu!dogie.macc.wisc.edu!uwvax!umn-d-ub!umn-cs!bungia!cimcor!mike From: mike@cimcor.MN.ORG (Michael Grenier) Newsgroups: comp.unix.i386,comp.unix.xenix,comp.sources.wanted Subject: Re: Fast parallel driver for Unix/Xenix AT? Message-ID: <54@cimcor.MN.ORG> Date: 25 Nov 89 15:51:50 GMT References: <2316@thebes.Thalatta.COM> Followup-To: comp.unix.i386 Organization: Grenier Family & Friends, Forest Lake, MN Lines: 231 From article <2316@thebes.Thalatta.COM>, by campbell@Thalatta.COM (Bill Campbell): > In article <256ADBB5.19093@ateng.com> chip@ateng.com (Chip Salzenberg) writes: >>SCO Xenix, like all AT Unixen, is shipped with a driver for IBM parallel >>ports. Unfortunately, at least with SCO Xenix, the parallel driver uses the >>internal kernel data structures (clists) intended for use with serial lines. >>The use of clists lowers the speed of parallel to something far slower than >>the hardware could support otherwise. > > There are problems with slow printing from Xenix with Tandy > printers in particular. Most of these problems can be solved by > using the Tandy printer cables (they have some non-standard > crossovers). There is also a patch to Xenix available from Tandy > to help speed up the printer. I can't speak to the problem with Tandy printers but I had a problem with this Epson under Microport UNIX where the printer *DOES* generate an interrupt with every character sent. With my old Microport V/AT sending bitmaps to the epson, this overhead brought my system to a standstill. It wasn't bad with V/386 but still more than what I wanted so I wrote my own driver. This driver does NOT use interrupts and does NOT do any character translations. If you want the goofy translations put them into your /usr/spool/lp/interface file for this printer (I use unix2dos to cat the file to the printer to add the CRs. This allows a raw interface via /dev/lp to dump bitmaps to.) The driver relies on the fact that the printer has a buffer. The driver will output as many characters as it can until it sees that the printer is not giving an acknowledge for the next byte within some time window. At which point the driver assumes that the buffer is full and goes to sleep for awhile. It wakes up periodically to see if the printer is now available and repeats the process. No clists or other goofy things are used...its about as simple as they get. One nice benefit with this driver is that none of the scarce interrupt lines are used. Still, the driver has worked great for sending the output of my TeX dvi driver to the epson while supporting general use. There are two variables of interest in this driver. The first is lpdelay which is number of clockticks to wait before waking up to retry sending data to the printer. The second is lpstobe which is the delay in a timing loop to wait before giving up getting an acknowledge and going to sleep. Both can be set using the Microport /etc/patch program to dynamically tune this for your system. If you don't have the kernel patcher (Eat your heart out!), the values given here work fine for me. Here it is : -Mike Grenier mike@cimcor.mn.org #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # config # lp.c # space.c # This archive created: Sat Nov 25 09:33:27 1989 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'config'" '(71 characters)' if test -f 'config' then echo shar: "will not over-write existing file 'config'" else sed 's/^ X//' << \SHAR_EOF > 'config' X Xcharacter(7) X Xprefix = lp Xfunctions = init, open, close, write, ioctl SHAR_EOF if test 71 -ne "`wc -c < 'config'`" then echo shar: "error transmitting 'config'" '(should have been 71 characters)' fi fi echo shar: "extracting 'lp.c'" '(2508 characters)' if test -f 'lp.c' then echo shar: "will not over-write existing file 'lp.c'" else sed 's/^ X//' << \SHAR_EOF > 'lp.c' X X/* X Fast printer driver Copyright(c) 1989 Michael Grenier X*/ X X X#include "sys/param.h" X#include "sys/types.h" X#include "sys/dir.h" X#include "sys/signal.h" X#include "sys/user.h" X#include "sys/errno.h" X#include "sys/tty.h" X X#define MAXLP 3 /* Make this as large as needed */ X Xstruct lp_config { X short data_port; X short ctrl_port; X short status_port; X} lp_config[MAXLP] = X X{ X { 0x3bc, 0x3be, 0x3bd }, /* Printer /dev/lp0 */ X { 0x378, 0x37a, 0x27a }, /* Printer /dev/lp1 */ X { 0x278, 0x27a, 0x279 } /* Printer /dev/lp2 */ X}; X Xint lpdebug= 0; /* 1 to turn on some debugging */ Xint lpstrobe = 50; /* Loop count delay for strobe line */ Xint lpdelay = 1; /* Number of clock tics before retrying printer */ X#define minor(x) (x & 0xff) X X/* Status port defines */ X X#define NOT_BUSY (1 << 7) X#define NOT_ACK (1 << 6) X#define END_OF_PAPER (1 << 5) X#define SELECT (1 << 4) X#define NOT_ERROR (1 << 3) X X/* Control port defines */ X X#define IRQ_ENABLE (1 << 4) X#define SELECT_IN (1 << 3) X#define NOT_INIT (1 << 2) X#define AUTO_LF (1 << 1) X#define STROBE 1 X X Xlpinit() X{ X int unit; X for (unit = 0; unit < MAXLP; unit++) X { X outb(lp_config[unit].ctrl_port, SELECT_IN | NOT_INIT); X if (lpdebug) X printf("Initial status of /dev/lp%d is %x\n", X unit, inb(lp_config[unit].status_port)); X } X} X X Xlpopen(dev, mode) Xint dev, mode; X{ X register unit = minor(dev); X X if ( unit >= MAXLP ) X { X u.u_error = EIO; X return; X } X X if ((inb(lp_config[unit].status_port) & NOT_ERROR) == 0) X { X u.u_error = EIO; /* Error detected at printer */ X if (lpdebug) X printf("Printer error detected on /dev/lp%d\n", unit); X return; X } X} X X Xlpclose(dev) Xint dev; X{ X /* Nothing exciting */ X} X Xlpioctl(dev) Xint dev; X{ X /* Nothing exciting */ X} X X Xlpwrite(dev) Xint dev; X{ X int strobe_cnt, ch; X struct lp_config lp; X X lp = lp_config[ minor(dev) ]; /* lp holds params for selected printer */ X X /* Loop, getting characters from user space and sending them out */ X X while ((ch = cpass()) >= 0) { X X /* while printer is busy, sleep awhile */ X X while ( !(inb(lp.status_port) & NOT_BUSY)) X delay(lpdelay); X X /* OK, send the character out */ X X outb( lp.data_port, ch ); X outb( lp.ctrl_port, SELECT_IN | NOT_INIT | STROBE); X for ( strobe_cnt = lpstrobe; strobe_cnt; strobe_cnt--); X outb( lp.ctrl_port, SELECT_IN | NOT_INIT); X } X} SHAR_EOF if test 2508 -ne "`wc -c < 'lp.c'`" then echo shar: "error transmitting 'lp.c'" '(should have been 2508 characters)' fi fi echo shar: "extracting 'space.c'" '(52 characters)' if test -f 'space.c' then echo shar: "will not over-write existing file 'space.c'" else sed 's/^ X//' << \SHAR_EOF > 'space.c' X/* X * lp/space.c, created 8/27/89, cimcor!mike X */ X SHAR_EOF if test 52 -ne "`wc -c < 'space.c'`" then echo shar: "error transmitting 'space.c'" '(should have been 52 characters)' fi fi exit 0 # End of shell archive