[comp.unix.i386] Parallel port driver rel 2.6 System V/386

pcg@cs.aber.ac.uk (Piercarlo Grandi) (08/28/90)

This is the most recent revision of my parallel post driver, inspired by
Mike Grenier's fast_lp driver, for System V/386. Mike's aim was to have
a printer driver that did flow control by polling, and not by taking
interrupts, in order to avoid assigning two of the scarce interrupt
lines of the ISA bus to printers. Since printers are slow devices,
polling can be infrquent enough that the overhead is irrelevant; also,
since they are buffered, filling the buffer can proceed in large chunks
without poll induced sleeps.

This revision was done mainly to test a suggestion by Mike, to transfer
characters from the user by the bufferful and not one at a time. This
reduces time overheads at the expense of space overheads. Well, the
difference either way turns out to be usually small enough to be
irrelevant.

Other minor changes in this version are better integration for the
Installable Driver mechanism of System V/386, and the correction of an
incredible bug (why nobody reported it?) that I had wantonly introduced
while posting the version before this, by way of incomplete application
of De Morgan's to a boolean test (a && reamined such instead of becoming
||) -- a stupid oversight that caused character losses with slow
printers.

	Let me repeat here the usual disclaimer: this work has been
	entirely done by me, with my own resources, funding and time,
	and is no way related to the research of the Unviersity College
	of Wales, which I however thank for the permission to use news.

-------------------- cut here ------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  MANIFEST Makefile Master Name Node README Space.c System
#   pp.c pp.h
# Wrapped by sw@aware on Tue Aug 28 13:25:11 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo '
    Copyright 1989 Piercarlo Grandi.  All rights reserved.

    This shar archive contains 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 1, or (at your option) any later version.

    As a special case, this driver may be incorporated in any OS kernel,
    whether the GNU General Public License applies to it or not.

    This shar archive 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 may 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.
