olpt.c revision 48006
148006Skato/*
248006Skato * Copyright (c) 1990 William F. Jolitz, TeleMuse
348006Skato * All rights reserved.
448006Skato *
548006Skato * Redistribution and use in source and binary forms, with or without
648006Skato * modification, are permitted provided that the following conditions
748006Skato * are met:
848006Skato * 1. Redistributions of source code must retain the above copyright
948006Skato *    notice, this list of conditions and the following disclaimer.
1048006Skato * 2. Redistributions in binary form must reproduce the above copyright
1148006Skato *    notice, this list of conditions and the following disclaimer in the
1248006Skato *    documentation and/or other materials provided with the distribution.
1348006Skato * 3. All advertising materials mentioning features or use of this software
1448006Skato *    must display the following acknowledgement:
1548006Skato *	This software is a component of "386BSD" developed by
1648006Skato *	William F. Jolitz, TeleMuse.
1748006Skato * 4. Neither the name of the developer nor the name "386BSD"
1848006Skato *    may be used to endorse or promote products derived from this software
1948006Skato *    without specific prior written permission.
2048006Skato *
2148006Skato * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
2248006Skato * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
2348006Skato * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
2448006Skato * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
2548006Skato * NOT MAKE USE OF THIS WORK.
2648006Skato *
2748006Skato * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
2848006Skato * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
2948006Skato * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
3048006Skato * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
3148006Skato * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
3248006Skato * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
3348006Skato * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
3448006Skato * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
3548006Skato *
3648006Skato * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
3748006Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3848006Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3948006Skato * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
4048006Skato * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4148006Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4248006Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4348006Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4448006Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4548006Skato * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4648006Skato * SUCH DAMAGE.
4748006Skato *
4848006Skato *	from: unknown origin, 386BSD 0.1
4948006Skato *	$Id$
5048006Skato */
5148006Skato
5248006Skato/*
5348006Skato * Device Driver for AT parallel printer port
5448006Skato * Written by William Jolitz 12/18/90
5548006Skato */
5648006Skato
5748006Skato/*
5848006Skato * Parallel port TCP/IP interfaces added.  I looked at the driver from
5948006Skato * MACH but this is a complete rewrite, and btw. incompatible, and it
6048006Skato * should perform better too.  I have never run the MACH driver though.
6148006Skato *
6248006Skato * This driver sends two bytes (0x08, 0x00) in front of each packet,
6348006Skato * to allow us to distinguish another format later.
6448006Skato *
6548006Skato * Now added an Linux/Crynwr compatibility mode which is enabled using
6648006Skato * IF_LINK0 - Tim Wilkinson.
6748006Skato *
6848006Skato * TODO:
6948006Skato *    Make HDLC/PPP mode, use IF_LLC1 to enable.
7048006Skato *
7148006Skato * Connect the two computers using a Laplink parallel cable to use this
7248006Skato * feature:
7348006Skato *
7448006Skato *      +----------------------------------------+
7548006Skato * 	|A-name	A-End	B-End	Descr.	Port/Bit |
7648006Skato *      +----------------------------------------+
7748006Skato *	|DATA0	2	15	Data	0/0x01   |
7848006Skato *	|-ERROR	15	2	   	1/0x08   |
7948006Skato *      +----------------------------------------+
8048006Skato *	|DATA1	3	13	Data	0/0x02	 |
8148006Skato *	|+SLCT	13	3	   	1/0x10   |
8248006Skato *      +----------------------------------------+
8348006Skato *	|DATA2	4	12	Data	0/0x04   |
8448006Skato *	|+PE	12	4	   	1/0x20   |
8548006Skato *      +----------------------------------------+
8648006Skato *	|DATA3	5	10	Strobe	0/0x08   |
8748006Skato *	|-ACK	10	5	   	1/0x40   |
8848006Skato *      +----------------------------------------+
8948006Skato *	|DATA4	6	11	Data	0/0x10   |
9048006Skato *	|BUSY	11	6	   	1/~0x80  |
9148006Skato *      +----------------------------------------+
9248006Skato *	|GND	18-25	18-25	GND	-        |
9348006Skato *      +----------------------------------------+
9448006Skato *
9548006Skato * Expect transfer-rates up to 75 kbyte/sec.
9648006Skato *
9748006Skato * If GCC could correctly grok
9848006Skato *	register int port asm("edx")
9948006Skato * the code would be cleaner
10048006Skato *
10148006Skato * Poul-Henning Kamp <phk@freebsd.org>
10248006Skato */
10348006Skato
10448006Skato#include "olpt.h"
10548006Skato#include "opt_devfs.h"
10648006Skato#include "opt_inet.h"
10748006Skato#ifdef PC98
10848006Skato#undef INET	/* PLIP is not supported for old PC-98 */
10948006Skato#endif
11048006Skato
11148006Skato#include <sys/param.h>
11248006Skato#include <sys/systm.h>
11348006Skato#include <sys/conf.h>
11448006Skato#include <sys/buf.h>
11548006Skato#include <sys/kernel.h>
11648006Skato#include <sys/uio.h>
11748006Skato#include <sys/syslog.h>
11848006Skato#ifdef DEVFS
11948006Skato#include <sys/devfsext.h>
12048006Skato#endif /*DEVFS*/
12148006Skato
12248006Skato#include <machine/clock.h>
12348006Skato#include <machine/lpt.h>
12448006Skato
12548006Skato#include <vm/vm.h>
12648006Skato#include <vm/vm_param.h>
12748006Skato#include <vm/pmap.h>
12848006Skato
12948006Skato#ifdef PC98
13048006Skato#include <pc98/pc98/pc98.h>
13148006Skato#else
13248006Skato#include <i386/isa/isa.h>
13348006Skato#endif
13448006Skato#include <i386/isa/isa_device.h>
13548006Skato#include <i386/isa/lptreg.h>
13648006Skato
13748006Skato#ifdef INET
13848006Skato#include <sys/malloc.h>
13948006Skato#include <sys/mbuf.h>
14048006Skato#include <sys/socket.h>
14148006Skato#include <sys/sockio.h>
14248006Skato
14348006Skato#include <net/if.h>
14448006Skato#include <net/if_types.h>
14548006Skato#include <net/netisr.h>
14648006Skato#include <netinet/in.h>
14748006Skato#include <netinet/in_var.h>
14848006Skato#include "bpfilter.h"
14948006Skato#if NBPFILTER > 0
15048006Skato#include <net/bpf.h>
15148006Skato#endif
15248006Skato#endif /* INET */
15348006Skato
15448006Skato
15548006Skato#define	LPINITRDY	4	/* wait up to 4 seconds for a ready */
15648006Skato#define	LPTOUTINITIAL	10	/* initial timeout to wait for ready 1/10 s */
15748006Skato#define	LPTOUTMAX	1	/* maximal timeout 1 s */
15848006Skato#define	LPPRI		(PZERO+8)
15948006Skato#define	BUFSIZE		1024
16048006Skato
16148006Skato#ifdef INET
16248006Skato#ifndef LPMTU			/* MTU for the lp# interfaces */
16348006Skato#define	LPMTU	1500
16448006Skato#endif
16548006Skato
16648006Skato#ifndef LPMAXSPIN1		/* DELAY factor for the lp# interfaces */
16748006Skato#define	LPMAXSPIN1	8000   /* Spinning for remote intr to happen */
16848006Skato#endif
16948006Skato
17048006Skato#ifndef LPMAXSPIN2		/* DELAY factor for the lp# interfaces */
17148006Skato#define	LPMAXSPIN2	500	/* Spinning for remote handshake to happen */
17248006Skato#endif
17348006Skato
17448006Skato#ifndef LPMAXERRS		/* Max errors before !RUNNING */
17548006Skato#define	LPMAXERRS	100
17648006Skato#endif
17748006Skato
17848006Skato#define CLPIPHDRLEN	14	/* We send dummy ethernet addresses (two) + packet type in front of packet */
17948006Skato#define	CLPIP_SHAKE	0x80	/* This bit toggles between nibble reception */
18048006Skato#define MLPIPHDRLEN	CLPIPHDRLEN
18148006Skato
18248006Skato#define LPIPHDRLEN	2	/* We send 0x08, 0x00 in front of packet */
18348006Skato#define	LPIP_SHAKE	0x40	/* This bit toggles between nibble reception */
18448006Skato#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
18548006Skato#define MLPIPHDRLEN	LPIPHDRLEN
18648006Skato#endif
18748006Skato
18848006Skato#define	LPIPTBLSIZE	256	/* Size of octet translation table */
18948006Skato
19048006Skato#endif /* INET */
19148006Skato
19248006Skato#ifndef PC98
19348006Skato/* BIOS printer list - used by BIOS probe*/
19448006Skato#define	BIOS_LPT_PORTS	0x408
19548006Skato#define	BIOS_PORTS	(short *)(KERNBASE+BIOS_LPT_PORTS)
19648006Skato#define	BIOS_MAX_LPT	4
19748006Skato#endif
19848006Skato
19948006Skato
20048006Skato#ifndef DEBUG
20148006Skato#define lprintf(args)
20248006Skato#else
20348006Skato#define lprintf(args)	do {				\
20448006Skato				if (lptflag)		\
20548006Skato					printf args;	\
20648006Skato			} while (0)
20748006Skatostatic int volatile lptflag = 1;
20848006Skato#endif
20948006Skato
21048006Skato#define	LPTUNIT(s)	((s)&0x03)
21148006Skato#define	LPTFLAGS(s)	((s)&0xfc)
21248006Skato
21348006Skatostatic struct lpt_softc {
21448006Skato	int	sc_port;
21548006Skato	short	sc_state;
21648006Skato	/* default case: negative prime, negative ack, handshake strobe,
21748006Skato	   prime once */
21848006Skato	u_char	sc_control;
21948006Skato	char	sc_flags;
22048006Skato#define LP_POS_INIT	0x04	/* if we are a postive init signal */
22148006Skato#define LP_POS_ACK	0x08	/* if we are a positive going ack */
22248006Skato#define LP_NO_PRIME	0x10	/* don't prime the printer at all */
22348006Skato#define LP_PRIMEOPEN	0x20	/* prime on every open */
22448006Skato#define LP_AUTOLF	0x40	/* tell printer to do an automatic lf */
22548006Skato#define LP_BYPASS	0x80	/* bypass  printer ready checks */
22648006Skato	struct	buf *sc_inbuf;
22748006Skato	short	sc_xfercnt ;
22848006Skato	char	sc_primed;
22948006Skato	char	*sc_cp ;
23048006Skato	u_char	sc_irq ;	/* IRQ status of port */
23148006Skato#define LP_HAS_IRQ	0x01	/* we have an irq available */
23248006Skato#define LP_USE_IRQ	0x02	/* we are using our irq */
23348006Skato#define LP_ENABLE_IRQ	0x04	/* enable IRQ on open */
23448006Skato	u_char	sc_backoff ;	/* time to call lptout() again */
23548006Skato
23648006Skato#ifdef INET
23748006Skato	struct  ifnet	sc_if;
23848006Skato	u_char		*sc_ifbuf;
23948006Skato	int		sc_iferrs;
24048006Skato#endif
24148006Skato#ifdef DEVFS
24248006Skato	void	*devfs_token;
24348006Skato	void	*devfs_token_ctl;
24448006Skato#endif
24548006Skato} lpt_sc[NOLPT] ;
24648006Skato
24748006Skato/* bits for state */
24848006Skato#define	OPEN		(1<<0)	/* device is open */
24948006Skato#define	ASLP		(1<<1)	/* awaiting draining of printer */
25048006Skato#define	ERROR		(1<<2)	/* error was received from printer */
25148006Skato#define	OBUSY		(1<<3)	/* printer is busy doing output */
25248006Skato#define LPTOUT		(1<<4)	/* timeout while not selected */
25348006Skato#define TOUT		(1<<5)	/* timeout while not selected */
25448006Skato#define INIT		(1<<6)	/* waiting to initialize for open */
25548006Skato#define INTERRUPTED	(1<<7)	/* write call was interrupted */
25648006Skato
25748006Skato
25848006Skato/* status masks to interrogate printer status */
25948006Skato#define RDY_MASK	(LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)	/* ready ? */
26048006Skato#define LP_READY	(LPS_SEL|LPS_NBSY|LPS_NERR)
26148006Skato
26248006Skato/* Printer Ready condition  - from lpa.c */
26348006Skato/* Only used in polling code */
26448006Skato#ifdef PC98
26548006Skato#define	NOT_READY(x)	((inb(x) & LPS_NBSY) != LPS_NBSY)
26648006Skato#else	/* IBM-PC */
26748006Skato#define	LPS_INVERT	(LPS_NBSY | LPS_NACK |           LPS_SEL | LPS_NERR)
26848006Skato#define	LPS_MASK	(LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
26948006Skato#define	NOT_READY(x)	((inb(x)^LPS_INVERT)&LPS_MASK)
27048006Skato#endif
27148006Skato
27248006Skato#define	MAX_SLEEP	(hz*5)	/* Timeout while waiting for device ready */
27348006Skato#define	MAX_SPIN	20	/* Max delay for device ready in usecs */
27448006Skato
27548006Skatostatic timeout_t lptout;
27648006Skatostatic int	lptprobe (struct isa_device *dvp);
27748006Skatostatic int	lptattach (struct isa_device *isdp);
27848006Skatostatic ointhand2_t	lptintr;
27948006Skato
28048006Skato#ifdef INET
28148006Skato
28248006Skato/* Tables for the lp# interface */
28348006Skatostatic u_char *txmith;
28448006Skato#define txmitl (txmith+(1*LPIPTBLSIZE))
28548006Skato#define trecvh (txmith+(2*LPIPTBLSIZE))
28648006Skato#define trecvl (txmith+(3*LPIPTBLSIZE))
28748006Skato
28848006Skatostatic u_char *ctxmith;
28948006Skato#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
29048006Skato#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
29148006Skato#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
29248006Skato
29348006Skato/* Functions for the lp# interface */
29448006Skatostatic void lpattach(struct lpt_softc *,int);
29548006Skato#ifndef PC98
29648006Skatostatic int lpinittables(void);
29748006Skato#endif
29848006Skatostatic int lpioctl(struct ifnet *, u_long, caddr_t);
29948006Skatostatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
30048006Skato	struct rtentry *);
30148006Skatostatic void lpintr(int);
30248006Skato#endif /* INET */
30348006Skato
30448006Skatostruct	isa_driver olptdriver = {
30548006Skato	lptprobe, lptattach, "olpt"
30648006Skato};
30748006Skato
30848006Skatostatic	d_open_t	lptopen;
30948006Skatostatic	d_close_t	lptclose;
31048006Skatostatic	d_write_t	lptwrite;
31148006Skatostatic	d_ioctl_t	lptioctl;
31248006Skato
31348006Skato#define CDEV_MAJOR 16
31448006Skatostatic struct cdevsw lpt_cdevsw = {
31548006Skato	/* open */	lptopen,
31648006Skato	/* close */	lptclose,
31748006Skato	/* read */	noread,
31848006Skato	/* write */	lptwrite,
31948006Skato	/* ioctl */	lptioctl,
32048006Skato	/* stop */	nostop,
32148006Skato	/* reset */	noreset,
32248006Skato	/* devtotty */	nodevtotty,
32348006Skato	/* poll */	nopoll,
32448006Skato	/* mmap */	nommap,
32548006Skato	/* strategy */	nostrategy,
32648006Skato	/* name */	"lpt",
32748006Skato	/* parms */	noparms,
32848006Skato	/* maj */	CDEV_MAJOR,
32948006Skato	/* dump */	nodump,
33048006Skato	/* psize */	nopsize,
33148006Skato	/* flags */	0,
33248006Skato	/* maxio */	0,
33348006Skato	/* bmaj */	-1
33448006Skato};
33548006Skato
33648006Skato#ifndef PC98
33748006Skato/*
33848006Skato * Internal routine to lptprobe to do port tests of one byte value
33948006Skato */
34048006Skatostatic int
34148006Skatolpt_port_test (int port, u_char data, u_char mask)
34248006Skato{
34348006Skato	int	temp, timeout;
34448006Skato
34548006Skato	data = data & mask;
34648006Skato	outb(port, data);
34748006Skato	timeout = 10000;
34848006Skato	do {
34948006Skato		DELAY(10);
35048006Skato		temp = inb(port) & mask;
35148006Skato	}
35248006Skato	while (temp != data && --timeout);
35348006Skato	lprintf(("Port 0x%x\tout=%x\tin=%x\ttout=%d\n",
35448006Skato		port, data, temp, timeout));
35548006Skato	return (temp == data);
35648006Skato}
35748006Skato#endif /* PC98 */
35848006Skato
35948006Skato/*
36048006Skato * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
36148006Skato * Based partially on Rod Grimes' printer probe
36248006Skato *
36348006Skato * Logic:
36448006Skato *	1) If no port address was given, use the bios detected ports
36548006Skato *	   and autodetect what ports the printers are on.
36648006Skato *	2) Otherwise, probe the data port at the address given,
36748006Skato *	   using the method in Rod Grimes' port probe.
36848006Skato *	   (Much code ripped off directly from Rod's probe.)
36948006Skato *
37048006Skato * Comments from Rod's probe:
37148006Skato * Logic:
37248006Skato *	1) You should be able to write to and read back the same value
37348006Skato *	   to the data port.  Do an alternating zeros, alternating ones,
37448006Skato *	   walking zero, and walking one test to check for stuck bits.
37548006Skato *
37648006Skato *	2) You should be able to write to and read back the same value
37748006Skato *	   to the control port lower 5 bits, the upper 3 bits are reserved
37848006Skato *	   per the IBM PC technical reference manauls and different boards
37948006Skato *	   do different things with them.  Do an alternating zeros, alternating
38048006Skato *	   ones, walking zero, and walking one test to check for stuck bits.
38148006Skato *
38248006Skato *	   Some printers drag the strobe line down when the are powered off
38348006Skato * 	   so this bit has been masked out of the control port test.
38448006Skato *
38548006Skato *	   XXX Some printers may not like a fast pulse on init or strobe, I
38648006Skato *	   don't know at this point, if that becomes a problem these bits
38748006Skato *	   should be turned off in the mask byte for the control port test.
38848006Skato *
38948006Skato *	   We are finally left with a mask of 0x14, due to some printers
39048006Skato *	   being adamant about holding other bits high ........
39148006Skato *
39248006Skato *	   Before probing the control port, we write a 0 to the data port -
39348006Skato *	   If not, some printers chuck out garbage when the strobe line
39448006Skato *	   gets toggled.
39548006Skato *
39648006Skato *	3) Set the data and control ports to a value of 0
39748006Skato *
39848006Skato *	This probe routine has been tested on Epson Lx-800, HP LJ3P,
39948006Skato *	Epson FX-1170 and C.Itoh 8510RM
40048006Skato *	printers.
40148006Skato *	Quick exit on fail added.
40248006Skato */
40348006Skato
40448006Skatoint
40548006Skatolptprobe(struct isa_device *dvp)
40648006Skato{
40748006Skato#ifdef PC98
40848006Skato#define PC98_OLD_LPT 0x40
40948006Skato#define PC98_IEEE_1284_FUNCTION 0x149
41048006Skato	unsigned int pc98_ieee_mode, tmp;
41148006Skato
41248006Skato	if (dvp->id_iobase == PC98_OLD_LPT) {
41348006Skato		tmp = inb(PC98_IEEE_1284_FUNCTION);
41448006Skato		pc98_ieee_mode = tmp;
41548006Skato		if ((tmp & 0x10) == 0x10) {
41648006Skato			outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10);
41748006Skato			tmp = inb(PC98_IEEE_1284_FUNCTION);
41848006Skato			if ((tmp & 0x10) != 0x10) {
41948006Skato				outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode);
42048006Skato				return 0;
42148006Skato			}
42248006Skato		}
42348006Skato	}
42448006Skato	return 8;
42548006Skato#else
42648006Skato	int		port;
42748006Skato	static short	next_bios_lpt = 0;
42848006Skato	int		status;
42948006Skato	static u_char	testbyte[18] = {
43048006Skato		0x55,			/* alternating zeros */
43148006Skato		0xaa,			/* alternating ones */
43248006Skato		0xfe, 0xfd, 0xfb, 0xf7,
43348006Skato		0xef, 0xdf, 0xbf, 0x7f,	/* walking zero */
43448006Skato		0x01, 0x02, 0x04, 0x08,
43548006Skato		0x10, 0x20, 0x40, 0x80	/* walking one */
43648006Skato	};
43748006Skato	int		i;
43848006Skato
43948006Skato	/*
44048006Skato	 * Make sure there is some way for lptopen to see that
44148006Skato	 * the port is not configured
44248006Skato	 * This 0 will remain if the port isn't attached
44348006Skato	 */
44448006Skato	(lpt_sc + dvp->id_unit)->sc_port = 0;
44548006Skato
44648006Skato	status = IO_LPTSIZE;
44748006Skato	/* If port not specified, use bios list */
44848006Skato	if(dvp->id_iobase < 0) {	/* port? */
44948006Skato		if((next_bios_lpt < BIOS_MAX_LPT) &&
45048006Skato				(*(BIOS_PORTS+next_bios_lpt) != 0) ) {
45148006Skato			dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++);
45248006Skato			goto end_probe;
45348006Skato		} else
45448006Skato			return (0);
45548006Skato	}
45648006Skato
45748006Skato	/* Port was explicitly specified */
45848006Skato	/* This allows probing of ports unknown to the BIOS */
45948006Skato	port = dvp->id_iobase + lpt_data;
46048006Skato	for (i = 0; i < 18; i++) {
46148006Skato		if (!lpt_port_test(port, testbyte[i], 0xff)) {
46248006Skato			status = 0;
46348006Skato			goto end_probe;
46448006Skato		}
46548006Skato	}
46648006Skato
46748006Skatoend_probe:
46848006Skato	/* write 0's to control and data ports */
46948006Skato	outb(dvp->id_iobase+lpt_data, 0);
47048006Skato	outb(dvp->id_iobase+lpt_control, 0);
47148006Skato
47248006Skato	return (status);
47348006Skato#endif
47448006Skato}
47548006Skato
47648006Skato/* XXX Todo - try and detect if interrupt is working */
47748006Skatoint
47848006Skatolptattach(struct isa_device *isdp)
47948006Skato{
48048006Skato	struct	lpt_softc	*sc;
48148006Skato	int	unit;
48248006Skato
48348006Skato	isdp->id_ointr = lptintr;
48448006Skato	unit = isdp->id_unit;
48548006Skato	sc = lpt_sc + unit;
48648006Skato	sc->sc_port = isdp->id_iobase;
48748006Skato	sc->sc_primed = 0;	/* not primed yet */
48848006Skato#ifdef PC98
48948006Skato	outb(sc->sc_port+lpt_pstb_ctrl,	LPC_DIS_PSTB);	/* PSTB disable */
49048006Skato	outb(sc->sc_port+lpt_control,	LPC_MODE8255);	/* 8255 mode set */
49148006Skato	outb(sc->sc_port+lpt_control,	LPC_NIRQ8);	/* IRQ8 inactive */
49248006Skato	outb(sc->sc_port+lpt_control,	LPC_NPSTB);	/* PSTB inactive */
49348006Skato	outb(sc->sc_port+lpt_pstb_ctrl,	LPC_EN_PSTB);	/* PSTB enable */
49448006Skato#else
49548006Skato	outb(sc->sc_port+lpt_control, LPC_NINIT);
49648006Skato#endif
49748006Skato
49848006Skato	/* check if we can use interrupt */
49948006Skato	lprintf(("oldirq %x\n", sc->sc_irq));
50048006Skato	if (isdp->id_irq) {
50148006Skato		sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
50248006Skato		printf("lpt%d: Interrupt-driven port\n", unit);
50348006Skato#ifdef INET
50448006Skato		lpattach(sc, unit);
50548006Skato#endif
50648006Skato	} else {
50748006Skato		sc->sc_irq = 0;
50848006Skato		lprintf(("lpt%d: Polled port\n", unit));
50948006Skato	}
51048006Skato	lprintf(("irq %x\n", sc->sc_irq));
51148006Skato
51248006Skato#ifdef DEVFS
51348006Skato	/* XXX what to do about the flags in the minor number? */
51448006Skato	sc->devfs_token = devfs_add_devswf(&lpt_cdevsw,
51548006Skato		unit, DV_CHR,
51648006Skato		UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit);
51748006Skato	sc->devfs_token_ctl = devfs_add_devswf(&lpt_cdevsw,
51848006Skato		unit | LP_BYPASS, DV_CHR,
51948006Skato		UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
52048006Skato#endif
52148006Skato	return (1);
52248006Skato}
52348006Skato
52448006Skato/*
52548006Skato * lptopen -- reset the printer, then wait until it's selected and not busy.
52648006Skato *	If LP_BYPASS flag is selected, then we do not try to select the
52748006Skato *	printer -- this is just used for passing ioctls.
52848006Skato */
52948006Skato
53048006Skatostatic	int
53148006Skatolptopen (dev_t dev, int flags, int fmt, struct proc *p)
53248006Skato{
53348006Skato	struct lpt_softc *sc;
53448006Skato	int s;
53548006Skato#ifdef PC98
53648006Skato	int port;
53748006Skato#else
53848006Skato	int trys, port;
53948006Skato#endif
54048006Skato	u_int unit = LPTUNIT(minor(dev));
54148006Skato
54248006Skato	sc = lpt_sc + unit;
54348006Skato	if ((unit >= NOLPT) || (sc->sc_port == 0))
54448006Skato		return (ENXIO);
54548006Skato
54648006Skato#ifdef INET
54748006Skato	if (sc->sc_if.if_flags & IFF_UP)
54848006Skato		return(EBUSY);
54948006Skato#endif
55048006Skato
55148006Skato	if (sc->sc_state) {
55248006Skato		lprintf(("lp: still open %x\n", sc->sc_state));
55348006Skato		return(EBUSY);
55448006Skato	} else
55548006Skato		sc->sc_state |= INIT;
55648006Skato
55748006Skato	sc->sc_flags = LPTFLAGS(minor(dev));
55848006Skato
55948006Skato	/* Check for open with BYPASS flag set. */
56048006Skato	if (sc->sc_flags & LP_BYPASS) {
56148006Skato		sc->sc_state = OPEN;
56248006Skato		return(0);
56348006Skato	}
56448006Skato
56548006Skato	s = spltty();
56648006Skato	lprintf(("lp flags 0x%x\n", sc->sc_flags));
56748006Skato	port = sc->sc_port;
56848006Skato
56948006Skato	/* set IRQ status according to ENABLE_IRQ flag */
57048006Skato	if (sc->sc_irq & LP_ENABLE_IRQ)
57148006Skato		sc->sc_irq |= LP_USE_IRQ;
57248006Skato	else
57348006Skato		sc->sc_irq &= ~LP_USE_IRQ;
57448006Skato
57548006Skato	/* init printer */
57648006Skato#ifndef PC98
57748006Skato	if ((sc->sc_flags & LP_NO_PRIME) == 0) {
57848006Skato		if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
57948006Skato			outb(port+lpt_control, 0);
58048006Skato			sc->sc_primed++;
58148006Skato			DELAY(500);
58248006Skato		}
58348006Skato	}
58448006Skato
58548006Skato	outb (port+lpt_control, LPC_SEL|LPC_NINIT);
58648006Skato
58748006Skato	/* wait till ready (printer running diagnostics) */
58848006Skato	trys = 0;
58948006Skato	do {
59048006Skato		/* ran out of waiting for the printer */
59148006Skato		if (trys++ >= LPINITRDY*4) {
59248006Skato			splx(s);
59348006Skato			sc->sc_state = 0;
59448006Skato			lprintf(("status %x\n", inb(port+lpt_status)));
59548006Skato			return (EBUSY);
59648006Skato		}
59748006Skato
59848006Skato		/* wait 1/4 second, give up if we get a signal */
59948006Skato		if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) !=
60048006Skato		    EWOULDBLOCK) {
60148006Skato			sc->sc_state = 0;
60248006Skato			splx(s);
60348006Skato			return (EBUSY);
60448006Skato		}
60548006Skato
60648006Skato		/* is printer online and ready for output */
60748006Skato	} while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
60848006Skato		 (LPS_SEL|LPS_NBSY|LPS_NERR));
60948006Skato
61048006Skato	sc->sc_control = LPC_SEL|LPC_NINIT;
61148006Skato	if (sc->sc_flags & LP_AUTOLF)
61248006Skato		sc->sc_control |= LPC_AUTOL;
61348006Skato
61448006Skato	/* enable interrupt if interrupt-driven */
61548006Skato	if (sc->sc_irq & LP_USE_IRQ)
61648006Skato		sc->sc_control |= LPC_ENA;
61748006Skato
61848006Skato	outb(port+lpt_control, sc->sc_control);
61948006Skato#endif
62048006Skato
62148006Skato	sc->sc_state = OPEN;
62248006Skato	sc->sc_inbuf = geteblk(BUFSIZE);
62348006Skato	sc->sc_xfercnt = 0;
62448006Skato	splx(s);
62548006Skato
62648006Skato	/* only use timeout if using interrupt */
62748006Skato	lprintf(("irq %x\n", sc->sc_irq));
62848006Skato	if (sc->sc_irq & LP_USE_IRQ) {
62948006Skato		sc->sc_state |= TOUT;
63048006Skato		timeout (lptout, (caddr_t)sc,
63148006Skato			 (sc->sc_backoff = hz/LPTOUTINITIAL));
63248006Skato	}
63348006Skato
63448006Skato	lprintf(("opened.\n"));
63548006Skato	return(0);
63648006Skato}
63748006Skato
63848006Skatostatic void
63948006Skatolptout (void *arg)
64048006Skato{
64148006Skato	struct lpt_softc *sc = arg;
64248006Skato	int pl;
64348006Skato
64448006Skato	lprintf(("T %x ", inb(sc->sc_port+lpt_status)));
64548006Skato	if (sc->sc_state & OPEN) {
64648006Skato		sc->sc_backoff++;
64748006Skato		if (sc->sc_backoff > hz/LPTOUTMAX)
64848006Skato			sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
64948006Skato		timeout (lptout, (caddr_t)sc, sc->sc_backoff);
65048006Skato	} else
65148006Skato		sc->sc_state &= ~TOUT;
65248006Skato
65348006Skato	if (sc->sc_state & ERROR)
65448006Skato		sc->sc_state &= ~ERROR;
65548006Skato
65648006Skato	/*
65748006Skato	 * Avoid possible hangs do to missed interrupts
65848006Skato	 */
65948006Skato	if (sc->sc_xfercnt) {
66048006Skato		pl = spltty();
66148006Skato		lptintr(sc - lpt_sc);
66248006Skato		splx(pl);
66348006Skato	} else {
66448006Skato		sc->sc_state &= ~OBUSY;
66548006Skato		wakeup((caddr_t)sc);
66648006Skato	}
66748006Skato}
66848006Skato
66948006Skato/*
67048006Skato * lptclose -- close the device, free the local line buffer.
67148006Skato *
67248006Skato * Check for interrupted write call added.
67348006Skato */
67448006Skato
67548006Skatostatic	int
67648006Skatolptclose(dev_t dev, int flags, int fmt, struct proc *p)
67748006Skato{
67848006Skato	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
67948006Skato#ifndef PC98
68048006Skato	int port = sc->sc_port;
68148006Skato#endif
68248006Skato
68348006Skato	if(sc->sc_flags & LP_BYPASS)
68448006Skato		goto end_close;
68548006Skato
68648006Skato	sc->sc_state &= ~OPEN;
68748006Skato
68848006Skato#ifndef PC98
68948006Skato	/* if the last write was interrupted, don't complete it */
69048006Skato	if((!(sc->sc_state  & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ))
69148006Skato		while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
69248006Skato			(LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
69348006Skato			/* wait 1/4 second, give up if we get a signal */
69448006Skato			if (tsleep ((caddr_t)sc, LPPRI|PCATCH,
69548006Skato				"lpclose", hz) != EWOULDBLOCK)
69648006Skato				break;
69748006Skato
69848006Skato	outb(sc->sc_port+lpt_control, LPC_NINIT);
69948006Skato#endif
70048006Skato	brelse(sc->sc_inbuf);
70148006Skato
70248006Skatoend_close:
70348006Skato	sc->sc_state = 0;
70448006Skato	sc->sc_xfercnt = 0;
70548006Skato	lprintf(("closed.\n"));
70648006Skato	return(0);
70748006Skato}
70848006Skato
70948006Skato/*
71048006Skato * pushbytes()
71148006Skato *	Workhorse for actually spinning and writing bytes to printer
71248006Skato *	Derived from lpa.c
71348006Skato *	Originally by ?
71448006Skato *
71548006Skato *	This code is only used when we are polling the port
71648006Skato */
71748006Skatostatic int
71848006Skatopushbytes(struct lpt_softc * sc)
71948006Skato{
72048006Skato	int spin, err, tic;
72148006Skato	char ch;
72248006Skato	int port = sc->sc_port;
72348006Skato
72448006Skato	lprintf(("p"));
72548006Skato	/* loop for every character .. */
72648006Skato	while (sc->sc_xfercnt > 0) {
72748006Skato		/* printer data */
72848006Skato		ch = *(sc->sc_cp);
72948006Skato		sc->sc_cp++;
73048006Skato		sc->sc_xfercnt--;
73148006Skato
73248006Skato		/*
73348006Skato		 * Wait for printer ready.
73448006Skato		 * Loop 20 usecs testing BUSY bit, then sleep
73548006Skato		 * for exponentially increasing timeout. (vak)
73648006Skato		 */
73748006Skato		for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
73848006Skato			DELAY(1);	/* XXX delay is NOT this accurate! */
73948006Skato		if (spin >= MAX_SPIN) {
74048006Skato			tic = 0;
74148006Skato			while (NOT_READY(port+lpt_status)) {
74248006Skato				/*
74348006Skato				 * Now sleep, every cycle a
74448006Skato				 * little longer ..
74548006Skato				 */
74648006Skato				tic = tic + tic + 1;
74748006Skato				/*
74848006Skato				 * But no more than 10 seconds. (vak)
74948006Skato				 */
75048006Skato				if (tic > MAX_SLEEP)
75148006Skato					tic = MAX_SLEEP;
75248006Skato				err = tsleep((caddr_t)sc, LPPRI,
75348006Skato					"lptpoll", tic);
75448006Skato				if (err != EWOULDBLOCK) {
75548006Skato					return (err);
75648006Skato				}
75748006Skato			}
75848006Skato		}
75948006Skato
76048006Skato		/* output data */
76148006Skato		outb(port+lpt_data, ch);
76248006Skato#ifdef PC98
76348006Skato		DELAY(1);
76448006Skato		outb(port+lpt_control, LPC_PSTB);
76548006Skato		DELAY(1);
76648006Skato		outb(port+lpt_control, LPC_NPSTB);
76748006Skato#else
76848006Skato		/* strobe */
76948006Skato		outb(port+lpt_control, sc->sc_control|LPC_STB);
77048006Skato		outb(port+lpt_control, sc->sc_control);
77148006Skato#endif
77248006Skato
77348006Skato	}
77448006Skato	return(0);
77548006Skato}
77648006Skato
77748006Skato/*
77848006Skato * lptwrite --copy a line from user space to a local buffer, then call
77948006Skato * putc to get the chars moved to the output queue.
78048006Skato *
78148006Skato * Flagging of interrupted write added.
78248006Skato */
78348006Skato
78448006Skatostatic	int
78548006Skatolptwrite(dev_t dev, struct uio * uio, int ioflag)
78648006Skato{
78748006Skato	register unsigned n;
78848006Skato	int pl, err;
78948006Skato	struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
79048006Skato
79148006Skato	if(sc->sc_flags & LP_BYPASS) {
79248006Skato		/* we can't do writes in bypass mode */
79348006Skato		return(EPERM);
79448006Skato	}
79548006Skato
79648006Skato	sc->sc_state &= ~INTERRUPTED;
79748006Skato	while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
79848006Skato		sc->sc_cp = sc->sc_inbuf->b_data ;
79948006Skato		uiomove(sc->sc_cp, n, uio);
80048006Skato		sc->sc_xfercnt = n ;
80148006Skato		while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
80248006Skato			lprintf(("i"));
80348006Skato			/* if the printer is ready for a char, */
80448006Skato			/* give it one */
80548006Skato			if ((sc->sc_state & OBUSY) == 0){
80648006Skato				lprintf(("\nC %d. ", sc->sc_xfercnt));
80748006Skato				pl = spltty();
80848006Skato				lptintr(sc - lpt_sc);
80948006Skato				(void) splx(pl);
81048006Skato			}
81148006Skato			lprintf(("W "));
81248006Skato			if (sc->sc_state & OBUSY)
81348006Skato				if ((err = tsleep ((caddr_t)sc,
81448006Skato					 LPPRI|PCATCH, "lpwrite", 0))) {
81548006Skato					sc->sc_state |= INTERRUPTED;
81648006Skato					return(err);
81748006Skato				}
81848006Skato		}
81948006Skato		/* check to see if we must do a polled write */
82048006Skato		if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
82148006Skato			lprintf(("p"));
82248006Skato			if((err = pushbytes(sc)))
82348006Skato				return(err);
82448006Skato		}
82548006Skato	}
82648006Skato	return(0);
82748006Skato}
82848006Skato
82948006Skato/*
83048006Skato * lptintr -- handle printer interrupts which occur when the printer is
83148006Skato * ready to accept another char.
83248006Skato *
83348006Skato * do checking for interrupted write call.
83448006Skato */
83548006Skato
83648006Skatostatic void
83748006Skatolptintr(int unit)
83848006Skato{
83948006Skato	struct lpt_softc *sc = lpt_sc + unit;
84048006Skato#ifndef PC98
84148006Skato	int port = sc->sc_port, sts;
84248006Skato	int i;
84348006Skato#endif
84448006Skato
84548006Skato#ifdef INET
84648006Skato	if(sc->sc_if.if_flags & IFF_UP) {
84748006Skato	    lpintr(unit);
84848006Skato	    return;
84948006Skato	}
85048006Skato#endif /* INET */
85148006Skato
85248006Skato#ifndef PC98
85348006Skato	/*
85448006Skato	 * Is printer online and ready for output?
85548006Skato	 *
85648006Skato	 * Avoid falling back to lptout() too quickly.  First spin-loop
85748006Skato	 * to see if the printer will become ready ``really soon now''.
85848006Skato	 */
85948006Skato	for (i = 0;
86048006Skato	     i < 100 &&
86148006Skato	     ((sts=inb(port+lpt_status)) & RDY_MASK) != LP_READY;
86248006Skato	     i++) ;
86348006Skato	if ((sts & RDY_MASK) == LP_READY) {
86448006Skato		sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR;
86548006Skato		sc->sc_backoff = hz/LPTOUTINITIAL;
86648006Skato
86748006Skato		if (sc->sc_xfercnt) {
86848006Skato			/* send char */
86948006Skato			/*lprintf(("%x ", *sc->sc_cp)); */
87048006Skato			outb(port+lpt_data, *sc->sc_cp++) ;
87148006Skato			outb(port+lpt_control, sc->sc_control|LPC_STB);
87248006Skato			/* DELAY(X) */
87348006Skato			outb(port+lpt_control, sc->sc_control);
87448006Skato
87548006Skato			/* any more data for printer */
87648006Skato			if(--(sc->sc_xfercnt) > 0) return;
87748006Skato		}
87848006Skato
87948006Skato		/*
88048006Skato		 * No more data waiting for printer.
88148006Skato		 * Wakeup is not done if write call was interrupted.
88248006Skato		 */
88348006Skato		sc->sc_state &= ~OBUSY;
88448006Skato		if(!(sc->sc_state & INTERRUPTED))
88548006Skato			wakeup((caddr_t)sc);
88648006Skato		lprintf(("w "));
88748006Skato		return;
88848006Skato	} else	{	/* check for error */
88948006Skato		if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
89048006Skato				(sc->sc_state & OPEN))
89148006Skato			sc->sc_state |= ERROR;
89248006Skato		/* lptout() will jump in and try to restart. */
89348006Skato	}
89448006Skato#endif
89548006Skato	lprintf(("sts %x ", sts));
89648006Skato}
89748006Skato
89848006Skatostatic	int
89948006Skatolptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
90048006Skato{
90148006Skato	int	error = 0;
90248006Skato        struct	lpt_softc *sc;
90348006Skato        u_int	unit = LPTUNIT(minor(dev));
90448006Skato	u_char	old_sc_irq;	/* old printer IRQ status */
90548006Skato
90648006Skato        sc = lpt_sc + unit;
90748006Skato
90848006Skato	switch (cmd) {
90948006Skato	case LPT_IRQ :
91048006Skato		if(sc->sc_irq & LP_HAS_IRQ) {
91148006Skato			/*
91248006Skato			 * NOTE:
91348006Skato			 * If the IRQ status is changed,
91448006Skato			 * this will only be visible on the
91548006Skato			 * next open.
91648006Skato			 *
91748006Skato			 * If interrupt status changes,
91848006Skato			 * this gets syslog'd.
91948006Skato			 */
92048006Skato			old_sc_irq = sc->sc_irq;
92148006Skato			if(*(int*)data == 0)
92248006Skato				sc->sc_irq &= (~LP_ENABLE_IRQ);
92348006Skato			else
92448006Skato				sc->sc_irq |= LP_ENABLE_IRQ;
92548006Skato			if (old_sc_irq != sc->sc_irq )
92648006Skato				log(LOG_NOTICE, "lpt%c switched to %s mode\n",
92748006Skato					(char)unit+'0',
92848006Skato					(sc->sc_irq & LP_ENABLE_IRQ)?
92948006Skato					"interrupt-driven":"polled");
93048006Skato		} else /* polled port */
93148006Skato			error = EOPNOTSUPP;
93248006Skato		break;
93348006Skato	default:
93448006Skato		error = ENODEV;
93548006Skato	}
93648006Skato
93748006Skato	return(error);
93848006Skato}
93948006Skato
94048006Skato#ifdef INET
94148006Skato
94248006Skatostatic void
94348006Skatolpattach (struct lpt_softc *sc, int unit)
94448006Skato{
94548006Skato	struct ifnet *ifp = &sc->sc_if;
94648006Skato
94748006Skato	ifp->if_softc = sc;
94848006Skato	ifp->if_name = "lp";
94948006Skato	ifp->if_unit = unit;
95048006Skato	ifp->if_mtu = LPMTU;
95148006Skato	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
95248006Skato	ifp->if_ioctl = lpioctl;
95348006Skato	ifp->if_output = lpoutput;
95448006Skato	ifp->if_type = IFT_PARA;
95548006Skato	ifp->if_hdrlen = 0;
95648006Skato	ifp->if_addrlen = 0;
95748006Skato	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
95848006Skato	if_attach(ifp);
95948006Skato	printf("lp%d: TCP/IP capable interface\n", unit);
96048006Skato
96148006Skato#if NBPFILTER > 0
96248006Skato	bpfattach(ifp, DLT_NULL, LPIPHDRLEN);
96348006Skato#endif
96448006Skato}
96548006Skato
96648006Skato#ifndef PC98
96748006Skato/*
96848006Skato * Build the translation tables for the LPIP (BSD unix) protocol.
96948006Skato * We don't want to calculate these nasties in our tight loop, so we
97048006Skato * precalculate them when we initialize.
97148006Skato */
97248006Skatostatic int
97348006Skatolpinittables (void)
97448006Skato{
97548006Skato    int i;
97648006Skato
97748006Skato    if (!txmith)
97848006Skato	txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
97948006Skato
98048006Skato    if (!txmith)
98148006Skato	return 1;
98248006Skato
98348006Skato    if (!ctxmith)
98448006Skato	ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
98548006Skato
98648006Skato    if (!ctxmith)
98748006Skato	return 1;
98848006Skato
98948006Skato    for (i=0; i < LPIPTBLSIZE; i++) {
99048006Skato	ctxmith[i] = (i & 0xF0) >> 4;
99148006Skato	ctxmitl[i] = 0x10 | (i & 0x0F);
99248006Skato	ctrecvh[i] = (i & 0x78) << 1;
99348006Skato	ctrecvl[i] = (i & 0x78) >> 3;
99448006Skato    }
99548006Skato
99648006Skato    for (i=0; i < LPIPTBLSIZE; i++) {
99748006Skato	txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
99848006Skato	txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
99948006Skato	trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
100048006Skato	trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
100148006Skato    }
100248006Skato
100348006Skato    return 0;
100448006Skato}
100548006Skato#endif /* PC98 */
100648006Skato
100748006Skato/*
100848006Skato * Process an ioctl request.
100948006Skato */
101048006Skato
101148006Skatostatic int
101248006Skatolpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
101348006Skato{
101448006Skato    struct lpt_softc *sc = lpt_sc + ifp->if_unit;
101548006Skato    struct ifaddr *ifa = (struct ifaddr *)data;
101648006Skato    struct ifreq *ifr = (struct ifreq *)data;
101748006Skato    u_char *ptr;
101848006Skato
101948006Skato    switch (cmd) {
102048006Skato
102148006Skato    case SIOCSIFDSTADDR:
102248006Skato    case SIOCAIFADDR:
102348006Skato    case SIOCSIFADDR:
102448006Skato	if (ifa->ifa_addr->sa_family != AF_INET)
102548006Skato	    return EAFNOSUPPORT;
102648006Skato	ifp->if_flags |= IFF_UP;
102748006Skato	/* FALLTHROUGH */
102848006Skato    case SIOCSIFFLAGS:
102948006Skato	if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
103048006Skato	    outb(sc->sc_port + lpt_control, 0x00);
103148006Skato	    ifp->if_flags &= ~IFF_RUNNING;
103248006Skato	    break;
103348006Skato	}
103448006Skato#ifdef PC98
103548006Skato	/* XXX */
103648006Skato	return ENOBUFS;
103748006Skato#else
103848006Skato	if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
103948006Skato	    if (lpinittables())
104048006Skato		return ENOBUFS;
104148006Skato	    sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
104248006Skato				  M_DEVBUF, M_WAITOK);
104348006Skato	    if (!sc->sc_ifbuf)
104448006Skato		return ENOBUFS;
104548006Skato
104648006Skato	    outb(sc->sc_port + lpt_control, LPC_ENA);
104748006Skato	    ifp->if_flags |= IFF_RUNNING;
104848006Skato	}
104948006Skato	break;
105048006Skato#endif
105148006Skato    case SIOCSIFMTU:
105248006Skato	ptr = sc->sc_ifbuf;
105348006Skato	sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
105448006Skato	if (!sc->sc_ifbuf) {
105548006Skato	    sc->sc_ifbuf = ptr;
105648006Skato	    return ENOBUFS;
105748006Skato	}
105848006Skato	if (ptr)
105948006Skato	    free(ptr,M_DEVBUF);
106048006Skato	sc->sc_if.if_mtu = ifr->ifr_mtu;
106148006Skato	break;
106248006Skato
106348006Skato    case SIOCGIFMTU:
106448006Skato	ifr->ifr_mtu = sc->sc_if.if_mtu;
106548006Skato	break;
106648006Skato
106748006Skato    case SIOCADDMULTI:
106848006Skato    case SIOCDELMULTI:
106948006Skato	if (ifr == 0) {
107048006Skato	    return EAFNOSUPPORT;		/* XXX */
107148006Skato	}
107248006Skato	switch (ifr->ifr_addr.sa_family) {
107348006Skato
107448006Skato#ifdef INET
107548006Skato	case AF_INET:
107648006Skato	    break;
107748006Skato#endif
107848006Skato
107948006Skato	default:
108048006Skato	    return EAFNOSUPPORT;
108148006Skato	}
108248006Skato	break;
108348006Skato
108448006Skato    default:
108548006Skato	lprintf(("LP:ioctl(0x%lx)\n", cmd));
108648006Skato	return EINVAL;
108748006Skato    }
108848006Skato    return 0;
108948006Skato}
109048006Skato
109148006Skatostatic __inline int
109248006Skatoclpoutbyte (u_char byte, int spin, int data_port, int status_port)
109348006Skato{
109448006Skato	outb(data_port, ctxmitl[byte]);
109548006Skato	while (inb(status_port) & CLPIP_SHAKE)
109648006Skato		if (--spin == 0) {
109748006Skato			return 1;
109848006Skato		}
109948006Skato	outb(data_port, ctxmith[byte]);
110048006Skato	while (!(inb(status_port) & CLPIP_SHAKE))
110148006Skato		if (--spin == 0) {
110248006Skato			return 1;
110348006Skato		}
110448006Skato	return 0;
110548006Skato}
110648006Skato
110748006Skatostatic __inline int
110848006Skatoclpinbyte (int spin, int data_port, int status_port)
110948006Skato{
111048006Skato	int c, cl;
111148006Skato
111248006Skato	while((inb(status_port) & CLPIP_SHAKE))
111348006Skato	    if(!--spin) {
111448006Skato		return -1;
111548006Skato	    }
111648006Skato	cl = inb(status_port);
111748006Skato	outb(data_port, 0x10);
111848006Skato
111948006Skato	while(!(inb(status_port) & CLPIP_SHAKE))
112048006Skato	    if(!--spin) {
112148006Skato		return -1;
112248006Skato	    }
112348006Skato	c = inb(status_port);
112448006Skato	outb(data_port, 0x00);
112548006Skato
112648006Skato	return (ctrecvl[cl] | ctrecvh[c]);
112748006Skato}
112848006Skato
112948006Skatostatic void
113048006Skatolpintr (int unit)
113148006Skato{
113248006Skato	struct   lpt_softc *sc = lpt_sc + unit;
113348006Skato	register int lpt_data_port = sc->sc_port + lpt_data;
113448006Skato	register int lpt_stat_port = sc->sc_port + lpt_status;
113548006Skato		 int lpt_ctrl_port = sc->sc_port + lpt_control;
113648006Skato	int len, s, j;
113748006Skato	u_char *bp;
113848006Skato	u_char c, cl;
113948006Skato	struct mbuf *top;
114048006Skato
114148006Skato	s = splhigh();
114248006Skato
114348006Skato	if (sc->sc_if.if_flags & IFF_LINK0) {
114448006Skato
114548006Skato	    /* Ack. the request */
114648006Skato	    outb(lpt_data_port, 0x01);
114748006Skato
114848006Skato	    /* Get the packet length */
114948006Skato	    j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
115048006Skato	    if (j == -1)
115148006Skato		goto err;
115248006Skato	    len = j;
115348006Skato	    j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
115448006Skato	    if (j == -1)
115548006Skato		goto err;
115648006Skato	    len = len + (j << 8);
115748006Skato	    if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
115848006Skato		goto err;
115948006Skato
116048006Skato	    bp  = sc->sc_ifbuf;
116148006Skato
116248006Skato	    while (len--) {
116348006Skato	        j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
116448006Skato	        if (j == -1) {
116548006Skato		    goto err;
116648006Skato	        }
116748006Skato	        *bp++ = j;
116848006Skato	    }
116948006Skato	    /* Get and ignore checksum */
117048006Skato	    j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
117148006Skato	    if (j == -1) {
117248006Skato	        goto err;
117348006Skato	    }
117448006Skato
117548006Skato	    len = bp - sc->sc_ifbuf;
117648006Skato	    if (len <= CLPIPHDRLEN)
117748006Skato	        goto err;
117848006Skato
117948006Skato	    sc->sc_iferrs = 0;
118048006Skato
118148006Skato	    if (IF_QFULL(&ipintrq)) {
118248006Skato	        lprintf(("DROP"));
118348006Skato	        IF_DROP(&ipintrq);
118448006Skato		goto done;
118548006Skato	    }
118648006Skato	    len -= CLPIPHDRLEN;
118748006Skato	    sc->sc_if.if_ipackets++;
118848006Skato	    sc->sc_if.if_ibytes += len;
118948006Skato	    top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
119048006Skato	    if (top) {
119148006Skato	        IF_ENQUEUE(&ipintrq, top);
119248006Skato	        schednetisr(NETISR_IP);
119348006Skato	    }
119448006Skato	    goto done;
119548006Skato	}
119648006Skato	while ((inb(lpt_stat_port) & LPIP_SHAKE)) {
119748006Skato	    len = sc->sc_if.if_mtu + LPIPHDRLEN;
119848006Skato	    bp  = sc->sc_ifbuf;
119948006Skato	    while (len--) {
120048006Skato
120148006Skato		cl = inb(lpt_stat_port);
120248006Skato		outb(lpt_data_port, 8);
120348006Skato
120448006Skato		j = LPMAXSPIN2;
120548006Skato		while((inb(lpt_stat_port) & LPIP_SHAKE))
120648006Skato		    if(!--j) goto err;
120748006Skato
120848006Skato		c = inb(lpt_stat_port);
120948006Skato		outb(lpt_data_port, 0);
121048006Skato
121148006Skato		*bp++= trecvh[cl] | trecvl[c];
121248006Skato
121348006Skato		j = LPMAXSPIN2;
121448006Skato		while (!((cl=inb(lpt_stat_port)) & LPIP_SHAKE)) {
121548006Skato		    if (cl != c &&
121648006Skato			(((cl = inb(lpt_stat_port)) ^ 0xb8) & 0xf8) ==
121748006Skato			  (c & 0xf8))
121848006Skato			goto end;
121948006Skato		    if (!--j) goto err;
122048006Skato		}
122148006Skato	    }
122248006Skato
122348006Skato	end:
122448006Skato	    len = bp - sc->sc_ifbuf;
122548006Skato	    if (len <= LPIPHDRLEN)
122648006Skato		goto err;
122748006Skato
122848006Skato	    sc->sc_iferrs = 0;
122948006Skato
123048006Skato	    if (IF_QFULL(&ipintrq)) {
123148006Skato		lprintf(("DROP"));
123248006Skato		IF_DROP(&ipintrq);
123348006Skato		goto done;
123448006Skato	    }
123548006Skato#if NBPFILTER > 0
123648006Skato	    if (sc->sc_if.if_bpf) {
123748006Skato		bpf_tap(&sc->sc_if, sc->sc_ifbuf, len);
123848006Skato	    }
123948006Skato#endif
124048006Skato	    len -= LPIPHDRLEN;
124148006Skato	    sc->sc_if.if_ipackets++;
124248006Skato	    sc->sc_if.if_ibytes += len;
124348006Skato	    top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
124448006Skato	    if (top) {
124548006Skato		    IF_ENQUEUE(&ipintrq, top);
124648006Skato		    schednetisr(NETISR_IP);
124748006Skato	    }
124848006Skato	}
124948006Skato	goto done;
125048006Skato
125148006Skato    err:
125248006Skato	outb(lpt_data_port, 0);
125348006Skato	lprintf(("R"));
125448006Skato	sc->sc_if.if_ierrors++;
125548006Skato	sc->sc_iferrs++;
125648006Skato
125748006Skato	/*
125848006Skato	 * We are not able to send receive anything for now,
125948006Skato	 * so stop wasting our time
126048006Skato	 */
126148006Skato	if (sc->sc_iferrs > LPMAXERRS) {
126248006Skato	    printf("lp%d: Too many errors, Going off-line.\n", unit);
126348006Skato	    outb(lpt_ctrl_port, 0x00);
126448006Skato	    sc->sc_if.if_flags &= ~IFF_RUNNING;
126548006Skato	    sc->sc_iferrs=0;
126648006Skato	}
126748006Skato
126848006Skato    done:
126948006Skato	splx(s);
127048006Skato	return;
127148006Skato}
127248006Skato
127348006Skatostatic __inline int
127448006Skatolpoutbyte (u_char byte, int spin, int data_port, int status_port)
127548006Skato{
127648006Skato    outb(data_port, txmith[byte]);
127748006Skato    while (!(inb(status_port) & LPIP_SHAKE))
127848006Skato	if (--spin == 0)
127948006Skato		return 1;
128048006Skato    outb(data_port, txmitl[byte]);
128148006Skato    while (inb(status_port) & LPIP_SHAKE)
128248006Skato	if (--spin == 0)
128348006Skato		return 1;
128448006Skato    return 0;
128548006Skato}
128648006Skato
128748006Skatostatic int
128848006Skatolpoutput (struct ifnet *ifp, struct mbuf *m,
128948006Skato	  struct sockaddr *dst, struct rtentry *rt)
129048006Skato{
129148006Skato    register int lpt_data_port = lpt_sc[ifp->if_unit].sc_port + lpt_data;
129248006Skato    register int lpt_stat_port = lpt_sc[ifp->if_unit].sc_port + lpt_status;
129348006Skato#ifndef PC98
129448006Skato	     int lpt_ctrl_port = lpt_sc[ifp->if_unit].sc_port + lpt_control;
129548006Skato#endif
129648006Skato
129748006Skato    int s, err;
129848006Skato    struct mbuf *mm;
129948006Skato    u_char *cp = "\0\0";
130048006Skato    u_char chksum = 0;
130148006Skato    int count = 0;
130248006Skato    int i;
130348006Skato    int spin;
130448006Skato
130548006Skato    /* We need a sensible value if we abort */
130648006Skato    cp++;
130748006Skato    ifp->if_flags |= IFF_RUNNING;
130848006Skato
130948006Skato    err = 1;			/* assume we're aborting because of an error */
131048006Skato
131148006Skato    s = splhigh();
131248006Skato
131348006Skato#ifndef PC98
131448006Skato    /* Suspend (on laptops) or receive-errors might have taken us offline */
131548006Skato    outb(lpt_ctrl_port, LPC_ENA);
131648006Skato#endif
131748006Skato
131848006Skato    if (ifp->if_flags & IFF_LINK0) {
131948006Skato
132048006Skato	if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) {
132148006Skato	    lprintf(("&"));
132248006Skato	    lptintr(ifp->if_unit);
132348006Skato	}
132448006Skato
132548006Skato	/* Alert other end to pending packet */
132648006Skato	spin = LPMAXSPIN1;
132748006Skato	outb(lpt_data_port, 0x08);
132848006Skato	while ((inb(lpt_stat_port) & 0x08) == 0)
132948006Skato		if (--spin == 0) {
133048006Skato			goto nend;
133148006Skato		}
133248006Skato
133348006Skato	/* Calculate length of packet, then send that */
133448006Skato
133548006Skato	count += 14;		/* Ethernet header len */
133648006Skato
133748006Skato	mm = m;
133848006Skato	for (mm = m; mm; mm = mm->m_next) {
133948006Skato		count += mm->m_len;
134048006Skato	}
134148006Skato	if (clpoutbyte(count & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
134248006Skato		goto nend;
134348006Skato	if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
134448006Skato		goto nend;
134548006Skato
134648006Skato	/* Send dummy ethernet header */
134748006Skato	for (i = 0; i < 12; i++) {
134848006Skato		if (clpoutbyte(i, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
134948006Skato			goto nend;
135048006Skato		chksum += i;
135148006Skato	}
135248006Skato
135348006Skato	if (clpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
135448006Skato		goto nend;
135548006Skato	if (clpoutbyte(0x00, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
135648006Skato		goto nend;
135748006Skato	chksum += 0x08 + 0x00;		/* Add into checksum */
135848006Skato
135948006Skato	mm = m;
136048006Skato	do {
136148006Skato		cp = mtod(mm, u_char *);
136248006Skato		while (mm->m_len--) {
136348006Skato			chksum += *cp;
136448006Skato			if (clpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
136548006Skato				goto nend;
136648006Skato		}
136748006Skato	} while ((mm = mm->m_next));
136848006Skato
136948006Skato	/* Send checksum */
137048006Skato	if (clpoutbyte(chksum, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
137148006Skato		goto nend;
137248006Skato
137348006Skato	/* Go quiescent */
137448006Skato	outb(lpt_data_port, 0);
137548006Skato
137648006Skato	err = 0;			/* No errors */
137748006Skato
137848006Skato	nend:
137948006Skato	if (err)  {				/* if we didn't timeout... */
138048006Skato		ifp->if_oerrors++;
138148006Skato		lprintf(("X"));
138248006Skato	} else {
138348006Skato		ifp->if_opackets++;
138448006Skato		ifp->if_obytes += m->m_pkthdr.len;
138548006Skato	}
138648006Skato
138748006Skato	m_freem(m);
138848006Skato
138948006Skato	if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) {
139048006Skato		lprintf(("^"));
139148006Skato		lptintr(ifp->if_unit);
139248006Skato	}
139348006Skato	(void) splx(s);
139448006Skato	return 0;
139548006Skato    }
139648006Skato
139748006Skato    if (inb(lpt_stat_port) & LPIP_SHAKE) {
139848006Skato        lprintf(("&"));
139948006Skato        lptintr(ifp->if_unit);
140048006Skato    }
140148006Skato
140248006Skato    if (lpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
140348006Skato        goto end;
140448006Skato    if (lpoutbyte(0x00, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
140548006Skato        goto end;
140648006Skato
140748006Skato    mm = m;
140848006Skato    do {
140948006Skato        cp = mtod(mm,u_char *);
141048006Skato        while (mm->m_len--)
141148006Skato	    if (lpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
141248006Skato	        goto end;
141348006Skato    } while ((mm = mm->m_next));
141448006Skato
141548006Skato    err = 0;				/* no errors were encountered */
141648006Skato
141748006Skato    end:
141848006Skato    --cp;
141948006Skato    outb(lpt_data_port, txmitl[*cp] ^ 0x17);
142048006Skato
142148006Skato    if (err)  {				/* if we didn't timeout... */
142248006Skato	ifp->if_oerrors++;
142348006Skato        lprintf(("X"));
142448006Skato    } else {
142548006Skato	ifp->if_opackets++;
142648006Skato	ifp->if_obytes += m->m_pkthdr.len;
142748006Skato#if NBPFILTER > 0
142848006Skato	if (ifp->if_bpf) {
142948006Skato	    /*
143048006Skato	     * We need to prepend the packet type as
143148006Skato	     * a two byte field.  Cons up a dummy header
143248006Skato	     * to pacify bpf.  This is safe because bpf
143348006Skato	     * will only read from the mbuf (i.e., it won't
143448006Skato	     * try to free it or keep a pointer to it).
143548006Skato	     */
143648006Skato	    struct mbuf m0;
143748006Skato	    u_short hdr = 0x800;
143848006Skato
143948006Skato	    m0.m_next = m;
144048006Skato	    m0.m_len = 2;
144148006Skato	    m0.m_data = (char *)&hdr;
144248006Skato
144348006Skato	    bpf_mtap(ifp, &m0);
144448006Skato	}
144548006Skato#endif
144648006Skato    }
144748006Skato
144848006Skato    m_freem(m);
144948006Skato
145048006Skato    if (inb(lpt_stat_port) & LPIP_SHAKE) {
145148006Skato	lprintf(("^"));
145248006Skato	lptintr(ifp->if_unit);
145348006Skato    }
145448006Skato
145548006Skato    (void) splx(s);
145648006Skato    return 0;
145748006Skato}
145848006Skato
145948006Skato#endif /* INET */
146048006Skato
146148006Skatostatic int lpt_devsw_installed;
146248006Skato
146348006Skatostatic void 	lpt_drvinit(void *unused)
146448006Skato{
146548006Skato
146648006Skato	if( ! lpt_devsw_installed ) {
146748006Skato		cdevsw_add(&lpt_cdevsw);
146848006Skato		lpt_devsw_installed = 1;
146948006Skato    	}
147048006Skato}
147148006Skato
147248006SkatoSYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL)
147348006Skato
1474