Fast parallel driver for Unix/Xenix AT?

Michael Grenier mike at cimcor.MN.ORG
Sun Nov 26 02:51:50 AEST 1989


>From article <2316 at thebes.Thalatta.COM>, by campbell at Thalatta.COM (Bill Campbell):
> In article <256ADBB5.19093 at ateng.com> chip at 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 at 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



More information about the Comp.unix.i386 mailing list