'
sleep 4
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(406 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	
X Makefile                   1	
X Master                     1	
X Name                       1	
X Node                       1	
X README                     1	
X Space.c                    1	
X System                     1	
X pp.c                       1	
X pp.h                       1	
END_OF_FILE
if test 406 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(525 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XDEV		=pp
XCONF		=/etc/conf/bin/
XSYS		=/usr/include/sys
XLSYS		=/usr/local/include/sys
XCFLAGS		=-O -DINKERNEL -I$(LSYS)
X
XDriver.o:	$(DEV).o;		ln $? $@
XSpace.c:	space.c;		ln $? $@
X$(LSYS)/$(DEV).h:	$(SYS)/$(DEV).h;	ln $? $@
X$(SYS)/$(DEV).h:	$(DEV).h;		cp $? $@
X
X$(DEV).o:	$(LSYS)/$(DEV).h Space.c
Xspace.o:	$(LSYS)/$(DEV).h
Xspace.o:	config.h
X
Xall:		Driver.o space.o
X
Xinstall:	Master System Driver.o Space.c Node Name
X	$(CONF)idinstall -kea -msopn $(DEV)
X	$(CONF)idmknod -s; chmod a=w /dev/$(DEV)?
X
Xclean:;		rm -f *.o core Space.c
END_OF_FILE
if test 525 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
chmod +x 'Makefile'
# end of 'Makefile'
fi
if test -f 'Master' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Master'\"
else
echo shar: Extracting \"'Master'\" \(29 characters\)
sed "s/^X//" >'Master' <<'END_OF_FILE'
Xpp	Iocw	icoHGO	pp	0	0	1	3	-1
END_OF_FILE
if test 29 -ne `wc -c <'Master'`; then
    echo shar: \"'Master'\" unpacked with wrong size!
fi
chmod +x 'Master'
# end of 'Master'
fi
if test -f 'Name' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Name'\"
else
echo shar: Extracting \"'Name'\" \(43 characters\)
sed "s/^X//" >'Name' <<'END_OF_FILE'
Xpp Parallel port driver, raw polled output
END_OF_FILE
if test 43 -ne `wc -c <'Name'`; then
    echo shar: \"'Name'\" unpacked with wrong size!
fi
chmod +x 'Name'
# end of 'Name'
fi
if test -f 'Node' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Node'\"
else
echo shar: Extracting \"'Node'\" \(33 characters\)
sed "s/^X//" >'Node' <<'END_OF_FILE'
Xpp	pp0	c	0
Xpp	pp1	c	1
Xpp	pp2	c	2
END_OF_FILE
if test 33 -ne `wc -c <'Node'`; then
    echo shar: \"'Node'\" unpacked with wrong size!
fi
chmod +x 'Node'
# end of 'Node'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4747 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X	A FAST PARALLEL PORT DRIVER THAT DOES NOT USE INTERRUPTS
X
XThis is the source of a parallel port driver for System V/386, rel. 3.2.
X
XIt is different from the standard lp(7) driver because it does only raw
Xoutput (while lp(7) uses the termio(4) line discipline), and it does not use
Xinterrupts. It assumes that the printer has an internal buffer, so that the
Xmost efficient style of communication is to pump characters as fast as
Xpossible until the buffer fills, then sleep for a relatively long period
Xwhen it signals not ready, and try again thereafter.
X
XThis implies that no interrupt processing is done, which has the advantages
Xof simplicity and low overhead, and, perhaps most importantly, of not using
Xone of the scarce interurpt lines of the ISA bus.
X
X	OUTLINE OF DESIGN
X
XOutput is done entirely in the top half of the driver, and therefore not
Xinside a critical region. This could mean that on a very busy system the
Xpumping could be interrupted by task switching. This, if important, can be
Xeasily obviated, by turning the pumping loop into a critical region; if this
Xis done it becomes important to limit the number of characters pumped in one
Xgo, by having two loops, the outer one that runs until busy is signaled, the
Xinner one for a fixed number of characters, and put only the inner one in
Xthe critical region.
X
XA similar driver has been posted by Mike Grenier; this version is completely
Xrewritten and uses different logic. In particular the polling waits are
Xeither very short if busy or interruptible if sleeping.
X
X	INSTALLATION
X
XAs it stands it is especially designed for a stock System V/386 rel. 3.2
Xsystem, e.g. ESIX, especially inasmuch installation is concerned. It should
Xbe sufficient to say 'make install' to install it, and then you should say
X'idconfig' and 'idmkunix' to rebuild the kernel (but first finish reading
Xthis file). The Makefile will install "pp.h" into "/usr/include/sys", which
Xis required.
X
XThis driver is so simple that it should port very quickly to other flavours
Xof Unix; the only thing that may not be portable is the reference to a kernel
Xprocedure called 'tenmicrosec()' in pp.c, which does a busy loop of 10
Xmicroseconds.  It is fairly easy to roll your own, of course.
X
X	CONFIGURATION OF PARAMETERS
X
XThis version can be configured in several ways. You can, in file "pp.h",
Xdefine ppSTATICSZ as either zero, in which case a buffer will be stolen from
Xthe block cache whenever a parallel port is open, or non zero, in which case
Xa static buffer will be allocated for each parallel port. The only reason
Xfor a buffer in this driver is to cut down on procedure invocations to fetch
Xcharacters to transmit from the user space, so even a small buffer will be
Xsufficient to amortize the cost of a procedure call (anything upwards of 64
Xbytes is probably OK). I recommend using a smallish static buffer (say
X128-256 bytes), as probably the code that implements cache block stealing
Xand restitution is about that size anyhow :-), even if static allocation is
Xaesthetically less pleasing (character by character fetching was simpler and
Xinsignificantly slower, but I will not bother putting it back in). Note that
Xthere is no interlocking provided for access (as opposed to allocation) to
Xthe buffer; if two processes try to write to the printer at the same time,
Xthey will use the same buffer without any synchronization. It is expected
Xthat higher level synchronization and queueing mechanisms exist.
X
XYou can configure, in file "space.c", a number of things; first the
Xaddresses of the IO ports of the printers you have got. These should not
Xneed changing at all on an AT compatible 386. At worst, you can
Xcomment/uncomment those lines that correspond to devices you have/don't
Xhave. You can also configure the masks and the durations for long term
X(waiting for the printer to be online) pauses and for short term (waiting
Xfor the interface buffer to become less choked) pauses. You can also
Xconfigure the number of tens of microseconds we are prepared to busy wait
Xfor the interface to accept the next character before switching to short
Xterm pausing and waiting for it to reach some low water mark.
X
XIn general the mask and pause values given as defaults should work, and the
Xpause durations do not matter that much; the max spinning count (busy wait
Xloops) parameters is more critical, in that if it is too small the printer
Xwill be driven very slowly (only a few characters per second), because a
Xshort pause will be entered on every character. If it is too large some time
Xwill be wasted when the interface becomes choked before we give up spinning,
Xbut this is probably not very frequent or important.  The default value is
Xconservative enough for my printer, but raise it if you are in doubt.
END_OF_FILE
if test 4747 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
chmod +x 'README'
# end of 'README'
fi
if test -f 'Space.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Space.c'\"
else
echo shar: Extracting \"'Space.c'\" \(3026 characters\)
sed "s/^X//" >'Space.c' <<'END_OF_FILE'
X/*
X    $Id: space.c,v 2.6 90/08/24 11:48:45 sw Exp $
X*/
X
X/*
X    "Copyright 1990 Piercarlo Grandi. All rights reserved.";
X*/
X
X/*
X    This driver is free software; you can redistribute it and/or
X    modify it under the terms of the GNU General Public License as
X    published by the Free Software Foundation; either version 1, or
X    (at your option) any later version.
X
X    As a special case, this driver may be incorporated in any OS kernel,
X    whether the GNU General Public License applies to it or not.
X
X    This driver is distributed in the hope that it will be useful,
X    but WITHOUT ANY WARRANTY; without even the implied warranty of
X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X    GNU General Public License for more details.
X
X    You may have received a copy of the GNU General Public License
X    along with this driver; if not, write to the Free Software
X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X*/
X
X#include "config.h"
X
X#ifdef PP
X
X#include "sys/types.h"
X#include "sys/param.h"
X#include "sys/buf.h"
X#include "sys/pp.h"
X
Xstruct pp_config	pp_config[] =
X{
X    /*	data,	    status,	    control */
X#if PP_CNTLS >= 1
X    {	PP_0_SIOA,  PP_0_SIOA+1,    PP_0_EIOA    },	/* /dev/pp0	*/
X#endif
X#if PP_CNTLS >= 2
X    {	PP_1_SIOA,  PP_1_SIOA+1,    PP_2_EIOA    },	/* /dev/pp0	*/
X#endif
X#if PP_CNTLS >= 3
X    {	PP_2_SIOA,  PP_2_SIOA+1,    PP_2_EIOA    },	/* /dev/pp0	*/
X#endif
X};
X
X#define ppMAX		(sizeof pp_config / sizeof (struct pp_config))
X
X#if ppSTATICSZ != 0
Xchar			pp_sbuf[ppMAX][ppSTATICSZ];
X#endif
X
Xshort			pp_max = ppMAX;
X
X/*
X    The exit conditions from the two polling loops here are a bit funny,
X    my printer (EPSON SQ850) and parallel port give the following statuses:
X
X				NOTBUSY NOTACK  NOPAPER ONLINE  NOTERROR
X
X	port missing		1	1	1	1	1
X	printer power off	1	0	0	0	0
X	printer not there	1	1	0	1	0
X	offline			0	1	0	1	0
X	online			1	1	0	1	1
X
X	The printer puts NOTBUSY low while we strobe the character in,
X	then strobes NOTACK low for 10 usecs afterwards to signal we can
X	strobe again. The relationship between the two is to say the
X	last bizarre.
X
X	Our problem is that we want to distinguish between long term and
X	short term busy, where short term busy is defined as the time taken
X	by the interface to read a character, and long term busy as paper
X	end, offline, power off, interface buffer full.
X*/
X
Xstruct pp_guard		pp_guard =
X{
X    {
X	(ppONLINE|ppNOTERROR|ppNOPAPER),		/* pause.mask	*/
X	(ppONLINE|ppNOTERROR)				/* pause.done	*/
X    },
X    {
X	(ppNOTACK|ppNOTBUSY),				/* spin.mask	*/
X	(ppNOTACK|ppNOTBUSY)				/* spin.done	*/
X    },
X};
X
X/*
X    These are the number of clock ticks in a long pause, the number of clock
X    ticks in a short pause, and the maximum # of times we busy wait, after
X    which we sleep wait; this should be a bit larger than the usual inter
X    character processing time of the interface.
X*/
X
Xshort unsigned		pp_longpause	= HZ/2;
Xshort unsigned		pp_shortpause	= HZ/4;
Xshort unsigned		pp_maxspins	= 7;	/* in 10 usec units	*/
X
X#endif /* PP */
END_OF_FILE
if test 3026 -ne `wc -c <'Space.c'`; then
    echo shar: \"'Space.c'\" unpacked with wrong size!
fi
chmod +x 'Space.c'
# end of 'Space.c'
fi
if test -f 'System' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'System'\"
else
echo shar: Extracting \"'System'\" \(75 characters\)
sed "s/^X//" >'System' <<'END_OF_FILE'
Xpp	Y	1	0	0	0	3bc	3be	0	0
Xpp	N	2	0	0	0	378	37a	0	0
Xpp	N	3	0	0	0	278	27a	0	0
END_OF_FILE
if test 75 -ne `wc -c <'System'`; then
    echo shar: \"'System'\" unpacked with wrong size!
fi
chmod +x 'System'
# end of 'System'
fi
if test -f 'pp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pp.c'\"
else
echo shar: Extracting \"'pp.c'\" \(7452 characters\)
sed "s/^X//" >'pp.c' <<'END_OF_FILE'
X/*
X    $Id: pp.c,v 2.6 90/08/24 11:48:24 sw Exp $
X*/
X
Xstatic char Notice[] =
X    "Copyright 1990 Piercarlo Grandi. All rights reserved.";
X
X/*
X    This driver is free software; you can redistribute it and/or
X    modify it under the terms of the GNU General Public License as
X    published by the Free Software Foundation; either version 1, or
X    (at your option) any later version.
X
X    As a special case, this driver may be incorporated in any OS kernel,
X    whether the GNU General Public License applies to it or not.
X
X    This driver is distributed in the hope that it will be useful,
X    but WITHOUT ANY WARRANTY; without even the implied warranty of
X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X    GNU General Public License for more details.
X
X    You may have received a copy of the GNU General Public License
X    along with this driver; if not, write to the Free Software
X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X*/
X
X/*
X    Fast parallel port driver, polling, no interrupts (somewhat
X    inspired by a driver from Michael Grenier <mike@cimcor.mn.org>)
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/buf.h"
X#include "sys/errno.h"
X#include "sys/immu.h"
X#include "sys/sysmacros.h"
X#include "sys/inline.h"
X
X#ifdef ppDEBUG
X    unsigned		    pp_debug = 1;
X#   define DEBUG(STMTS)	    do { if (pp_debug) { STMTS; }; } while (0)
X
X    unsigned		    pp_nchar;
X    unsigned		    pp_nlongpause;
X    unsigned		    pp_nshortpause;
X    unsigned		    pp_nspin;
X#else
X#   define DEBUG(list)	    /* skip */
X#endif
X
X#include "sys/pp.h"
X
X#if (ppSTATICSZ == 0)
X#   define ppBUFSZ	SBUFSIZE
X#else
X#   define ppBUFSZ	ppSTATICSZ
X#endif
X
X/*
X    A long pause for polling the printer until it is online again
X    the pause while the strobe is high, and a short pause to wait
X    for the interface to become ready for the next character.
X    The longer pause is done sleeping, the other two are done
X    spinning, so they had better be few.
X*/
X
Xextern int		min();
Xextern int		tenmicrosec();
Xextern int		wakeup();
Xextern int		timeout();
Xextern int		sleep();
X#if (ppSTATICSZ == 0)
X    extern struct buf	*geteblk();
X#endif
X
X#define ppSPIN()	(void) (tenmicrosec())
X#define ppPAUSE(U,N)	(void) (timeout(wakeup,(U),(N)),sleep((U),PSLEP))
X
Xextern int		copyin();
X
Xextern int		ppinit()
X{
X    register struct pp_config *pp;
X
X    for (pp = pp_config; pp < (pp_config+pp_max); pp++)
X    {
X#	if (ppSTATICSZ != 0)
X	    pp->buf = &pp_sbuf[pp-pp_config][0];
X#	endif
X	outb(pp->control,(ppSELECT|ppNOTRESET));
X	DEBUG(printf("Initial status of /dev/pp%d is %x\n",
X		pp-pp_config,inb(pp->status)));
X    }
X}
X
X/* ARGSUSED */
Xextern int              ppopen(dev,mode)
X    int			    dev,mode;
X{
X    register int	    unit = minor(dev);
X    register unsigned	    status;
X    register struct pp_config *pp;
X
X    if (unit >= pp_max)
X    {
X	u.u_error = EIO;
X	return;
X    }
X
X    pp = &pp_config[unit];
X
X    status = inb(pp->status);
X
X    if ((status&0xff) == 0xff)
X    {
X	u.u_error = ENXIO;
X	DEBUG(printf("Printer /dev/pp%d does not exist\n",unit));
X	return;
X    }
X
X    /*
X	We ignore error condition except when printer is online ready.
X    */
X
X    if ((status&(ppONLINE|ppNOTBUSY|ppNOTERROR)) == (ppONLINE|ppNOTBUSY))
X    {
X	u.u_error = EIO;
X	DEBUG(printf("Error status %x detected on /dev/pp%d\n",status,unit));
X	return;
X    }
X
X    DEBUG((pp_nchar = pp_nlongpause = pp_nshortpause = pp_nspin = 0));
X
X#   if (ppSTATICSZ == 0)
X    {
X	int			s;
X
X	s = spl3();
X	{
X	    if (pp->hdr)
X	    {
X		splx(s);
X		DEBUG(printf("Printer /dev/pp%d already open (%x)\n",
X		    unit,pp->hdr));
X		return;
X	    }
X	    pp->hdr = (struct buf *) 1;
X	}
X	splx(s);
X
X	pp->hdr = geteblk();
X	if (pp->hdr)
X	{
X	    pp->hdr->b_flags |= B_PRIVLG;
X	    pp->buf = pp->hdr->b_un.b_addr;
X	}
X	else
X	{
X	    u.u_error = ENOMEM;
X	    DEBUG(printf("Cannot allocate buffer for /dev/pp%d\n",unit));
X	}
X
X	DEBUG(printf("Printer /dev/pp%d has bufhdr %x, buf %x\n",
X	    unit,pp->hdr,pp->buf));
X    }
X#endif
X}
X
X/* ARGSUSED */
Xextern int              ppclose(dev)
X    int			    dev;
X{
X    DEBUG(printf("Printed %d characters, paused %d and spun %d (%d) times\n",
X	pp_nchar,pp_longpause,pp_nspin,pp_nshortpause));
X
X#   if (ppSTATICSZ == 0)
X    {
X	register struct pp_config *pp;
X
X	pp = &pp_config[minor(dev)];
X
X	if (pp->hdr)
X	{
X	    pp->buf = (caddr_t) 0;
X	    pp->hdr->b_flags &=~ B_PRIVLG;
X
X	    brelse(pp->hdr);
X	    pp->hdr = (struct buf *) 0;
X	}
X	else
X	    DEBUG(printf("Impossible close without buffer of /dev/pp%d\n",
X		pp-pp_config));
X    }
X#   endif
X}
X
Xstatic void		ppbufwrite(pp,buf,endbuf)
X    register struct pp_config *pp;
X    caddr_t		    buf;
X    register caddr_t	    endbuf;
X{
X    register unsigned	    status;
X    register int	    statusp;
X    register char	    *ch;
X
X    statusp = pp->status;
X
X    for (ch = (char *) buf; ch < (char *) endbuf; ch++)
X    {
X	DEBUG(pp_nchar++);
X
X    latch_character:
X
X	outb(pp->data,*ch);
X
X	/*
X	    Here we wait for the printer to be ready, and this may
X	    be a longish wait, because of paper end, offline, power off.
X	    We sleep, polling a few times per second, as this is simpler
X	    than taking an interrupt and the cost is very low.
X	*/
X
X    wait_printer_online:
X
X	for
X	(
X	    status = inb(statusp);
X	    (status & pp_guard.pause.mask) != pp_guard.pause.done
X		|| (status & pp_guard.spin.mask) != pp_guard.spin.done;
X	    status = inb(statusp)
X	)
X	{
X	    ppPAUSE((caddr_t) &pp->status,pp_longpause);
X	    DEBUG(pp_nlongpause++);
X	}
X
X	/*
X	    Allelluiah! The printer is ready. Strobe the character
X	    we had already latched in.
X	*/
X
X    strobe_awhile:
X
X	outb(pp->control,(ppSELECT|ppNOTRESET|ppSTROBE));
X	ppSPIN(); /* This should last at least one microsecond */
X	outb(pp->control,(ppSELECT|ppNOTRESET));
X
X	/*
X	    Here we wait for the interface to be ready to accept another
X	    character, and thus we spin, because we expect the wait to be
X	    short (e.g. 3-6 turns). This is cheaper than the overheads
X	    involved in sleeping or even in taking an interrupt.
X	*/
X
X    wait_interface_ready:
X
X	{
X	    register unsigned		    spins;
X
X	    for
X	    (
X		spins = 0, status = inb(statusp);
X		spins < pp_maxspins /* Don't waste too much time spinning */
X		    && (status & pp_guard.spin.mask) != pp_guard.spin.done
X		    && (status & pp_guard.pause.mask) == (pp_guard.pause.done);
X		spins++, status = inb(statusp)
X	    )
X	    {
X		ppSPIN();
X		DEBUG(pp_nspin++);
X	    }
X
X	    /*
X		This is not really necessary; we could just have one pause
X		above, before latching the character. We do not do that
X		simply because we want to have a shorter pause for buffer
X		full here, to have snappier response. Well, in theory :->.
X	    */
X
X	    if (spins == pp_maxspins)
X	    {
X		ppPAUSE((caddr_t) &pp->status,pp_shortpause);
X		DEBUG(pp_nshortpause++);
X	    }
X	}
X    }
X}
X
Xextern int              ppwrite(dev)
X    int			    dev;
X{
X    register struct pp_config *pp;
X    register caddr_t	    buf;
X    register unsigned	    count;
X
X    pp	    = &pp_config[minor(dev)];
X    buf	    = pp->buf;
X
X    DEBUG(printf("Print total %d chars from %x on /dev/pp%d\n",
X	u.u_count,u.u_base,pp-pp_config));
X
X    for
X    (
X	u.u_base, u.u_count;
X	(count = min(u.u_count,ppBUFSZ)) != 0
X	    && copyin(u.u_base,buf,count) == 0;
X	u.u_base += count, u.u_count -= count
X    )
X    {
X	DEBUG(printf("Print %d chars from %x on /dev/pp%d\n",
X	    count,u.u_base,pp-pp_config));
X	ppbufwrite(pp,buf,buf+count);
X    }
X}
END_OF_FILE
if test 7452 -ne `wc -c <'pp.c'`; then
    echo shar: \"'pp.c'\" unpacked with wrong size!
fi
chmod +x 'pp.c'
# end of 'pp.c'
fi
if test -f 'pp.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pp.h'\"
else
echo shar: Extracting \"'pp.h'\" \(2692 characters\)
sed "s/^X//" >'pp.h' <<'END_OF_FILE'
X/*
X    $Id: pp.h,v 2.6 90/08/24 11:49:16 sw Exp $
X*/
X
X/*
X    "Copyright 1990 Piercarlo Grandi. All rights reserved.";
X*/
X
X/*
X    This driver is free software; you can redistribute it and/or
X    modify it under the terms of the GNU General Public License as
X    published by the Free Software Foundation; either version 1, or
X    (at your option) any later version.
X
X    As a special case, this driver may be incorporated in any OS kernel,
X    whether the GNU General Public License applies to it or not.
X
X    This driver is distributed in the hope that it will be useful,
X    but WITHOUT ANY WARRANTY; without even the implied warranty of
X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X    GNU General Public License for more details.
X
X    You may have received a copy of the GNU General Public License
X    along with this driver; if not, write to the Free Software
X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X*/
X
X/*
X    Status port defines
X*/
X
X#define ppNOTERROR	0x08	/* Online, paper present, OK		*/
X#define ppONLINE	0x10	/* Printer is online			*/
X#define ppNOPAPER	0x20	/* Paper missing			*/
X#define ppNOTACK	0x40	/* Data have been read			*/
X#define ppNOTBUSY	0x80	/* Interface ready			*/
X
X/*
X    Control port defines
X*/
X
X#define ppSTROBE	0x01	/* Strobe a character in		*/
X#define ppAUTOLF	0x02	/* Enable auto line feed		*/
X#define ppNOTRESET	0x04	/* Normal operation			*/
X#define ppSELECT	0x08	/* Put the printer online		*/
X#define ppINTERRUPT	0x10	/* Send interrupt when NOTACK is reset	*/
X
X#ifdef INKERNEL
X
X/*
X    Here we have a difficult decision. We want to copy whole chunks of
X    user characters to kernel space and then push them out one by one
X    to the printer. How long these chunks should be, i.e. how much
X    buffer space should we consume? Should it be reserved statically or
X    dynamically? Here you have two choices. Either you reserve a static
X    buffer of the indicated size (typically a small one), or we will
X    reserve a block cache buffer dynamically if this is zero.
X*/
X
X#define ppSTATICSZ	128	/* Other good values: 128, 256		*/
X
Xstruct pp_guard
X{
X    struct
X    {
X	char unsigned		mask;
X	char unsigned		done;
X    }
X			    pause,spin;
X};
X
Xstruct pp_config
X{
X    short                   data;
X    short                   status;
X    short                   control;
X    caddr_t		    buf;
X#if (ppSTATICSZ == 0)
X    struct buf		    *hdr;
X#endif
X};
X
Xextern struct pp_guard	pp_guard;
Xextern struct pp_config	pp_config[];
X#if (ppSTATICSZ != 0)
X    extern char		pp_sbuf[][ppSTATICSZ];
X#endif
X
Xextern short		pp_max;
X
Xextern short unsigned	pp_longpause;
Xextern short unsigned	pp_shortpause;
Xextern short unsigned	pp_maxspins;
X#endif
END_OF_FILE
if test 2692 -ne `wc -c <'pp.h'`; then
    echo shar: \"'pp.h'\" unpacked with wrong size!
fi
chmod +x 'pp.h'
# end of 'pp.h'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
--
Piercarlo "Peter" Grandi           | ARPA: pcg%uk.ac.aber.cs@nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth        | UUCP: ...!mcsun!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk