olpt.c revision 50436
1155192Srwatson/*
2155192Srwatson * Copyright (c) 1990 William F. Jolitz, TeleMuse
3155192Srwatson * All rights reserved.
4155192Srwatson *
5155192Srwatson * Redistribution and use in source and binary forms, with or without
6155192Srwatson * modification, are permitted provided that the following conditions
7155192Srwatson * are met:
8155192Srwatson * 1. Redistributions of source code must retain the above copyright
9155192Srwatson *    notice, this list of conditions and the following disclaimer.
10155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11155192Srwatson *    notice, this list of conditions and the following disclaimer in the
12155192Srwatson *    documentation and/or other materials provided with the distribution.
13155192Srwatson * 3. All advertising materials mentioning features or use of this software
14155192Srwatson *    must display the following acknowledgement:
15155192Srwatson *	This software is a component of "386BSD" developed by
16155192Srwatson *	William F. Jolitz, TeleMuse.
17155192Srwatson * 4. Neither the name of the developer nor the name "386BSD"
18155192Srwatson *    may be used to endorse or promote products derived from this software
19155192Srwatson *    without specific prior written permission.
20155192Srwatson *
21155192Srwatson * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
22155192Srwatson * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
23155192Srwatson * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
24155192Srwatson * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
25155192Srwatson * NOT MAKE USE OF THIS WORK.
26155192Srwatson *
27155192Srwatson * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
28155192Srwatson * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
29155192Srwatson * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
30155192Srwatson * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
31155192Srwatson * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
32155192Srwatson * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
33155192Srwatson * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
34155192Srwatson * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
35155192Srwatson *
36155192Srwatson * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
37155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39160136Swsalamon * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
40155192Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44155192Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45155192Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46155192Srwatson * SUCH DAMAGE.
47155192Srwatson *
48155192Srwatson *	from: unknown origin, 386BSD 0.1
49155192Srwatson *	$Id: olpt.c,v 1.2 1999/07/06 19:23:20 des Exp $
50155192Srwatson */
51155192Srwatson
52155192Srwatson/*
53155192Srwatson * Device Driver for AT parallel printer port
54155192Srwatson * Written by William Jolitz 12/18/90
55155192Srwatson */
56155192Srwatson
57155192Srwatson/*
58155192Srwatson * Parallel port TCP/IP interfaces added.  I looked at the driver from
59155192Srwatson * MACH but this is a complete rewrite, and btw. incompatible, and it
60155192Srwatson * should perform better too.  I have never run the MACH driver though.
61155192Srwatson *
62155192Srwatson * This driver sends two bytes (0x08, 0x00) in front of each packet,
63155192Srwatson * to allow us to distinguish another format later.
64155192Srwatson *
65155192Srwatson * Now added an Linux/Crynwr compatibility mode which is enabled using
66155192Srwatson * IF_LINK0 - Tim Wilkinson.
67155192Srwatson *
68155192Srwatson * TODO:
69155192Srwatson *    Make HDLC/PPP mode, use IF_LLC1 to enable.
70155192Srwatson *
71155192Srwatson * Connect the two computers using a Laplink parallel cable to use this
72156889Srwatson * feature:
73156889Srwatson *
74156889Srwatson *      +----------------------------------------+
75156889Srwatson * 	|A-name	A-End	B-End	Descr.	Port/Bit |
76156889Srwatson *      +----------------------------------------+
77156889Srwatson *	|DATA0	2	15	Data	0/0x01   |
78155192Srwatson *	|-ERROR	15	2	   	1/0x08   |
79156889Srwatson *      +----------------------------------------+
80155192Srwatson *	|DATA1	3	13	Data	0/0x02	 |
81156889Srwatson *	|+SLCT	13	3	   	1/0x10   |
82155192Srwatson *      +----------------------------------------+
83162466Srwatson *	|DATA2	4	12	Data	0/0x04   |
84155192Srwatson *	|+PE	12	4	   	1/0x20   |
85155192Srwatson *      +----------------------------------------+
86155192Srwatson *	|DATA3	5	10	Strobe	0/0x08   |
87155192Srwatson *	|-ACK	10	5	   	1/0x40   |
88155192Srwatson *      +----------------------------------------+
89155192Srwatson *	|DATA4	6	11	Data	0/0x10   |
90155192Srwatson *	|BUSY	11	6	   	1/~0x80  |
91155192Srwatson *      +----------------------------------------+
92155192Srwatson *	|GND	18-25	18-25	GND	-        |
93156889Srwatson *      +----------------------------------------+
94155192Srwatson *
95155192Srwatson * Expect transfer-rates up to 75 kbyte/sec.
96155192Srwatson *
97155192Srwatson * If GCC could correctly grok
98155192Srwatson *	register int port asm("edx")
99155192Srwatson * the code would be cleaner
100155192Srwatson *
101155192Srwatson * Poul-Henning Kamp <phk@freebsd.org>
102155192Srwatson */
103155192Srwatson
104155192Srwatson#include "olpt.h"
105155192Srwatson#include "opt_inet.h"
106155192Srwatson#ifdef PC98
107155192Srwatson#undef INET	/* PLIP is not supported for old PC-98 */
108155192Srwatson#endif
109155192Srwatson
110155192Srwatson#include <sys/param.h>
111155192Srwatson#include <sys/systm.h>
112155192Srwatson#include <sys/conf.h>
113155192Srwatson#include <sys/buf.h>
114155192Srwatson#include <sys/kernel.h>
115156889Srwatson#include <sys/uio.h>
116161635Srwatson#include <sys/syslog.h>
117162466Srwatson#include <machine/clock.h>
118170196Srwatson#include <machine/lpt.h>
119162466Srwatson
120162466Srwatson#include <vm/vm.h>
121162466Srwatson#include <vm/vm_param.h>
122162466Srwatson#include <vm/pmap.h>
123155192Srwatson
124162466Srwatson#ifdef PC98
125162466Srwatson#include <pc98/pc98/pc98.h>
126155192Srwatson#else
127162466Srwatson#include <i386/isa/isa.h>
128162466Srwatson#endif
129162466Srwatson#include <i386/isa/isa_device.h>
130162466Srwatson#include <i386/isa/lptreg.h>
131162466Srwatson
132155192Srwatson#ifdef INET
133155192Srwatson#include <sys/malloc.h>
134155192Srwatson#include <sys/mbuf.h>
135155192Srwatson#include <sys/socket.h>
136156889Srwatson#include <sys/sockio.h>
137156889Srwatson
138155192Srwatson#include <net/if.h>
139155192Srwatson#include <net/if_types.h>
140155192Srwatson#include <net/netisr.h>
141155192Srwatson#include <netinet/in.h>
142155192Srwatson#include <netinet/in_var.h>
143155192Srwatson#include "bpf.h"
144156889Srwatson#if NBPF > 0
145155192Srwatson#include <net/bpf.h>
146155192Srwatson#endif
147155192Srwatson#endif /* INET */
148155192Srwatson
149156889Srwatson
150155192Srwatson#define	LPINITRDY	4	/* wait up to 4 seconds for a ready */
151155192Srwatson#define	LPTOUTINITIAL	10	/* initial timeout to wait for ready 1/10 s */
152156889Srwatson#define	LPTOUTMAX	1	/* maximal timeout 1 s */
153155192Srwatson#define	LPPRI		(PZERO+8)
154155192Srwatson#define	BUFSIZE		1024
155155192Srwatson
156155192Srwatson#ifdef INET
157155192Srwatson#ifndef LPMTU			/* MTU for the lp# interfaces */
158170196Srwatson#define	LPMTU	1500
159155192Srwatson#endif
160155192Srwatson
161155192Srwatson#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
162155192Srwatson#define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
163155192Srwatson#endif
164155192Srwatson
165155192Srwatson#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
166155192Srwatson#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
167155192Srwatson#endif
168155192Srwatson
169155192Srwatson#ifndef LPMAXERRS		/* Max errors before !RUNNING */
170155192Srwatson#define	LPMAXERRS	100
171155192Srwatson#endif
172155192Srwatson
173155192Srwatson#define CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
174155192Srwatson#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
175155192Srwatson#define MLPIPHDRLEN	CLPIPHDRLEN
176155192Srwatson
177155192Srwatson#define LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
178155192Srwatson#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
179155192Srwatson#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
180155192Srwatson#define MLPIPHDRLEN	LPIPHDRLEN
181155192Srwatson#endif
182155192Srwatson
183155192Srwatson#define	LPIPTBLSIZE	256	/* Size of octet translation table */
184155192Srwatson
185155192Srwatson#endif /* INET */
186155192Srwatson
187155192Srwatson#ifndef PC98
188155192Srwatson/* BIOS printer list - used by BIOS probe*/
189155192Srwatson#define	BIOS_LPT_PORTS	0x408
190155192Srwatson#define	BIOS_PORTS	(short *)(KERNBASE+BIOS_LPT_PORTS)
191155192Srwatson#define	BIOS_MAX_LPT	4
192155192Srwatson#endif
193155192Srwatson
194155192Srwatson
195155192Srwatson#ifndef DEBUG
196155192Srwatson#define lprintf(args)
197155192Srwatson#else
198155192Srwatson#define lprintf(args)	do {				\
199155192Srwatson				if (lptflag)		\
200155192Srwatson					printf args;	\
201155192Srwatson			} while (0)
202155192Srwatsonstatic int volatile lptflag = 1;
203155192Srwatson#endif
204155192Srwatson
205155192Srwatson#define	LPTUNIT(s)	((s)&0x03)
206155192Srwatson#define	LPTFLAGS(s)	((s)&0xfc)
207155192Srwatson
208155192Srwatsonstatic struct lpt_softc {
209155192Srwatson	int	sc_port;
210155192Srwatson	short	sc_state;
211155192Srwatson	/* default case: negative prime, negative ack, handshake strobe,
212156889Srwatson	   prime once */
213156889Srwatson	u_char	sc_control;
214155192Srwatson	char	sc_flags;
215155192Srwatson#define LP_POS_INIT	0x04	/* if we are a postive init signal */
216155192Srwatson#define LP_POS_ACK	0x08	/* if we are a positive going ack */
217155192Srwatson#define LP_NO_PRIME	0x10	/* don't prime the printer at all */
218155192Srwatson#define LP_PRIMEOPEN	0x20	/* prime on every open */
219155192Srwatson#define LP_AUTOLF	0x40	/* tell printer to do an automatic lf */
220159277Srwatson#define LP_BYPASS	0x80	/* bypass  printer ready checks */
221159277Srwatson	struct	buf *sc_inbuf;
222172915Scsjp	short	sc_xfercnt ;
223159277Srwatson	char	sc_primed;
224159277Srwatson	char	*sc_cp ;
225159277Srwatson	u_char	sc_irq ;	/* IRQ status of port */
226172915Scsjp#define LP_HAS_IRQ	0x01	/* we have an irq available */
227159277Srwatson#define LP_USE_IRQ	0x02	/* we are using our irq */
228159277Srwatson#define LP_ENABLE_IRQ	0x04	/* enable IRQ on open */
229159277Srwatson	u_char	sc_backoff ;	/* time to call lptout() again */
230159277Srwatson
231155192Srwatson#ifdef INET
232155192Srwatson	struct  ifnet	sc_if;
233155192Srwatson	u_char		*sc_ifbuf;
234160136Swsalamon	int		sc_iferrs;
235160136Swsalamon#endif
236160136Swsalamon} lpt_sc[NOLPT] ;
237160136Swsalamon
238160136Swsalamon/* bits for state */
239160136Swsalamon#define	OPEN		(1<<0)	/* device is open */
240160136Swsalamon#define	ASLP		(1<<1)	/* awaiting draining of printer */
241160136Swsalamon#define	ERROR		(1<<2)	/* error was received from printer */
242160136Swsalamon#define	OBUSY		(1<<3)	/* printer is busy doing output */
243160136Swsalamon#define LPTOUT		(1<<4)	/* timeout while not selected */
244160136Swsalamon#define TOUT		(1<<5)	/* timeout while not selected */
245160136Swsalamon#define INIT		(1<<6)	/* waiting to initialize for open */
246160136Swsalamon#define INTERRUPTED	(1<<7)	/* write call was interrupted */
247160136Swsalamon
248160136Swsalamon
249160136Swsalamon/* status masks to interrogate printer status */
250160136Swsalamon#define RDY_MASK	(LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)	/* ready ? */
251160136Swsalamon#define LP_READY	(LPS_SEL|LPS_NBSY|LPS_NERR)
252160136Swsalamon
253160136Swsalamon/* Printer Ready condition  - from lpa.c */
254160136Swsalamon/* Only used in polling code */
255160136Swsalamon#ifdef PC98
256160136Swsalamon#define	NOT_READY(x)	((inb(x) & LPS_NBSY) != LPS_NBSY)
257155192Srwatson#else	/* IBM-PC */
258155192Srwatson#define	LPS_INVERT	(LPS_NBSY | LPS_NACK |           LPS_SEL | LPS_NERR)
259155192Srwatson#define	LPS_MASK	(LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
260155192Srwatson#define	NOT_READY(x)	((inb(x)^LPS_INVERT)&LPS_MASK)
261155192Srwatson#endif
262155192Srwatson
263155192Srwatson#define	MAX_SLEEP	(hz*5)	/* Timeout while waiting for device ready */
264155192Srwatson#define	MAX_SPIN	20	/* Max delay for device ready in usecs */
265155192Srwatson
266155192Srwatsonstatic timeout_t lptout;
267155192Srwatsonstatic int	lptprobe (struct isa_device *dvp);
268156889Srwatsonstatic int	lptattach (struct isa_device *isdp);
269155192Srwatsonstatic ointhand2_t	lptintr;
270156889Srwatson
271156889Srwatson#ifdef INET
272155192Srwatson
273156889Srwatson/* Tables for the lp# interface */
274156889Srwatsonstatic u_char *txmith;
275155192Srwatson#define txmitl (txmith+(1*LPIPTBLSIZE))
276155192Srwatson#define trecvh (txmith+(2*LPIPTBLSIZE))
277155192Srwatson#define trecvl (txmith+(3*LPIPTBLSIZE))
278156889Srwatson
279156889Srwatsonstatic u_char *ctxmith;
280156889Srwatson#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
281155192Srwatson#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
282156889Srwatson#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
283156889Srwatson
284155192Srwatson/* Functions for the lp# interface */
285155192Srwatsonstatic void lpattach(struct lpt_softc *,int);
286155192Srwatson#ifndef PC98
287156889Srwatsonstatic int lpinittables(void);
288156889Srwatson#endif
289156889Srwatsonstatic int lpioctl(struct ifnet *, u_long, caddr_t);
290155192Srwatsonstatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
291156889Srwatson	struct rtentry *);
292156889Srwatsonstatic void lpintr(int);
293155192Srwatson#endif /* INET */
294156889Srwatson
295156889Srwatsonstruct	isa_driver olptdriver = {
296155192Srwatson	lptprobe, lptattach, "olpt"
297156889Srwatson};
298156889Srwatson
299155192Srwatsonstatic	d_open_t	lptopen;
300156889Srwatsonstatic	d_close_t	lptclose;
301156889Srwatsonstatic	d_write_t	lptwrite;
302155192Srwatsonstatic	d_ioctl_t	lptioctl;
303155192Srwatson
304155192Srwatson#define CDEV_MAJOR 16
305156889Srwatsonstatic struct cdevsw lpt_cdevsw = {
306156889Srwatson	/* open */	lptopen,
307156889Srwatson	/* close */	lptclose,
308155192Srwatson	/* read */	noread,
309156889Srwatson	/* write */	lptwrite,
310156889Srwatson	/* ioctl */	lptioctl,
311155192Srwatson	/* stop */	nostop,
312155192Srwatson	/* reset */	noreset,
313155192Srwatson	/* devtotty */	nodevtotty,
314156889Srwatson	/* poll */	nopoll,
315156889Srwatson	/* mmap */	nommap,
316156889Srwatson	/* strategy */	nostrategy,
317155192Srwatson	/* name */	"lpt",
318156889Srwatson	/* parms */	noparms,
319156889Srwatson	/* maj */	CDEV_MAJOR,
320155192Srwatson	/* dump */	nodump,
321155192Srwatson	/* psize */	nopsize,
322155192Srwatson	/* flags */	0,
323156889Srwatson	/* maxio */	0,
324155192Srwatson	/* bmaj */	-1
325156889Srwatson};
326156889Srwatson
327155192Srwatson#ifndef PC98
328156889Srwatson/*
329156889Srwatson * Internal routine to lptprobe to do port tests of one byte value
330155192Srwatson */
331155192Srwatsonstatic int
332155192Srwatsonlpt_port_test (int port, u_char data, u_char mask)
333156889Srwatson{
334155192Srwatson	int	temp, timeout;
335156889Srwatson
336155192Srwatson	data = data & mask;
337155192Srwatson	outb(port, data);
338156889Srwatson	timeout = 10000;
339155192Srwatson	do {
340155192Srwatson		DELAY(10);
341155192Srwatson		temp = inb(port) & mask;
342156889Srwatson	}
343156889Srwatson	while (temp != data && --timeout);
344156889Srwatson	lprintf(("Port 0x%x\tout=%x\tin=%x\ttout=%d\n",
345155192Srwatson		port, data, temp, timeout));
346156889Srwatson	return (temp == data);
347156889Srwatson}
348155192Srwatson#endif /* PC98 */
349155192Srwatson
350155192Srwatson/*
351156889Srwatson * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
352156889Srwatson * Based partially on Rod Grimes' printer probe
353156889Srwatson *
354155192Srwatson * Logic:
355155192Srwatson *	1) If no port address was given, use the bios detected ports
356155192Srwatson *	   and autodetect what ports the printers are on.
357155192Srwatson *	2) Otherwise, probe the data port at the address given,
358155192Srwatson *	   using the method in Rod Grimes' port probe.
359155192Srwatson *	   (Much code ripped off directly from Rod's probe.)
360155192Srwatson *
361155192Srwatson * Comments from Rod's probe:
362155192Srwatson * Logic:
363156889Srwatson *	1) You should be able to write to and read back the same value
364156889Srwatson *	   to the data port.  Do an alternating zeros, alternating ones,
365156889Srwatson *	   walking zero, and walking one test to check for stuck bits.
366156889Srwatson *
367155192Srwatson *	2) You should be able to write to and read back the same value
368155192Srwatson *	   to the control port lower 5 bits, the upper 3 bits are reserved
369155192Srwatson *	   per the IBM PC technical reference manauls and different boards
370156889Srwatson *	   do different things with them.  Do an alternating zeros, alternating
371155192Srwatson *	   ones, walking zero, and walking one test to check for stuck bits.
372155192Srwatson *
373155192Srwatson *	   Some printers drag the strobe line down when the are powered off
374155192Srwatson * 	   so this bit has been masked out of the control port test.
375155192Srwatson *
376155192Srwatson *	   XXX Some printers may not like a fast pulse on init or strobe, I
377155192Srwatson *	   don't know at this point, if that becomes a problem these bits
378155192Srwatson *	   should be turned off in the mask byte for the control port test.
379155192Srwatson *
380155192Srwatson *	   We are finally left with a mask of 0x14, due to some printers
381155192Srwatson *	   being adamant about holding other bits high ........
382155192Srwatson *
383155192Srwatson *	   Before probing the control port, we write a 0 to the data port -
384155192Srwatson *	   If not, some printers chuck out garbage when the strobe line
385155192Srwatson *	   gets toggled.
386155192Srwatson *
387155192Srwatson *	3) Set the data and control ports to a value of 0
388168688Scsjp *
389168688Scsjp *	This probe routine has been tested on Epson Lx-800, HP LJ3P,
390168688Scsjp *	Epson FX-1170 and C.Itoh 8510RM
391168688Scsjp *	printers.
392168688Scsjp *	Quick exit on fail added.
393168688Scsjp */
394168688Scsjp
395168688Scsjpint
396168688Scsjplptprobe(struct isa_device *dvp)
397168688Scsjp{
398168688Scsjp#ifdef PC98
399168688Scsjp#define PC98_OLD_LPT 0x40
400168688Scsjp#define PC98_IEEE_1284_FUNCTION 0x149
401168688Scsjp	unsigned int pc98_ieee_mode, tmp;
402168688Scsjp
403168688Scsjp	if (dvp->id_iobase == PC98_OLD_LPT) {
404168688Scsjp		tmp = inb(PC98_IEEE_1284_FUNCTION);
405168688Scsjp		pc98_ieee_mode = tmp;
406168688Scsjp		if ((tmp & 0x10) == 0x10) {
407168688Scsjp			outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10);
408168688Scsjp			tmp = inb(PC98_IEEE_1284_FUNCTION);
409168688Scsjp			if ((tmp & 0x10) != 0x10) {
410168688Scsjp				outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode);
411168688Scsjp				return 0;
412168688Scsjp			}
413168688Scsjp		}
414168688Scsjp	}
415168688Scsjp	return 8;
416168688Scsjp#else
417168688Scsjp	int		port;
418168688Scsjp	static short	next_bios_lpt = 0;
419168688Scsjp	int		status;
420168688Scsjp	static u_char	testbyte[18] = {
421168688Scsjp		0x55,			/* alternating zeros */
422155192Srwatson		0xaa,			/* alternating ones */
423156889Srwatson		0xfe, 0xfd, 0xfb, 0xf7,
424156889Srwatson		0xef, 0xdf, 0xbf, 0x7f,	/* walking zero */
425156889Srwatson		0x01, 0x02, 0x04, 0x08,
426155192Srwatson		0x10, 0x20, 0x40, 0x80	/* walking one */
427155192Srwatson	};
428156889Srwatson	int		i;
429155192Srwatson
430155192Srwatson	/*
431155192Srwatson	 * Make sure there is some way for lptopen to see that
432155192Srwatson	 * the port is not configured
433162990Srwatson	 * This 0 will remain if the port isn't attached
434155192Srwatson	 */
435156889Srwatson	(lpt_sc + dvp->id_unit)->sc_port = 0;
436162990Srwatson
437162990Srwatson	status = IO_LPTSIZE;
438155192Srwatson	/* If port not specified, use bios list */
439155192Srwatson	if(dvp->id_iobase < 0) {	/* port? */
440156889Srwatson		if((next_bios_lpt < BIOS_MAX_LPT) &&
441156889Srwatson				(*(BIOS_PORTS+next_bios_lpt) != 0) ) {
442156889Srwatson			dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++);
443155192Srwatson			goto end_probe;
444155192Srwatson		} else
445155192Srwatson			return (0);
446155192Srwatson	}
447155192Srwatson
448156889Srwatson	/* Port was explicitly specified */
449156889Srwatson	/* This allows probing of ports unknown to the BIOS */
450155192Srwatson	port = dvp->id_iobase + lpt_data;
451155192Srwatson	for (i = 0; i < 18; i++) {
452155192Srwatson		if (!lpt_port_test(port, testbyte[i], 0xff)) {
453156889Srwatson			status = 0;
454156889Srwatson			goto end_probe;
455155192Srwatson		}
456155192Srwatson	}
457155192Srwatson
458155192Srwatsonend_probe:
459155192Srwatson	/* write 0's to control and data ports */
460155192Srwatson	outb(dvp->id_iobase+lpt_data, 0);
461155192Srwatson	outb(dvp->id_iobase+lpt_control, 0);
462155192Srwatson
463155192Srwatson	return (status);
464155192Srwatson#endif
465155192Srwatson}
466155192Srwatson
467155192Srwatson/* XXX Todo - try and detect if interrupt is working */
468155192Srwatsonint
469155192Srwatsonlptattach(struct isa_device *isdp)
470155192Srwatson{
471155192Srwatson	struct	lpt_softc	*sc;
472155192Srwatson	int	unit;
473155192Srwatson
474155192Srwatson	isdp->id_ointr = lptintr;
475155192Srwatson	unit = isdp->id_unit;
476155192Srwatson	sc = lpt_sc + unit;
477155192Srwatson	sc->sc_port = isdp->id_iobase;
478155192Srwatson	sc->sc_primed = 0;	/* not primed yet */
479155192Srwatson#ifdef PC98
480155192Srwatson	outb(sc->sc_port+lpt_pstb_ctrl,	LPC_DIS_PSTB);	/* PSTB disable */
481155192Srwatson	outb(sc->sc_port+lpt_control,	LPC_MODE8255);	/* 8255 mode set */
482155192Srwatson	outb(sc->sc_port+lpt_control,	LPC_NIRQ8);	/* IRQ8 inactive */
483155192Srwatson	outb(sc->sc_port+lpt_control,	LPC_NPSTB);	/* PSTB inactive */
484155192Srwatson	outb(sc->sc_port+lpt_pstb_ctrl,	LPC_EN_PSTB);	/* PSTB enable */
485155192Srwatson#else
486155192Srwatson	outb(sc->sc_port+lpt_control, LPC_NINIT);
487155192Srwatson#endif
488155192Srwatson
489155192Srwatson	/* check if we can use interrupt */
490155192Srwatson	lprintf(("oldirq %x\n", sc->sc_irq));
491155192Srwatson	if (isdp->id_irq) {
492155192Srwatson		sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
493155192Srwatson		printf("lpt%d: Interrupt-driven port\n", unit);
494155192Srwatson#ifdef INET
495155192Srwatson		lpattach(sc, unit);
496155192Srwatson#endif
497155192Srwatson	} else {
498155192Srwatson		sc->sc_irq = 0;
499155192Srwatson		lprintf(("lpt%d: Polled port\n", unit));
500155192Srwatson	}
501171066Scsjp	lprintf(("irq %x\n", sc->sc_irq));
502171066Scsjp
503171066Scsjp	/* XXX what to do about the flags in the minor number? */
504171066Scsjp	make_dev(&lpt_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit);
505156889Srwatson	make_dev(&lpt_cdevsw, unit | LP_BYPASS,
506156889Srwatson			UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
507155192Srwatson	return (1);
508156889Srwatson}
509156889Srwatson
510155192Srwatson/*
511156889Srwatson * lptopen -- reset the printer, then wait until it's selected and not busy.
512156889Srwatson *	If LP_BYPASS flag is selected, then we do not try to select the
513155192Srwatson *	printer -- this is just used for passing ioctls.
514156889Srwatson */
515156889Srwatson
516155192Srwatsonstatic	int
517156889Srwatsonlptopen (dev_t dev, int flags, int fmt, struct proc *p)
518156889Srwatson{
519155192Srwatson	struct lpt_softc *sc;
520156889Srwatson	int s;
521156889Srwatson#ifdef PC98
522155192Srwatson	int port;
523155192Srwatson#else
524155192Srwatson	int trys, port;
525155192Srwatson#endif
526155192Srwatson	u_int unit = LPTUNIT(minor(dev));
527171066Scsjp
528171066Scsjp	sc = lpt_sc + unit;
529171066Scsjp	if ((unit >= NOLPT) || (sc->sc_port == 0))
530171066Scsjp		return (ENXIO);
531171066Scsjp
532171066Scsjp#ifdef INET
533171066Scsjp	if (sc->sc_if.if_flags & IFF_UP)
534171066Scsjp		return(EBUSY);
535171066Scsjp#endif
536171066Scsjp
537171066Scsjp	if (sc->sc_state) {
538171066Scsjp		lprintf(("lp: still open %x\n", sc->sc_state));
539171066Scsjp		return(EBUSY);
540171066Scsjp	} else
541171066Scsjp		sc->sc_state |= INIT;
542171066Scsjp
543171066Scsjp	sc->sc_flags = LPTFLAGS(minor(dev));
544171066Scsjp
545171066Scsjp	/* Check for open with BYPASS flag set. */
546171066Scsjp	if (sc->sc_flags & LP_BYPASS) {
547171066Scsjp		sc->sc_state = OPEN;
548171066Scsjp		return(0);
549171066Scsjp	}
550171066Scsjp
551171066Scsjp	s = spltty();
552171066Scsjp	lprintf(("lp flags 0x%x\n", sc->sc_flags));
553171066Scsjp	port = sc->sc_port;
554171066Scsjp
555171066Scsjp	/* set IRQ status according to ENABLE_IRQ flag */
556171066Scsjp	if (sc->sc_irq & LP_ENABLE_IRQ)
557171066Scsjp		sc->sc_irq |= LP_USE_IRQ;
558155192Srwatson	else
559155192Srwatson		sc->sc_irq &= ~LP_USE_IRQ;
560156889Srwatson
561156889Srwatson	/* init printer */
562156889Srwatson#ifndef PC98
563155192Srwatson	if ((sc->sc_flags & LP_NO_PRIME) == 0) {
564155192Srwatson		if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
565155192Srwatson			outb(port+lpt_control, 0);
566155192Srwatson			sc->sc_primed++;
567155192Srwatson			DELAY(500);
568155192Srwatson		}
569155192Srwatson	}
570155192Srwatson
571155192Srwatson	outb (port+lpt_control, LPC_SEL|LPC_NINIT);
572155192Srwatson
573155192Srwatson	/* wait till ready (printer running diagnostics) */
574155192Srwatson	trys = 0;
575155192Srwatson	do {
576155192Srwatson		/* ran out of waiting for the printer */
577155192Srwatson		if (trys++ >= LPINITRDY*4) {
578155192Srwatson			splx(s);
579155192Srwatson			sc->sc_state = 0;
580155192Srwatson			lprintf(("status %x\n", inb(port+lpt_status)));
581155192Srwatson			return (EBUSY);
582155192Srwatson		}
583155192Srwatson
584155192Srwatson		/* wait 1/4 second, give up if we get a signal */
585156889Srwatson		if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) !=
586155192Srwatson		    EWOULDBLOCK) {
587155192Srwatson			sc->sc_state = 0;
588156889Srwatson			splx(s);
589155192Srwatson			return (EBUSY);
590155192Srwatson		}
591155192Srwatson
592155192Srwatson		/* is printer online and ready for output */
593155192Srwatson	} while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
594155192Srwatson		 (LPS_SEL|LPS_NBSY|LPS_NERR));
595155192Srwatson
596155192Srwatson	sc->sc_control = LPC_SEL|LPC_NINIT;
597155192Srwatson	if (sc->sc_flags & LP_AUTOLF)
598155192Srwatson		sc->sc_control |= LPC_AUTOL;
599155192Srwatson
600155192Srwatson	/* enable interrupt if interrupt-driven */
601155192Srwatson	if (sc->sc_irq & LP_USE_IRQ)
602162990Srwatson		sc->sc_control |= LPC_ENA;
603155192Srwatson
604162990Srwatson	outb(port+lpt_control, sc->sc_control);
605155192Srwatson#endif
606155192Srwatson
607155192Srwatson	sc->sc_state = OPEN;
608162990Srwatson	sc->sc_inbuf = geteblk(BUFSIZE);
609155192Srwatson	sc->sc_xfercnt = 0;
610162990Srwatson	splx(s);
611162990Srwatson
612162990Srwatson	/* only use timeout if using interrupt */
613162990Srwatson	lprintf(("irq %x\n", sc->sc_irq));
614162990Srwatson	if (sc->sc_irq & LP_USE_IRQ) {
615162990Srwatson		sc->sc_state |= TOUT;
616162990Srwatson		timeout (lptout, (caddr_t)sc,
617162990Srwatson			 (sc->sc_backoff = hz/LPTOUTINITIAL));
618162990Srwatson	}
619155192Srwatson
620162990Srwatson	lprintf(("opened.\n"));
621162990Srwatson	return(0);
622162990Srwatson}
623162990Srwatson
624155192Srwatsonstatic void
625155192Srwatsonlptout (void *arg)
626155192Srwatson{
627155192Srwatson	struct lpt_softc *sc = arg;
628162990Srwatson	int pl;
629162990Srwatson
630156889Srwatson	lprintf(("T %x ", inb(sc->sc_port+lpt_status)));
631156889Srwatson	if (sc->sc_state & OPEN) {
632156889Srwatson		sc->sc_backoff++;
633155192Srwatson		if (sc->sc_backoff > hz/LPTOUTMAX)
634155192Srwatson			sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
635159278Srwatson		timeout (lptout, (caddr_t)sc, sc->sc_backoff);
636159278Srwatson	} else
637159278Srwatson		sc->sc_state &= ~TOUT;
638159278Srwatson
639159278Srwatson	if (sc->sc_state & ERROR)
640159278Srwatson		sc->sc_state &= ~ERROR;
641155192Srwatson
642155192Srwatson	/*
643155192Srwatson	 * Avoid possible hangs do to missed interrupts
644155559Srwatson	 */
645155192Srwatson	if (sc->sc_xfercnt) {
646162990Srwatson		pl = spltty();
647162419Scsjp		lptintr(sc - lpt_sc);
648155192Srwatson		splx(pl);
649155192Srwatson	} else {
650155192Srwatson		sc->sc_state &= ~OBUSY;
651155192Srwatson		wakeup((caddr_t)sc);
652155192Srwatson	}
653155192Srwatson}
654155192Srwatson
655155192Srwatson/*
656155192Srwatson * lptclose -- close the device, free the local line buffer.
657155192Srwatson *
658162990Srwatson * Check for interrupted write call added.
659162990Srwatson */
660155192Srwatson
661155192Srwatsonstatic	int
662155192Srwatsonlptclose(dev_t dev, int flags, int fmt, struct proc *p)
663155192Srwatson{
664155192Srwatson	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
665155192Srwatson#ifndef PC98
666155192Srwatson	int port = sc->sc_port;
667162990Srwatson#endif
668162990Srwatson
669162990Srwatson	if(sc->sc_flags & LP_BYPASS)
670162990Srwatson		goto end_close;
671162990Srwatson
672162990Srwatson	sc->sc_state &= ~OPEN;
673155192Srwatson
674155192Srwatson#ifndef PC98
675155192Srwatson	/* if the last write was interrupted, don't complete it */
676155192Srwatson	if((!(sc->sc_state  & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ))
677155192Srwatson		while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
678155192Srwatson			(LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
679155192Srwatson			/* wait 1/4 second, give up if we get a signal */
680155192Srwatson			if (tsleep ((caddr_t)sc, LPPRI|PCATCH,
681156889Srwatson				"lpclose", hz) != EWOULDBLOCK)
682155192Srwatson				break;
683155192Srwatson
684155192Srwatson	outb(sc->sc_port+lpt_control, LPC_NINIT);
685156889Srwatson#endif
686156889Srwatson	brelse(sc->sc_inbuf);
687155192Srwatson
688155192Srwatsonend_close:
689155192Srwatson	sc->sc_state = 0;
690155192Srwatson	sc->sc_xfercnt = 0;
691156889Srwatson	lprintf(("closed.\n"));
692155192Srwatson	return(0);
693155192Srwatson}
694155192Srwatson
695155192Srwatson/*
696155192Srwatson * pushbytes()
697155192Srwatson *	Workhorse for actually spinning and writing bytes to printer
698155192Srwatson *	Derived from lpa.c
699155192Srwatson *	Originally by ?
700155192Srwatson *
701155192Srwatson *	This code is only used when we are polling the port
702155192Srwatson */
703155192Srwatsonstatic int
704156889Srwatsonpushbytes(struct lpt_softc * sc)
705155192Srwatson{
706155192Srwatson	int spin, err, tic;
707155192Srwatson	char ch;
708155192Srwatson	int port = sc->sc_port;
709155192Srwatson
710155192Srwatson	lprintf(("p"));
711155192Srwatson	/* loop for every character .. */
712155192Srwatson	while (sc->sc_xfercnt > 0) {
713155192Srwatson		/* printer data */
714155192Srwatson		ch = *(sc->sc_cp);
715155192Srwatson		sc->sc_cp++;
716155192Srwatson		sc->sc_xfercnt--;
717155192Srwatson
718160136Swsalamon		/*
719160136Swsalamon		 * Wait for printer ready.
720160136Swsalamon		 * Loop 20 usecs testing BUSY bit, then sleep
721160136Swsalamon		 * for exponentially increasing timeout. (vak)
722160136Swsalamon		 */
723160136Swsalamon		for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
724160136Swsalamon			DELAY(1);	/* XXX delay is NOT this accurate! */
725160136Swsalamon		if (spin >= MAX_SPIN) {
726160136Swsalamon			tic = 0;
727160136Swsalamon			while (NOT_READY(port+lpt_status)) {
728160136Swsalamon				/*
729160136Swsalamon				 * Now sleep, every cycle a
730160136Swsalamon				 * little longer ..
731160136Swsalamon				 */
732160136Swsalamon				tic = tic + tic + 1;
733160136Swsalamon				/*
734160136Swsalamon				 * But no more than 10 seconds. (vak)
735160136Swsalamon				 */
736160136Swsalamon				if (tic > MAX_SLEEP)
737160136Swsalamon					tic = MAX_SLEEP;
738160136Swsalamon				err = tsleep((caddr_t)sc, LPPRI,
739160136Swsalamon					"lptpoll", tic);
740160136Swsalamon				if (err != EWOULDBLOCK) {
741160136Swsalamon					return (err);
742160136Swsalamon				}
743160136Swsalamon			}
744160136Swsalamon		}
745160136Swsalamon
746160136Swsalamon		/* output data */
747160136Swsalamon		outb(port+lpt_data, ch);
748160136Swsalamon#ifdef PC98
749160136Swsalamon		DELAY(1);
750160136Swsalamon		outb(port+lpt_control, LPC_PSTB);
751160136Swsalamon		DELAY(1);
752160136Swsalamon		outb(port+lpt_control, LPC_NPSTB);
753161813Swsalamon#else
754161813Swsalamon		/* strobe */
755161813Swsalamon		outb(port+lpt_control, sc->sc_control|LPC_STB);
756161813Swsalamon		outb(port+lpt_control, sc->sc_control);
757161813Swsalamon#endif
758161813Swsalamon
759161813Swsalamon	}
760161813Swsalamon	return(0);
761161813Swsalamon}
762161813Swsalamon
763161813Swsalamon/*
764161813Swsalamon * lptwrite --copy a line from user space to a local buffer, then call
765161813Swsalamon * putc to get the chars moved to the output queue.
766161813Swsalamon *
767155192Srwatson * Flagging of interrupted write added.
768155192Srwatson */
769156889Srwatson
770156889Srwatsonstatic	int
771155192Srwatsonlptwrite(dev_t dev, struct uio * uio, int ioflag)
772155192Srwatson{
773155192Srwatson	register unsigned n;
774155192Srwatson	int pl, err;
775156889Srwatson	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
776162990Srwatson
777162990Srwatson	if(sc->sc_flags & LP_BYPASS) {
778162990Srwatson		/* we can't do writes in bypass mode */
779155192Srwatson		return(EPERM);
780155192Srwatson	}
781162990Srwatson
782155192Srwatson	sc->sc_state &= ~INTERRUPTED;
783155192Srwatson	while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
784155192Srwatson		sc->sc_cp = sc->sc_inbuf->b_data ;
785155192Srwatson		uiomove(sc->sc_cp, n, uio);
786155192Srwatson		sc->sc_xfercnt = n ;
787155192Srwatson		while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
788162990Srwatson			lprintf(("i"));
789162990Srwatson			/* if the printer is ready for a char, */
790162990Srwatson			/* give it one */
791162990Srwatson			if ((sc->sc_state & OBUSY) == 0){
792162990Srwatson				lprintf(("\nC %d. ", sc->sc_xfercnt));
793155192Srwatson				pl = spltty();
794155192Srwatson				lptintr(sc - lpt_sc);
795156889Srwatson				(void) splx(pl);
796155192Srwatson			}
797155192Srwatson			lprintf(("W "));
798155192Srwatson			if (sc->sc_state & OBUSY)
799155192Srwatson				if ((err = tsleep ((caddr_t)sc,
800155192Srwatson					 LPPRI|PCATCH, "lpwrite", 0))) {
801155192Srwatson					sc->sc_state |= INTERRUPTED;
802155192Srwatson					return(err);
803155192Srwatson				}
804155192Srwatson		}
805155192Srwatson		/* check to see if we must do a polled write */
806155192Srwatson		if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
807156889Srwatson			lprintf(("p"));
808155192Srwatson			if((err = pushbytes(sc)))
809155192Srwatson				return(err);
810155192Srwatson		}
811155192Srwatson	}
812155192Srwatson	return(0);
813155192Srwatson}
814155192Srwatson
815155192Srwatson/*
816155192Srwatson * lptintr -- handle printer interrupts which occur when the printer is
817155192Srwatson * ready to accept another char.
818156889Srwatson *
819155192Srwatson * do checking for interrupted write call.
820155192Srwatson */
821155192Srwatson
822155192Srwatsonstatic void
823155192Srwatsonlptintr(int unit)
824155192Srwatson{
825155192Srwatson	struct lpt_softc *sc = lpt_sc + unit;
826156889Srwatson#ifndef PC98
827155192Srwatson	int port = sc->sc_port, sts;
828155192Srwatson	int i;
829155192Srwatson#endif
830155192Srwatson
831155192Srwatson#ifdef INET
832155192Srwatson	if(sc->sc_if.if_flags & IFF_UP) {
833155192Srwatson	    lpintr(unit);
834156889Srwatson	    return;
835155192Srwatson	}
836155192Srwatson#endif /* INET */
837155192Srwatson
838155192Srwatson#ifndef PC98
839155192Srwatson	/*
840155192Srwatson	 * Is printer online and ready for output?
841155192Srwatson	 *
842155192Srwatson	 * Avoid falling back to lptout() too quickly.  First spin-loop
843155192Srwatson	 * to see if the printer will become ready ``really soon now''.
844155192Srwatson	 */
845155192Srwatson	for (i = 0;
846155192Srwatson	     i < 100 &&
847155192Srwatson	     ((sts=inb(port+lpt_status)) & RDY_MASK) != LP_READY;
848156889Srwatson	     i++) ;
849155192Srwatson	if ((sts & RDY_MASK) == LP_READY) {
850155192Srwatson		sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR;
851155192Srwatson		sc->sc_backoff = hz/LPTOUTINITIAL;
852155192Srwatson
853155192Srwatson		if (sc->sc_xfercnt) {
854155192Srwatson			/* send char */
855155271Srwatson			/*lprintf(("%x ", *sc->sc_cp)); */
856155271Srwatson			outb(port+lpt_data, *sc->sc_cp++) ;
857155192Srwatson			outb(port+lpt_control, sc->sc_control|LPC_STB);
858155192Srwatson			/* DELAY(X) */
859156889Srwatson			outb(port+lpt_control, sc->sc_control);
860155192Srwatson
861156889Srwatson			/* any more data for printer */
862155192Srwatson			if(--(sc->sc_xfercnt) > 0) return;
863156889Srwatson		}
864155192Srwatson
865155192Srwatson		/*
866155192Srwatson		 * No more data waiting for printer.
867155192Srwatson		 * Wakeup is not done if write call was interrupted.
868155192Srwatson		 */
869155192Srwatson		sc->sc_state &= ~OBUSY;
870155192Srwatson		if(!(sc->sc_state & INTERRUPTED))
871155192Srwatson			wakeup((caddr_t)sc);
872155192Srwatson		lprintf(("w "));
873155192Srwatson		return;
874155192Srwatson	} else	{	/* check for error */
875155192Srwatson		if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
876162990Srwatson				(sc->sc_state & OPEN))
877155192Srwatson			sc->sc_state |= ERROR;
878155192Srwatson		/* lptout() will jump in and try to restart. */
879155192Srwatson	}
880155192Srwatson#endif
881155192Srwatson	lprintf(("sts %x ", sts));
882155192Srwatson}
883155192Srwatson
884155192Srwatsonstatic	int
885155192Srwatsonlptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
886155192Srwatson{
887155192Srwatson	int	error = 0;
888155192Srwatson        struct	lpt_softc *sc;
889155192Srwatson        u_int	unit = LPTUNIT(minor(dev));
890155192Srwatson	u_char	old_sc_irq;	/* old printer IRQ status */
891155192Srwatson
892155192Srwatson        sc = lpt_sc + unit;
893155192Srwatson
894155192Srwatson	switch (cmd) {
895155192Srwatson	case LPT_IRQ :
896155192Srwatson		if(sc->sc_irq & LP_HAS_IRQ) {
897155192Srwatson			/*
898155192Srwatson			 * NOTE:
899155192Srwatson			 * If the IRQ status is changed,
900155192Srwatson			 * this will only be visible on the
901155192Srwatson			 * next open.
902155192Srwatson			 *
903155192Srwatson			 * If interrupt status changes,
904155192Srwatson			 * this gets syslog'd.
905155192Srwatson			 */
906155271Srwatson			old_sc_irq = sc->sc_irq;
907155192Srwatson			if(*(int*)data == 0)
908155192Srwatson				sc->sc_irq &= (~LP_ENABLE_IRQ);
909155192Srwatson			else
910155192Srwatson				sc->sc_irq |= LP_ENABLE_IRQ;
911156889Srwatson			if (old_sc_irq != sc->sc_irq )
912155192Srwatson				log(LOG_NOTICE, "lpt%c switched to %s mode\n",
913155192Srwatson					(char)unit+'0',
914155192Srwatson					(sc->sc_irq & LP_ENABLE_IRQ)?
915155192Srwatson					"interrupt-driven":"polled");
916155192Srwatson		} else /* polled port */
917155192Srwatson			error = EOPNOTSUPP;
918155192Srwatson		break;
919155192Srwatson	default:
920155192Srwatson		error = ENODEV;
921155192Srwatson	}
922155192Srwatson
923155192Srwatson	return(error);
924155192Srwatson}
925155192Srwatson
926155192Srwatson#ifdef INET
927155192Srwatson
928155192Srwatsonstatic void
929155192Srwatsonlpattach (struct lpt_softc *sc, int unit)
930155192Srwatson{
931155192Srwatson	struct ifnet *ifp = &sc->sc_if;
932155192Srwatson
933155192Srwatson	ifp->if_softc = sc;
934155192Srwatson	ifp->if_name = "lp";
935155192Srwatson	ifp->if_unit = unit;
936155192Srwatson	ifp->if_mtu = LPMTU;
937155192Srwatson	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
938155192Srwatson	ifp->if_ioctl = lpioctl;
939155192Srwatson	ifp->if_output = lpoutput;
940155271Srwatson	ifp->if_type = IFT_PARA;
941155192Srwatson	ifp->if_hdrlen = 0;
942155192Srwatson	ifp->if_addrlen = 0;
943155192Srwatson	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
944155192Srwatson	if_attach(ifp);
945155192Srwatson	printf("lp%d: TCP/IP capable interface\n", unit);
946155192Srwatson
947155192Srwatson#if NBPF > 0
948155192Srwatson	bpfattach(ifp, DLT_NULL, LPIPHDRLEN);
949155192Srwatson#endif
950155192Srwatson}
951155192Srwatson
952155192Srwatson#ifndef PC98
953155192Srwatson/*
954155192Srwatson * Build the translation tables for the LPIP (BSD unix) protocol.
955155192Srwatson * We don't want to calculate these nasties in our tight loop, so we
956155192Srwatson * precalculate them when we initialize.
957155192Srwatson */
958155192Srwatsonstatic int
959155192Srwatsonlpinittables (void)
960155192Srwatson{
961155192Srwatson    int i;
962155192Srwatson
963155192Srwatson    if (!txmith)
964155192Srwatson	txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
965155192Srwatson
966162990Srwatson    if (!txmith)
967155192Srwatson	return 1;
968155192Srwatson
969155192Srwatson    if (!ctxmith)
970155192Srwatson	ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
971155192Srwatson
972155192Srwatson    if (!ctxmith)
973155192Srwatson	return 1;
974155192Srwatson
975155192Srwatson    for (i=0; i < LPIPTBLSIZE; i++) {
976155192Srwatson	ctxmith[i] = (i & 0xF0) >> 4;
977156889Srwatson	ctxmitl[i] = 0x10 | (i & 0x0F);
978155192Srwatson	ctrecvh[i] = (i & 0x78) << 1;
979155192Srwatson	ctrecvl[i] = (i & 0x78) >> 3;
980155192Srwatson    }
981155192Srwatson
982155192Srwatson    for (i=0; i < LPIPTBLSIZE; i++) {
983155192Srwatson	txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
984155192Srwatson	txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
985156889Srwatson	trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
986155192Srwatson	trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
987155192Srwatson    }
988155192Srwatson
989155192Srwatson    return 0;
990155192Srwatson}
991155192Srwatson#endif /* PC98 */
992155192Srwatson
993155192Srwatson/*
994155192Srwatson * Process an ioctl request.
995155192Srwatson */
996155192Srwatson
997155192Srwatsonstatic int
998155192Srwatsonlpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
999155192Srwatson{
1000155192Srwatson    struct lpt_softc *sc = lpt_sc + ifp->if_unit;
1001155192Srwatson    struct ifaddr *ifa = (struct ifaddr *)data;
1002155192Srwatson    struct ifreq *ifr = (struct ifreq *)data;
1003155192Srwatson    u_char *ptr;
1004155192Srwatson
1005155192Srwatson    switch (cmd) {
1006155192Srwatson
1007155192Srwatson    case SIOCSIFDSTADDR:
1008155192Srwatson    case SIOCAIFADDR:
1009155271Srwatson    case SIOCSIFADDR:
1010155192Srwatson	if (ifa->ifa_addr->sa_family != AF_INET)
1011155192Srwatson	    return EAFNOSUPPORT;
1012155192Srwatson	ifp->if_flags |= IFF_UP;
1013156889Srwatson	/* FALLTHROUGH */
1014155192Srwatson    case SIOCSIFFLAGS:
1015155192Srwatson	if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
1016155192Srwatson	    outb(sc->sc_port + lpt_control, 0x00);
1017155192Srwatson	    ifp->if_flags &= ~IFF_RUNNING;
1018155192Srwatson	    break;
1019155192Srwatson	}
1020162990Srwatson#ifdef PC98
1021155192Srwatson	/* XXX */
1022155192Srwatson	return ENOBUFS;
1023155192Srwatson#else
1024155192Srwatson	if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
1025155192Srwatson	    if (lpinittables())
1026155192Srwatson		return ENOBUFS;
1027155192Srwatson	    sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
1028155192Srwatson				  M_DEVBUF, M_WAITOK);
1029155192Srwatson	    if (!sc->sc_ifbuf)
1030155192Srwatson		return ENOBUFS;
1031155192Srwatson
1032155192Srwatson	    outb(sc->sc_port + lpt_control, LPC_ENA);
1033155192Srwatson	    ifp->if_flags |= IFF_RUNNING;
1034155192Srwatson	}
1035155192Srwatson	break;
1036155192Srwatson#endif
1037155192Srwatson    case SIOCSIFMTU:
1038155192Srwatson	ptr = sc->sc_ifbuf;
1039155192Srwatson	sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
1040155192Srwatson	if (!sc->sc_ifbuf) {
1041155192Srwatson	    sc->sc_ifbuf = ptr;
1042155192Srwatson	    return ENOBUFS;
1043155192Srwatson	}
1044155192Srwatson	if (ptr)
1045155192Srwatson	    free(ptr,M_DEVBUF);
1046155192Srwatson	sc->sc_if.if_mtu = ifr->ifr_mtu;
1047155271Srwatson	break;
1048155192Srwatson
1049155192Srwatson    case SIOCGIFMTU:
1050155192Srwatson	ifr->ifr_mtu = sc->sc_if.if_mtu;
1051155192Srwatson	break;
1052155192Srwatson
1053155192Srwatson    case SIOCADDMULTI:
1054155192Srwatson    case SIOCDELMULTI:
1055155192Srwatson	if (ifr == 0) {
1056155192Srwatson	    return EAFNOSUPPORT;		/* XXX */
1057155192Srwatson	}
1058155192Srwatson	switch (ifr->ifr_addr.sa_family) {
1059155192Srwatson
1060155192Srwatson#ifdef INET
1061155192Srwatson	case AF_INET:
1062155192Srwatson	    break;
1063155192Srwatson#endif
1064155192Srwatson
1065155192Srwatson	default:
1066155192Srwatson	    return EAFNOSUPPORT;
1067155192Srwatson	}
1068155192Srwatson	break;
1069155192Srwatson
1070155192Srwatson    default:
1071155192Srwatson	lprintf(("LP:ioctl(0x%lx)\n", cmd));
1072155192Srwatson	return EINVAL;
1073155192Srwatson    }
1074155192Srwatson    return 0;
1075155192Srwatson}
1076155192Srwatson
1077155192Srwatsonstatic __inline int
1078155192Srwatsonclpoutbyte (u_char byte, int spin, int data_port, int status_port)
1079156889Srwatson{
1080155192Srwatson	outb(data_port, ctxmitl[byte]);
1081155192Srwatson	while (inb(status_port) & CLPIP_SHAKE)
1082155192Srwatson		if (--spin == 0) {
1083155192Srwatson			return 1;
1084155192Srwatson		}
1085155192Srwatson	outb(data_port, ctxmith[byte]);
1086155192Srwatson	while (!(inb(status_port) & CLPIP_SHAKE))
1087155192Srwatson		if (--spin == 0) {
1088155192Srwatson			return 1;
1089155192Srwatson		}
1090155192Srwatson	return 0;
1091156889Srwatson}
1092155192Srwatson
1093155192Srwatsonstatic __inline int
1094155192Srwatsonclpinbyte (int spin, int data_port, int status_port)
1095155192Srwatson{
1096155192Srwatson	int c, cl;
1097155192Srwatson
1098155192Srwatson	while((inb(status_port) & CLPIP_SHAKE))
1099155192Srwatson	    if(!--spin) {
1100155192Srwatson		return -1;
1101156889Srwatson	    }
1102155192Srwatson	cl = inb(status_port);
1103155192Srwatson	outb(data_port, 0x10);
1104155192Srwatson
1105155192Srwatson	while(!(inb(status_port) & CLPIP_SHAKE))
1106155192Srwatson	    if(!--spin) {
1107155192Srwatson		return -1;
1108156889Srwatson	    }
1109155192Srwatson	c = inb(status_port);
1110155192Srwatson	outb(data_port, 0x00);
1111155192Srwatson
1112155192Srwatson	return (ctrecvl[cl] | ctrecvh[c]);
1113155192Srwatson}
1114155192Srwatson
1115156889Srwatsonstatic void
1116155192Srwatsonlpintr (int unit)
1117155192Srwatson{
1118155192Srwatson	struct   lpt_softc *sc = lpt_sc + unit;
1119155192Srwatson	register int lpt_data_port = sc->sc_port + lpt_data;
1120155192Srwatson	register int lpt_stat_port = sc->sc_port + lpt_status;
1121155192Srwatson		 int lpt_ctrl_port = sc->sc_port + lpt_control;
1122155192Srwatson	int len, s, j;
1123155192Srwatson	u_char *bp;
1124155192Srwatson	u_char c, cl;
1125155192Srwatson	struct mbuf *top;
1126156889Srwatson
1127155192Srwatson	s = splhigh();
1128155192Srwatson
1129155192Srwatson	if (sc->sc_if.if_flags & IFF_LINK0) {
1130155192Srwatson
1131155192Srwatson	    /* Ack. the request */
1132155192Srwatson	    outb(lpt_data_port, 0x01);
1133155192Srwatson
1134155192Srwatson	    /* Get the packet length */
1135155192Srwatson	    j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
1136155192Srwatson	    if (j == -1)
1137156889Srwatson		goto err;
1138155192Srwatson	    len = j;
1139155192Srwatson	    j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
1140155192Srwatson	    if (j == -1)
1141155192Srwatson		goto err;
1142155192Srwatson	    len = len + (j << 8);
1143155192Srwatson	    if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
1144155192Srwatson		goto err;
1145155192Srwatson
1146155192Srwatson	    bp  = sc->sc_ifbuf;
1147155192Srwatson
1148155192Srwatson	    while (len--) {
1149155192Srwatson	        j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
1150155192Srwatson	        if (j == -1) {
1151155192Srwatson		    goto err;
1152156889Srwatson	        }
1153155192Srwatson	        *bp++ = j;
1154155192Srwatson	    }
1155155192Srwatson	    /* Get and ignore checksum */
1156155192Srwatson	    j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
1157155192Srwatson	    if (j == -1) {
1158155192Srwatson	        goto err;
1159155192Srwatson	    }
1160155192Srwatson
1161155192Srwatson	    len = bp - sc->sc_ifbuf;
1162155192Srwatson	    if (len <= CLPIPHDRLEN)
1163155192Srwatson	        goto err;
1164155192Srwatson
1165155192Srwatson	    sc->sc_iferrs = 0;
1166155192Srwatson
1167156889Srwatson	    if (IF_QFULL(&ipintrq)) {
1168155192Srwatson	        lprintf(("DROP"));
1169155192Srwatson	        IF_DROP(&ipintrq);
1170155192Srwatson		goto done;
1171155192Srwatson	    }
1172155192Srwatson	    len -= CLPIPHDRLEN;
1173155192Srwatson	    sc->sc_if.if_ipackets++;
1174156889Srwatson	    sc->sc_if.if_ibytes += len;
1175155192Srwatson	    top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
1176155192Srwatson	    if (top) {
1177155192Srwatson	        IF_ENQUEUE(&ipintrq, top);
1178155192Srwatson	        schednetisr(NETISR_IP);
1179155192Srwatson	    }
1180155192Srwatson	    goto done;
1181156889Srwatson	}
1182155192Srwatson	while ((inb(lpt_stat_port) & LPIP_SHAKE)) {
1183155192Srwatson	    len = sc->sc_if.if_mtu + LPIPHDRLEN;
1184155192Srwatson	    bp  = sc->sc_ifbuf;
1185155192Srwatson	    while (len--) {
1186155192Srwatson
1187155192Srwatson		cl = inb(lpt_stat_port);
1188155192Srwatson		outb(lpt_data_port, 8);
1189155192Srwatson
1190155192Srwatson		j = LPMAXSPIN2;
1191155192Srwatson		while((inb(lpt_stat_port) & LPIP_SHAKE))
1192155192Srwatson		    if(!--j) goto err;
1193155192Srwatson
1194155192Srwatson		c = inb(lpt_stat_port);
1195155192Srwatson		outb(lpt_data_port, 0);
1196155192Srwatson
1197155192Srwatson		*bp++= trecvh[cl] | trecvl[c];
1198155192Srwatson
1199155192Srwatson		j = LPMAXSPIN2;
1200155192Srwatson		while (!((cl=inb(lpt_stat_port)) & LPIP_SHAKE)) {
1201155192Srwatson		    if (cl != c &&
1202155192Srwatson			(((cl = inb(lpt_stat_port)) ^ 0xb8) & 0xf8) ==
1203155192Srwatson			  (c & 0xf8))
1204155192Srwatson			goto end;
1205155192Srwatson		    if (!--j) goto err;
1206155192Srwatson		}
1207155192Srwatson	    }
1208155192Srwatson
1209155192Srwatson	end:
1210155192Srwatson	    len = bp - sc->sc_ifbuf;
1211155192Srwatson	    if (len <= LPIPHDRLEN)
1212155192Srwatson		goto err;
1213155192Srwatson
1214155192Srwatson	    sc->sc_iferrs = 0;
1215155192Srwatson
1216155192Srwatson	    if (IF_QFULL(&ipintrq)) {
1217155192Srwatson		lprintf(("DROP"));
1218155192Srwatson		IF_DROP(&ipintrq);
1219155192Srwatson		goto done;
1220155192Srwatson	    }
1221155192Srwatson#if NBPF > 0
1222155192Srwatson	    if (sc->sc_if.if_bpf) {
1223155192Srwatson		bpf_tap(&sc->sc_if, sc->sc_ifbuf, len);
1224155192Srwatson	    }
1225155192Srwatson#endif
1226155192Srwatson	    len -= LPIPHDRLEN;
1227155192Srwatson	    sc->sc_if.if_ipackets++;
1228155192Srwatson	    sc->sc_if.if_ibytes += len;
1229155192Srwatson	    top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
1230155192Srwatson	    if (top) {
1231155192Srwatson		    IF_ENQUEUE(&ipintrq, top);
1232155271Srwatson		    schednetisr(NETISR_IP);
1233155192Srwatson	    }
1234155192Srwatson	}
1235155192Srwatson	goto done;
1236155192Srwatson
1237155192Srwatson    err:
1238155192Srwatson	outb(lpt_data_port, 0);
1239155192Srwatson	lprintf(("R"));
1240155192Srwatson	sc->sc_if.if_ierrors++;
1241155192Srwatson	sc->sc_iferrs++;
1242155192Srwatson
1243155192Srwatson	/*
1244155192Srwatson	 * We are not able to send receive anything for now,
1245155192Srwatson	 * so stop wasting our time
1246155192Srwatson	 */
1247155192Srwatson	if (sc->sc_iferrs > LPMAXERRS) {
1248155192Srwatson	    printf("lp%d: Too many errors, Going off-line.\n", unit);
1249155192Srwatson	    outb(lpt_ctrl_port, 0x00);
1250155192Srwatson	    sc->sc_if.if_flags &= ~IFF_RUNNING;
1251155192Srwatson	    sc->sc_iferrs=0;
1252155192Srwatson	}
1253155192Srwatson
1254155192Srwatson    done:
1255155192Srwatson	splx(s);
1256155192Srwatson	return;
1257155192Srwatson}
1258155192Srwatson
1259155192Srwatsonstatic __inline int
1260155192Srwatsonlpoutbyte (u_char byte, int spin, int data_port, int status_port)
1261155192Srwatson{
1262155192Srwatson    outb(data_port, txmith[byte]);
1263155192Srwatson    while (!(inb(status_port) & LPIP_SHAKE))
1264155192Srwatson	if (--spin == 0)
1265155192Srwatson		return 1;
1266155192Srwatson    outb(data_port, txmitl[byte]);
1267155192Srwatson    while (inb(status_port) & LPIP_SHAKE)
1268155192Srwatson	if (--spin == 0)
1269155192Srwatson		return 1;
1270155192Srwatson    return 0;
1271155271Srwatson}
1272155192Srwatson
1273155192Srwatsonstatic int
1274155192Srwatsonlpoutput (struct ifnet *ifp, struct mbuf *m,
1275155192Srwatson	  struct sockaddr *dst, struct rtentry *rt)
1276155192Srwatson{
1277155192Srwatson    register int lpt_data_port = lpt_sc[ifp->if_unit].sc_port + lpt_data;
1278155192Srwatson    register int lpt_stat_port = lpt_sc[ifp->if_unit].sc_port + lpt_status;
1279155192Srwatson#ifndef PC98
1280155192Srwatson	     int lpt_ctrl_port = lpt_sc[ifp->if_unit].sc_port + lpt_control;
1281155192Srwatson#endif
1282155192Srwatson
1283155192Srwatson    int s, err;
1284155192Srwatson    struct mbuf *mm;
1285155192Srwatson    u_char *cp = "\0\0";
1286155192Srwatson    u_char chksum = 0;
1287155192Srwatson    int count = 0;
1288155192Srwatson    int i;
1289155192Srwatson    int spin;
1290156889Srwatson
1291155192Srwatson    /* We need a sensible value if we abort */
1292155192Srwatson    cp++;
1293155192Srwatson    ifp->if_flags |= IFF_RUNNING;
1294155192Srwatson
1295155192Srwatson    err = 1;			/* assume we're aborting because of an error */
1296155192Srwatson
1297155192Srwatson    s = splhigh();
1298155192Srwatson
1299155192Srwatson#ifndef PC98
1300155192Srwatson    /* Suspend (on laptops) or receive-errors might have taken us offline */
1301155192Srwatson    outb(lpt_ctrl_port, LPC_ENA);
1302155192Srwatson#endif
1303155192Srwatson
1304155192Srwatson    if (ifp->if_flags & IFF_LINK0) {
1305155192Srwatson
1306155192Srwatson	if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) {
1307155192Srwatson	    lprintf(("&"));
1308155192Srwatson	    lptintr(ifp->if_unit);
1309155192Srwatson	}
1310155192Srwatson
1311155192Srwatson	/* Alert other end to pending packet */
1312155192Srwatson	spin = LPMAXSPIN1;
1313155192Srwatson	outb(lpt_data_port, 0x08);
1314155192Srwatson	while ((inb(lpt_stat_port) & 0x08) == 0)
1315155192Srwatson		if (--spin == 0) {
1316155192Srwatson			goto nend;
1317155192Srwatson		}
1318155192Srwatson
1319155192Srwatson	/* Calculate length of packet, then send that */
1320155192Srwatson
1321155192Srwatson	count += 14;		/* Ethernet header len */
1322155192Srwatson
1323155192Srwatson	mm = m;
1324155192Srwatson	for (mm = m; mm; mm = mm->m_next) {
1325155192Srwatson		count += mm->m_len;
1326155192Srwatson	}
1327155192Srwatson	if (clpoutbyte(count & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
1328155192Srwatson		goto nend;
1329155192Srwatson	if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
1330155192Srwatson		goto nend;
1331155192Srwatson
1332155192Srwatson	/* Send dummy ethernet header */
1333155192Srwatson	for (i = 0; i < 12; i++) {
1334155192Srwatson		if (clpoutbyte(i, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
1335156889Srwatson			goto nend;
1336155192Srwatson		chksum += i;
1337155192Srwatson	}
1338155192Srwatson
1339155192Srwatson	if (clpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
1340155192Srwatson		goto nend;
1341155192Srwatson	if (clpoutbyte(0x00, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
1342155192Srwatson		goto nend;
1343155192Srwatson	chksum += 0x08 + 0x00;		/* Add into checksum */
1344155192Srwatson
1345155192Srwatson	mm = m;
1346155192Srwatson	do {
1347155192Srwatson		cp = mtod(mm, u_char *);
1348155192Srwatson		while (mm->m_len--) {
1349155192Srwatson			chksum += *cp;
1350155192Srwatson			if (clpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
1351155192Srwatson				goto nend;
1352155192Srwatson		}
1353155192Srwatson	} while ((mm = mm->m_next));
1354155192Srwatson
1355155192Srwatson	/* Send checksum */
1356155192Srwatson	if (clpoutbyte(chksum, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
1357155192Srwatson		goto nend;
1358155192Srwatson
1359155192Srwatson	/* Go quiescent */
1360155192Srwatson	outb(lpt_data_port, 0);
1361155192Srwatson
1362155192Srwatson	err = 0;			/* No errors */
1363155192Srwatson
1364155192Srwatson	nend:
1365155192Srwatson	if (err)  {				/* if we didn't timeout... */
1366155192Srwatson		ifp->if_oerrors++;
1367155192Srwatson		lprintf(("X"));
1368155192Srwatson	} else {
1369155192Srwatson		ifp->if_opackets++;
1370155192Srwatson		ifp->if_obytes += m->m_pkthdr.len;
1371155192Srwatson	}
1372155192Srwatson
1373155192Srwatson	m_freem(m);
1374156889Srwatson
1375156889Srwatson	if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) {
1376156889Srwatson		lprintf(("^"));
1377155192Srwatson		lptintr(ifp->if_unit);
1378155192Srwatson	}
1379155192Srwatson	(void) splx(s);
1380155192Srwatson	return 0;
1381155192Srwatson    }
1382155192Srwatson
1383155192Srwatson    if (inb(lpt_stat_port) & LPIP_SHAKE) {
1384155192Srwatson        lprintf(("&"));
1385155192Srwatson        lptintr(ifp->if_unit);
1386155192Srwatson    }
1387155192Srwatson
1388155192Srwatson    if (lpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
1389155192Srwatson        goto end;
1390155192Srwatson    if (lpoutbyte(0x00, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
1391155192Srwatson        goto end;
1392155192Srwatson
1393155192Srwatson    mm = m;
1394155192Srwatson    do {
1395155192Srwatson        cp = mtod(mm,u_char *);
1396155192Srwatson        while (mm->m_len--)
1397155192Srwatson	    if (lpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
1398155192Srwatson	        goto end;
1399155192Srwatson    } while ((mm = mm->m_next));
1400155192Srwatson
1401155192Srwatson    err = 0;				/* no errors were encountered */
1402155192Srwatson
1403155192Srwatson    end:
1404155192Srwatson    --cp;
1405162990Srwatson    outb(lpt_data_port, txmitl[*cp] ^ 0x17);
1406156889Srwatson
1407155192Srwatson    if (err)  {				/* if we didn't timeout... */
1408156889Srwatson	ifp->if_oerrors++;
1409155192Srwatson        lprintf(("X"));
1410155192Srwatson    } else {
1411155192Srwatson	ifp->if_opackets++;
1412155192Srwatson	ifp->if_obytes += m->m_pkthdr.len;
1413155192Srwatson#if NBPF > 0
1414155192Srwatson	if (ifp->if_bpf) {
1415156889Srwatson	    /*
1416155192Srwatson	     * We need to prepend the packet type as
1417155192Srwatson	     * a two byte field.  Cons up a dummy header
1418155192Srwatson	     * to pacify bpf.  This is safe because bpf
1419155192Srwatson	     * will only read from the mbuf (i.e., it won't
1420155192Srwatson	     * try to free it or keep a pointer to it).
1421155192Srwatson	     */
1422155192Srwatson	    struct mbuf m0;
1423155192Srwatson	    u_short hdr = 0x800;
1424155192Srwatson
1425155192Srwatson	    m0.m_next = m;
1426156889Srwatson	    m0.m_len = 2;
1427156889Srwatson	    m0.m_data = (char *)&hdr;
1428156889Srwatson
1429155192Srwatson	    bpf_mtap(ifp, &m0);
1430155192Srwatson	}
1431155192Srwatson#endif
1432155192Srwatson    }
1433155192Srwatson
1434156889Srwatson    m_freem(m);
1435156889Srwatson
1436155192Srwatson    if (inb(lpt_stat_port) & LPIP_SHAKE) {
1437155192Srwatson	lprintf(("^"));
1438156889Srwatson	lptintr(ifp->if_unit);
1439156889Srwatson    }
1440155192Srwatson
1441155192Srwatson    (void) splx(s);
1442156889Srwatson    return 0;
1443156889Srwatson}
1444155192Srwatson
1445155192Srwatson#endif /* INET */
1446155192Srwatson
1447static int lpt_devsw_installed;
1448
1449static void 	lpt_drvinit(void *unused)
1450{
1451
1452	if( ! lpt_devsw_installed ) {
1453		cdevsw_add(&lpt_cdevsw);
1454		lpt_devsw_installed = 1;
1455    	}
1456}
1457
1458SYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL)
1459
1460