lpt.c revision 46153
18012Sjulian/*
212090Sgibbs * Copyright (c) 1990 William F. Jolitz, TeleMuse
38012Sjulian * All rights reserved.
413691Sgibbs *
512090Sgibbs * Redistribution and use in source and binary forms, with or without
615329Sgibbs * modification, are permitted provided that the following conditions
712090Sgibbs * are met:
812090Sgibbs * 1. Redistributions of source code must retain the above copyright
912090Sgibbs *    notice, this list of conditions and the following disclaimer.
1012090Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1112090Sgibbs *    notice, this list of conditions and the following disclaimer in the
1212090Sgibbs *    documentation and/or other materials provided with the distribution.
1312090Sgibbs * 3. All advertising materials mentioning features or use of this software
1412090Sgibbs *    must display the following acknowledgement:
1512090Sgibbs *	This software is a component of "386BSD" developed by
1615329Sgibbs *	William F. Jolitz, TeleMuse.
1715329Sgibbs * 4. Neither the name of the developer nor the name "386BSD"
1815329Sgibbs *    may be used to endorse or promote products derived from this software
1915329Sgibbs *    without specific prior written permission.
2015329Sgibbs *
2115329Sgibbs * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
2215329Sgibbs * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
2315329Sgibbs * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
2415329Sgibbs * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
2515329Sgibbs * NOT MAKE USE OF THIS WORK.
2615329Sgibbs *
2715329Sgibbs * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
2815329Sgibbs * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
2915329Sgibbs * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
308012Sjulian * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
3150477Speter * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
328012Sjulian * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
3323855Sjoerg * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
3423855Sjoerg * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
3523855Sjoerg *
368012Sjulian * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
3712090Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3845791Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3912090Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
4045791Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4145791Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4245791Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
438012Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4428551Sbde * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4545791Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4645791Speter * SUCH DAMAGE.
4745791Speter *
4828551Sbde *	from: unknown origin, 386BSD 0.1
4955953Speter *	From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
508012Sjulian *	From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp
5145791Speter *	$Id: lpt.c,v 1.2 1999/02/14 16:19:16 nsouch Exp $
5245791Speter */
5345791Speter
5445791Speter/*
5545791Speter * Device Driver for AT parallel printer port
5645791Speter * Written by William Jolitz 12/18/90
5745791Speter */
5845791Speter
5945791Speter/*
6045791Speter * Updated for ppbus by Nicolas Souchu
6145791Speter * [Mon Jul 28 1997]
6245791Speter */
6349360Smdodd
6445791Speter
6545791Speter#ifdef KERNEL
6612090Sgibbs#include "opt_devfs.h"
678012Sjulian
6845791Speter#include <sys/param.h>
6912090Sgibbs#include <sys/systm.h>
7045791Speter#include <sys/conf.h>
7145791Speter#include <sys/buf.h>
7245791Speter#include <sys/kernel.h>
7345791Speter#include <sys/uio.h>
7445791Speter#include <sys/syslog.h>
7545791Speter#ifdef DEVFS
7612177Sgibbs#include <sys/devfsext.h>
7745791Speter#endif /*DEVFS*/
7845791Speter#include <sys/malloc.h>
7945791Speter
8045791Speter#include <machine/clock.h>
8145791Speter#include <machine/lpt.h>
8212177Sgibbs#endif /*KERNEL*/
8345791Speter
8423855Sjoerg#include <dev/ppbus/ppbconf.h>
8549281Smdodd#include <dev/ppbus/ppb_1284.h>
8623855Sjoerg#include <dev/ppbus/lpt.h>
8723855Sjoerg
8823855Sjoerg#include "opt_lpt.h"
8920450Sjoerg
9045791Speter#ifndef LPT_DEBUG
9145791Speter#define lprintf(args)
9245791Speter#else
9349281Smdodd#define lprintf(args)						\
9449360Smdodd		do {						\
9549281Smdodd			if (lptflag)				\
9649281Smdodd				printf args;			\
9749281Smdodd		} while (0)
9845791Speterstatic int volatile lptflag = 1;
9945791Speter#endif
10045791Speter
10145791Speter#define	LPINITRDY	4	/* wait up to 4 seconds for a ready */
10245791Speter#define	LPTOUTINITIAL	10	/* initial timeout to wait for ready 1/10 s */
10345791Speter#define	LPTOUTMAX	1	/* maximal timeout 1 s */
10445791Speter#define	LPPRI		(PZERO+8)
10545791Speter#define	BUFSIZE		1024
10645791Speter#define	BUFSTATSIZE	32
10745791Speter
10845791Speter#define	LPTUNIT(s)	((s)&0x03)
10945791Speter#define	LPTFLAGS(s)	((s)&0xfc)
11045791Speter
11145791Speterstruct lpt_data {
11248754Sdfr	unsigned short lpt_unit;
11345791Speter
11445791Speter	struct ppb_device lpt_dev;
11545791Speter
11645791Speter	short	sc_state;
11745791Speter	/* default case: negative prime, negative ack, handshake strobe,
11845791Speter	   prime once */
11945791Speter	u_char	sc_control;
12045791Speter	char	sc_flags;
12145791Speter#define LP_POS_INIT	0x04	/* if we are a postive init signal */
12245791Speter#define LP_POS_ACK	0x08	/* if we are a positive going ack */
12345791Speter#define LP_NO_PRIME	0x10	/* don't prime the printer at all */
12445791Speter#define LP_PRIMEOPEN	0x20	/* prime on every open */
12545791Speter#define LP_AUTOLF	0x40	/* tell printer to do an automatic lf */
12645818Speter#define LP_BYPASS	0x80	/* bypass  printer ready checks */
12745791Speter	struct	buf *sc_inbuf;
12845791Speter	struct	buf *sc_statbuf;
12945791Speter	short	sc_xfercnt ;
13045791Speter	char	sc_primed;
13145791Speter	char	*sc_cp ;
13245791Speter	u_short	sc_irq ;	/* IRQ status of port */
13345791Speter#define LP_HAS_IRQ	0x01	/* we have an irq available */
13445791Speter#define LP_USE_IRQ	0x02	/* we are using our irq */
13545791Speter#define LP_ENABLE_IRQ	0x04	/* enable IRQ on open */
13645791Speter#define LP_ENABLE_EXT	0x10	/* we shall use advanced mode when possible */
13745791Speter	u_char	sc_backoff ;	/* time to call lptout() again */
13845791Speter
13945791Speter#ifdef DEVFS
14045791Speter	void	*devfs_token;
14145791Speter	void	*devfs_token_ctl;
14245791Speter#endif
14345791Speter};
14445791Speter
14545791Speterstatic int	nlpt = 0;
14613691Sgibbs#define MAXLPT	8			/* XXX not much better! */
14713691Sgibbsstatic struct lpt_data *lptdata[MAXLPT];
1488012Sjulian
1498012Sjulian#define LPT_NAME	"lpt"		/* our official name */
15045791Speter
15145791Speterstatic timeout_t lptout;
1528012Sjulianstatic int	lpt_port_test(struct lpt_data *sc, u_char data, u_char mask);
15312157Sgibbsstatic int	lpt_detect(struct lpt_data *sc);
15412157Sgibbs
15554073Smdodd/*
15612157Sgibbs * Make ourselves visible as a ppbus driver
15712157Sgibbs */
15847308Speter
1598012Sjulianstatic struct ppb_device	*lptprobe(struct ppb_data *ppb);
16045804Speterstatic int			lptattach(struct ppb_device *dev);
16145804Speterstatic void			lptintr(int unit);
16220450Sjoergstatic void			lpt_drvinit(void *unused);
16312157Sgibbs
16412157Sgibbsstatic void			lpt_intr(int unit);	/* without spls */
16512157Sgibbs
16613179Sgibbs#ifdef KERNEL
16712157Sgibbs
16812157Sgibbsstatic struct ppb_driver lptdriver = {
16912157Sgibbs    lptprobe, lptattach, LPT_NAME
17012157Sgibbs};
17112157SgibbsDATA_SET(ppbdriver_set, lptdriver);
17247308Speter
17347308Speter#endif /* KERNEL */
17412157Sgibbs
17545791Speter/* bits for state */
17645791Speter#define	OPEN		(1<<0)	/* device is open */
17745791Speter#define	ASLP		(1<<1)	/* awaiting draining of printer */
17845818Speter#define	EERROR		(1<<2)	/* error was received from printer */
17912157Sgibbs#define	OBUSY		(1<<3)	/* printer is busy doing output */
18012157Sgibbs#define LPTOUT		(1<<4)	/* timeout while not selected */
18145791Speter#define TOUT		(1<<5)	/* timeout while not selected */
18213691Sgibbs#define LPTINIT		(1<<6)	/* waiting to initialize for open */
18312157Sgibbs#define INTERRUPTED	(1<<7)	/* write call was interrupted */
18413691Sgibbs
18512157Sgibbs#define HAVEBUS		(1<<8)	/* the driver owns the bus */
18613691Sgibbs
18713691Sgibbs
18813691Sgibbs/* status masks to interrogate printer status */
18913691Sgibbs#define RDY_MASK	(LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)	/* ready ? */
19029674Sgibbs#define LP_READY	(LPS_SEL|LPS_NBSY|LPS_NERR)
19113691Sgibbs
19254073Smdodd/* Printer Ready condition  - from lpa.c */
19354073Smdodd/* Only used in polling code */
19412090Sgibbs#define	LPS_INVERT	(LPS_NBSY | LPS_NACK |           LPS_SEL | LPS_NERR)
1958012Sjulian#define	LPS_MASK	(LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
19647308Speter#define	NOT_READY(lpt)	((ppb_rstr(&(lpt)->lpt_dev)^LPS_INVERT)&LPS_MASK)
19747308Speter
19847308Speter#define	MAX_SLEEP	(hz*5)	/* Timeout while waiting for device ready */
19947308Speter#define	MAX_SPIN	20	/* Max delay for device ready in usecs */
20047308Speter
20147308Speter
20245791Speterstatic	d_open_t	lptopen;
20312157Sgibbsstatic	d_close_t	lptclose;
20445791Speterstatic	d_write_t	lptwrite;
20548754Sdfrstatic	d_read_t	lptread;
20648754Sdfrstatic	d_ioctl_t	lptioctl;
20748754Sdfr
20848754Sdfr#define CDEV_MAJOR 16
20948754Sdfrstatic struct cdevsw lpt_cdevsw =
21048754Sdfr	{ lptopen,	lptclose,	lptread,	lptwrite,	/*16*/
21148754Sdfr	  lptioctl,	nullstop,	nullreset,	nodevtotty,	/* lpt */
21248754Sdfr	  seltrue,	nommap,		nostrat,	LPT_NAME,	NULL,	-1 };
21348754Sdfr
21448754Sdfrstatic int
21548754Sdfrlpt_request_ppbus(struct lpt_data *sc, int how)
21648754Sdfr{
21748754Sdfr	int error;
21848754Sdfr
21948754Sdfr	if (sc->sc_state & HAVEBUS)
22048754Sdfr		return (0);
22148754Sdfr
22249281Smdodd	/* we have the bus only if the request succeded */
22349281Smdodd	if ((error = ppb_request_bus(&sc->lpt_dev, how)) == 0)
22449281Smdodd		sc->sc_state |= HAVEBUS;
22549281Smdodd
22649281Smdodd	return (error);
22749281Smdodd}
22849281Smdodd
22949281Smdoddstatic int
23049281Smdoddlpt_release_ppbus(struct lpt_data *sc)
23149281Smdodd{
23249281Smdodd	ppb_release_bus(&sc->lpt_dev);
23349281Smdodd	sc->sc_state &= ~HAVEBUS;
23449281Smdodd
23549281Smdodd	return (0);
23649281Smdodd}
23749281Smdodd
23849281Smdodd/*
23949281Smdodd * Internal routine to lptprobe to do port tests of one byte value
24049281Smdodd */
24149281Smdoddstatic int
24249281Smdoddlpt_port_test(struct lpt_data *sc, u_char data, u_char mask)
24349281Smdodd{
24449281Smdodd	int	temp, timeout;
24549281Smdodd
24649281Smdodd	data = data & mask;
24749281Smdodd	ppb_wdtr(&sc->lpt_dev, data);
24849281Smdodd	timeout = 10000;
24949281Smdodd	do {
25049281Smdodd		DELAY(10);
25149281Smdodd		temp = ppb_rdtr(&sc->lpt_dev) & mask;
25249281Smdodd	}
25349281Smdodd	while (temp != data && --timeout);
25449195Smdodd	lprintf(("out=%x\tin=%x\ttout=%d\n", data, temp, timeout));
25545791Speter	return (temp == data);
25645791Speter}
25749281Smdodd
25849281Smdodd/*
25949281Smdodd * Probe simplified by replacing multiple loops with a hardcoded
26049382Smdodd * test pattern - 1999/02/08 des@freebsd.org
26149281Smdodd *
26249281Smdodd * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
26349281Smdodd * Based partially on Rod Grimes' printer probe
26449281Smdodd *
26549195Smdodd * Logic:
26649281Smdodd *	1) If no port address was given, use the bios detected ports
26749281Smdodd *	   and autodetect what ports the printers are on.
26849281Smdodd *	2) Otherwise, probe the data port at the address given,
26949281Smdodd *	   using the method in Rod Grimes' port probe.
27049195Smdodd *	   (Much code ripped off directly from Rod's probe.)
27149281Smdodd *
27249281Smdodd * Comments from Rod's probe:
27349281Smdodd * Logic:
27449281Smdodd *	1) You should be able to write to and read back the same value
27549281Smdodd *	   to the data port.  Do an alternating zeros, alternating ones,
27649281Smdodd *	   walking zero, and walking one test to check for stuck bits.
27749281Smdodd *
27849281Smdodd *	2) You should be able to write to and read back the same value
27949281Smdodd *	   to the control port lower 5 bits, the upper 3 bits are reserved
28049281Smdodd *	   per the IBM PC technical reference manauls and different boards
28149281Smdodd *	   do different things with them.  Do an alternating zeros, alternating
28249281Smdodd *	   ones, walking zero, and walking one test to check for stuck bits.
28349281Smdodd *
28449281Smdodd *	   Some printers drag the strobe line down when the are powered off
28549281Smdodd * 	   so this bit has been masked out of the control port test.
28649281Smdodd *
28749195Smdodd *	   XXX Some printers may not like a fast pulse on init or strobe, I
28849281Smdodd *	   don't know at this point, if that becomes a problem these bits
28949281Smdodd *	   should be turned off in the mask byte for the control port test.
29049281Smdodd *
29149281Smdodd *	   We are finally left with a mask of 0x14, due to some printers
29249281Smdodd *	   being adamant about holding other bits high ........
29349281Smdodd *
29449281Smdodd *	   Before probing the control port, we write a 0 to the data port -
29549281Smdodd *	   If not, some printers chuck out garbage when the strobe line
29649281Smdodd *	   gets toggled.
29749281Smdodd *
29849281Smdodd *	3) Set the data and control ports to a value of 0
29949281Smdodd *
30049281Smdodd *	This probe routine has been tested on Epson Lx-800, HP LJ3P,
30149281Smdodd *	Epson FX-1170 and C.Itoh 8510RM
30249281Smdodd *	printers.
30349281Smdodd *	Quick exit on fail added.
30449281Smdodd */
30549281Smdoddstatic int
30649360Smdoddlpt_detect(struct lpt_data *sc)
30749360Smdodd{
30849360Smdodd	static u_char	testbyte[18] = {
30949281Smdodd		0x55,			/* alternating zeros */
31049281Smdodd		0xaa,			/* alternating ones */
31149281Smdodd		0xfe, 0xfd, 0xfb, 0xf7,
31249281Smdodd		0xef, 0xdf, 0xbf, 0x7f,	/* walking zero */
31349281Smdodd		0x01, 0x02, 0x04, 0x08,
31449281Smdodd		0x10, 0x20, 0x40, 0x80	/* walking one */
31549281Smdodd	};
31649281Smdodd	int		i, error, status;
31749195Smdodd
31845791Speter	status = 1;				/* assume success */
3198012Sjulian
32049360Smdodd	if ((error = lpt_request_ppbus(sc, PPB_DONTWAIT))) {
32145791Speter		printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error);
32245791Speter		status = 0;
32345791Speter		goto end_probe;
32445791Speter	}
32529674Sgibbs
32645791Speter	for (i = 0; i < 18 && status; i++)
32745791Speter		if (!lpt_port_test(sc, testbyte[i], 0xff)) {
32845791Speter			status = 0;
32945791Speter			goto end_probe;
33045791Speter		}
33145791Speter
33249360Smdoddend_probe:
33345791Speter	/* write 0's to control and data ports */
33449360Smdodd	ppb_wdtr(&sc->lpt_dev, 0);
33545791Speter	ppb_wctr(&sc->lpt_dev, 0);
3368012Sjulian
33745791Speter	lpt_release_ppbus(sc);
33845791Speter
33945791Speter	return (status);
34045791Speter}
34145791Speter
3428012Sjulian/*
34345791Speter * lptprobe()
34445791Speter */
34545791Speterstatic struct ppb_device *
34645791Speterlptprobe(struct ppb_data *ppb)
3478012Sjulian{
34845791Speter	struct lpt_data *sc;
34945791Speter
35045791Speter	sc = (struct lpt_data *) malloc(sizeof(struct lpt_data),
35145791Speter							M_TEMP, M_NOWAIT);
35245791Speter	if (!sc) {
35345791Speter		printf(LPT_NAME ": cannot malloc!\n");
35445791Speter		return (0);
35545791Speter	}
35645791Speter	bzero(sc, sizeof(struct lpt_data));
35745791Speter
35845791Speter	lptdata[nlpt] = sc;
35945791Speter
36045791Speter	/*
36145791Speter	 * lpt dependent initialisation.
36245791Speter	 */
36345791Speter	sc->lpt_unit = nlpt;
36445791Speter
36545791Speter	/*
36645791Speter	 * ppbus dependent initialisation.
36745791Speter	 */
36845791Speter	sc->lpt_dev.id_unit = sc->lpt_unit;
36949360Smdodd	sc->lpt_dev.name = lptdriver.name;
37045791Speter	sc->lpt_dev.ppb = ppb;
37145791Speter	sc->lpt_dev.intr = lptintr;
37245791Speter
37345791Speter	/*
37445791Speter	 * Now, try to detect the printer.
37545791Speter	 */
37645791Speter	if (!lpt_detect(sc)) {
37745791Speter		free(sc, M_TEMP);
37845791Speter		return (0);
37945791Speter	}
38045791Speter
38145791Speter	/* Ok, go to next device on next probe */
38249360Smdodd	nlpt ++;
38349360Smdodd
38449360Smdodd	return (&sc->lpt_dev);
38549360Smdodd}
38649360Smdodd
38745791Speterstatic int
38845791Speterlptattach(struct ppb_device *dev)
38945791Speter{
39045791Speter	struct lpt_data *sc = lptdata[dev->id_unit];
39112122Sgibbs	int error;
3928012Sjulian
39345791Speter	/*
39445791Speter	 * Report ourselves
39513691Sgibbs	 */
39645791Speter	printf(LPT_NAME "%d: <generic printer> on ppbus %d\n",
39745791Speter	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
39845791Speter
39945791Speter	sc->sc_primed = 0;	/* not primed yet */
40045791Speter
40145791Speter	if ((error = lpt_request_ppbus(sc, PPB_DONTWAIT))) {
40245791Speter		printf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error);
40345791Speter		return (0);
40445791Speter	}
40545791Speter
40645791Speter	ppb_wctr(&sc->lpt_dev, LPC_NINIT);
40745791Speter
40845791Speter	/* check if we can use interrupt, should be done by ppc stuff */
40945791Speter	lprintf(("oldirq %x\n", sc->sc_irq));
41045791Speter	if (ppb_get_irq(&sc->lpt_dev)) {
41145791Speter		sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
41245791Speter		printf(LPT_NAME "%d: Interrupt-driven port\n", dev->id_unit);
41345791Speter	} else {
41445791Speter		sc->sc_irq = 0;
41545791Speter		lprintf((LPT_NAME "%d: Polled port\n", dev->id_unit));
41649360Smdodd	}
41749360Smdodd	lprintf(("irq %x\n", sc->sc_irq));
41845791Speter
41949360Smdodd	lpt_release_ppbus(sc);
42045791Speter
42149360Smdodd#ifdef DEVFS
42249360Smdodd	sc->devfs_token = devfs_add_devswf(&lpt_cdevsw,
42349360Smdodd		dev->id_unit, DV_CHR,
42449360Smdodd		UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d", dev->id_unit);
42549360Smdodd	sc->devfs_token_ctl = devfs_add_devswf(&lpt_cdevsw,
42612157Sgibbs		dev->id_unit | LP_BYPASS, DV_CHR,
42745791Speter		UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d.ctl", dev->id_unit);
42845791Speter#endif
42945791Speter
43045791Speter	return (1);
43145791Speter}
43245791Speter
43345791Speterstatic void
43445791Speterlptout(void *arg)
43545791Speter{
43645791Speter	struct lpt_data *sc = arg;
43745791Speter	int pl;
43847451Speter
43945791Speter	lprintf(("T %x ", ppb_rstr(&sc->lpt_dev)));
44045791Speter	if (sc->sc_state & OPEN) {
44112157Sgibbs		sc->sc_backoff++;
44245791Speter		if (sc->sc_backoff > hz/LPTOUTMAX)
44345791Speter			sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
44445791Speter		timeout(lptout, (caddr_t)sc, sc->sc_backoff);
44545791Speter	} else
44645791Speter		sc->sc_state &= ~TOUT;
44745791Speter
44845791Speter	if (sc->sc_state & EERROR)
44945791Speter		sc->sc_state &= ~EERROR;
45045791Speter
45145791Speter	/*
45245791Speter	 * Avoid possible hangs do to missed interrupts
45347451Speter	 */
45445791Speter	if (sc->sc_xfercnt) {
45545791Speter		pl = spltty();
45645791Speter		lpt_intr(sc->lpt_unit);
45745791Speter		splx(pl);
45845791Speter	} else {
45945791Speter		sc->sc_state &= ~OBUSY;
46045791Speter		wakeup((caddr_t)sc);
4618012Sjulian	}
46245791Speter}
46345791Speter
46445791Speter/*
46545791Speter * lptopen -- reset the printer, then wait until it's selected and not busy.
46645791Speter *	If LP_BYPASS flag is selected, then we do not try to select the
46745791Speter *	printer -- this is just used for passing ioctls.
46845791Speter */
46912090Sgibbs
4708012Sjulianstatic	int
47145791Speterlptopen(dev_t dev, int flags, int fmt, struct proc *p)
47245791Speter{
47345791Speter	struct lpt_data *sc;
47412090Sgibbs
47545791Speter	int s;
47645791Speter	int trys, err;
47745791Speter	u_int unit = LPTUNIT(minor(dev));
47812090Sgibbs
47945791Speter	if ((unit >= nlpt))
48045791Speter		return (ENXIO);
48149360Smdodd
48245791Speter	sc = lptdata[unit];
48345791Speter
48445791Speter	if (sc->sc_state) {
48545791Speter		lprintf((LPT_NAME ": still open %x\n", sc->sc_state));
48645791Speter		return(EBUSY);
48745791Speter	} else
48845791Speter		sc->sc_state |= LPTINIT;
48945791Speter
49045791Speter	sc->sc_flags = LPTFLAGS(minor(dev));
49145791Speter
49245791Speter	/* Check for open with BYPASS flag set. */
49345791Speter	if (sc->sc_flags & LP_BYPASS) {
49445791Speter		sc->sc_state = OPEN;
49545791Speter		return(0);
49645791Speter	}
49745791Speter
49812157Sgibbs	/* request the ppbus only if we don't have it already */
49912090Sgibbs	if ((err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)) != 0)
50045791Speter		return (err);
50145791Speter
50245791Speter	s = spltty();
50345791Speter	lprintf((LPT_NAME " flags 0x%x\n", sc->sc_flags));
50445791Speter
5058012Sjulian	/* set IRQ status according to ENABLE_IRQ flag */
50645791Speter	if (sc->sc_irq & LP_ENABLE_IRQ)
50745791Speter		sc->sc_irq |= LP_USE_IRQ;
50812090Sgibbs	else
5098012Sjulian		sc->sc_irq &= ~LP_USE_IRQ;
51012090Sgibbs
51149360Smdodd	/* init printer */
51212090Sgibbs	if ((sc->sc_flags & LP_NO_PRIME) == 0) {
51345791Speter		if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
51449360Smdodd			ppb_wctr(&sc->lpt_dev, 0);
51529674Sgibbs			sc->sc_primed++;
51629674Sgibbs			DELAY(500);
51729674Sgibbs		}
51829674Sgibbs	}
51929674Sgibbs
52029674Sgibbs	ppb_wctr(&sc->lpt_dev, LPC_SEL|LPC_NINIT);
52129674Sgibbs
52249360Smdodd	/* wait till ready (printer running diagnostics) */
52329674Sgibbs	trys = 0;
52429674Sgibbs	do {
52512157Sgibbs		/* ran out of waiting for the printer */
52612090Sgibbs		if (trys++ >= LPINITRDY*4) {
52712090Sgibbs			splx(s);
52813691Sgibbs			sc->sc_state = 0;
52946601Speter			lprintf(("status %x\n", ppb_rstr(&sc->lpt_dev)));
53046601Speter
53113691Sgibbs			lpt_release_ppbus(sc);
53213691Sgibbs			return (EBUSY);
53313691Sgibbs		}
53413691Sgibbs
53513691Sgibbs		/* wait 1/4 second, give up if we get a signal */
53613691Sgibbs		if (tsleep((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) !=
53713691Sgibbs		    EWOULDBLOCK) {
53813691Sgibbs			sc->sc_state = 0;
53913691Sgibbs			splx(s);
54013691Sgibbs
54113691Sgibbs			lpt_release_ppbus(sc);
54213691Sgibbs			return (EBUSY);
54313691Sgibbs		}
54413691Sgibbs
54513691Sgibbs		/* is printer online and ready for output */
54613691Sgibbs	} while ((ppb_rstr(&sc->lpt_dev) &
54713691Sgibbs			(LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
54813691Sgibbs					(LPS_SEL|LPS_NBSY|LPS_NERR));
54913691Sgibbs
55013691Sgibbs	sc->sc_control = LPC_SEL|LPC_NINIT;
55113691Sgibbs	if (sc->sc_flags & LP_AUTOLF)
55213691Sgibbs		sc->sc_control |= LPC_AUTOL;
55313691Sgibbs
55413691Sgibbs	/* enable interrupt if interrupt-driven */
55513691Sgibbs	if (sc->sc_irq & LP_USE_IRQ)
55613691Sgibbs		sc->sc_control |= LPC_ENA;
55713691Sgibbs
55813691Sgibbs	ppb_wctr(&sc->lpt_dev, sc->sc_control);
55913691Sgibbs
56013691Sgibbs	sc->sc_state = OPEN;
56113691Sgibbs	sc->sc_inbuf = geteblk(BUFSIZE);
56213691Sgibbs	sc->sc_statbuf = geteblk(BUFSTATSIZE);
56313691Sgibbs	sc->sc_xfercnt = 0;
56413691Sgibbs	splx(s);
56513691Sgibbs
56613691Sgibbs	/* release the ppbus */
56713691Sgibbs	lpt_release_ppbus(sc);
56813691Sgibbs
56913691Sgibbs	/* only use timeout if using interrupt */
57013691Sgibbs	lprintf(("irq %x\n", sc->sc_irq));
57113691Sgibbs	if (sc->sc_irq & LP_USE_IRQ) {
57213691Sgibbs		sc->sc_state |= TOUT;
57313691Sgibbs		timeout(lptout, (caddr_t)sc,
57413691Sgibbs			 (sc->sc_backoff = hz/LPTOUTINITIAL));
57513691Sgibbs	}
57613691Sgibbs
57712090Sgibbs	lprintf(("opened.\n"));
57846601Speter	return(0);
57912090Sgibbs}
58045791Speter
58146601Speter/*
58213804Sgibbs * lptclose -- close the device, free the local line buffer.
58313804Sgibbs *
58412090Sgibbs * Check for interrupted write call added.
58512090Sgibbs */
58612090Sgibbs
58746601Speterstatic	int
58812090Sgibbslptclose(dev_t dev, int flags, int fmt, struct proc *p)
58945791Speter{
59046601Speter	struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))];
59113804Sgibbs	int err;
59213804Sgibbs
59313691Sgibbs	if(sc->sc_flags & LP_BYPASS)
59413691Sgibbs		goto end_close;
59545791Speter
59645791Speter	if ((err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)) != 0)
59745791Speter		return (err);
59845791Speter
59945791Speter	sc->sc_state &= ~OPEN;
60048100Speter
60148100Speter	/* if the last write was interrupted, don't complete it */
60245791Speter	if((!(sc->sc_state  & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ))
60345791Speter		while ((ppb_rstr(&sc->lpt_dev) &
60445791Speter			(LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
60548754Sdfr			(LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
60645791Speter			/* wait 1/4 second, give up if we get a signal */
60745791Speter			if (tsleep((caddr_t)sc, LPPRI|PCATCH,
60845791Speter				"lpclose", hz) != EWOULDBLOCK)
60945791Speter				break;
61045791Speter
61145791Speter	ppb_wctr(&sc->lpt_dev, LPC_NINIT);
61245791Speter	brelse(sc->sc_inbuf);
61345791Speter	brelse(sc->sc_statbuf);
61445791Speter
61545791Speterend_close:
61645791Speter	/* release the bus anyway */
61745791Speter	lpt_release_ppbus(sc);
61845791Speter
61945791Speter	sc->sc_state = 0;
62045791Speter	sc->sc_xfercnt = 0;
62145791Speter	lprintf(("closed.\n"));
62245791Speter	return(0);
62345791Speter}
62445791Speter
62545791Speter/*
62645807Speter * lpt_pushbytes()
627 *	Workhorse for actually spinning and writing bytes to printer
628 *	Derived from lpa.c
629 *	Originally by ?
630 *
631 *	This code is only used when we are polling the port
632 */
633static int
634lpt_pushbytes(struct lpt_data *sc)
635{
636	int spin, err, tic;
637	char ch;
638
639	lprintf(("p"));
640	/* loop for every character .. */
641	while (sc->sc_xfercnt > 0) {
642		/* printer data */
643		ch = *(sc->sc_cp);
644		sc->sc_cp++;
645		sc->sc_xfercnt--;
646
647		/*
648		 * Wait for printer ready.
649		 * Loop 20 usecs testing BUSY bit, then sleep
650		 * for exponentially increasing timeout. (vak)
651		 */
652		for (spin = 0; NOT_READY(sc) && spin < MAX_SPIN; ++spin)
653			DELAY(1);	/* XXX delay is NOT this accurate! */
654		if (spin >= MAX_SPIN) {
655			tic = 0;
656			while (NOT_READY(sc)) {
657				/*
658				 * Now sleep, every cycle a
659				 * little longer ..
660				 */
661				tic = tic + tic + 1;
662				/*
663				 * But no more than 10 seconds. (vak)
664				 */
665				if (tic > MAX_SLEEP)
666					tic = MAX_SLEEP;
667				err = tsleep((caddr_t)sc, LPPRI,
668					LPT_NAME "poll", tic);
669				if (err != EWOULDBLOCK) {
670					return (err);
671				}
672			}
673		}
674
675		/* output data */
676		ppb_wdtr(&sc->lpt_dev, ch);
677		/* strobe */
678		ppb_wctr(&sc->lpt_dev, sc->sc_control|LPC_STB);
679		ppb_wctr(&sc->lpt_dev, sc->sc_control);
680
681	}
682	return(0);
683}
684
685/*
686 * lptread --retrieve printer status in IEEE1284 NIBBLE mode
687 */
688
689static int
690lptread(dev_t dev, struct uio *uio, int ioflag)
691{
692	struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))];
693	int error = 0, len;
694
695	if ((error = ppb_1284_negociate(&sc->lpt_dev, PPB_NIBBLE, 0)))
696		return (error);
697
698	/* read data in an other buffer, read/write may be simultaneous */
699	len = 0;
700	while (uio->uio_resid) {
701		if ((error = ppb_1284_read(&sc->lpt_dev, PPB_NIBBLE,
702				sc->sc_statbuf->b_data, min(BUFSTATSIZE,
703				uio->uio_resid), &len))) {
704			goto error;
705		}
706
707		if (!len)
708			goto error;		/* no more data */
709
710		if ((error = uiomove(sc->sc_statbuf->b_data, len, uio)))
711			goto error;
712	}
713
714error:
715	ppb_1284_terminate(&sc->lpt_dev);
716	return (error);
717}
718
719/*
720 * lptwrite --copy a line from user space to a local buffer, then call
721 * putc to get the chars moved to the output queue.
722 *
723 * Flagging of interrupted write added.
724 */
725
726static	int
727lptwrite(dev_t dev, struct uio *uio, int ioflag)
728{
729	register unsigned n;
730	int pl, err;
731        u_int	unit = LPTUNIT(minor(dev));
732	struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))];
733
734	if(sc->sc_flags & LP_BYPASS) {
735		/* we can't do writes in bypass mode */
736		return(EPERM);
737	}
738
739	/* request the ppbus only if we don't have it already */
740	if ((err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)) != 0)
741		return (err);
742
743	sc->sc_state &= ~INTERRUPTED;
744	while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
745		sc->sc_cp = sc->sc_inbuf->b_data ;
746		uiomove(sc->sc_cp, n, uio);
747		sc->sc_xfercnt = n ;
748
749		if (sc->sc_irq & LP_ENABLE_EXT) {
750			/* try any extended mode */
751			err = ppb_write(&sc->lpt_dev, sc->sc_cp,
752							sc->sc_xfercnt, 0);
753			switch (err) {
754			case 0:
755				/* if not all data was sent, we could rely
756				 * on polling for the last bytes */
757				sc->sc_xfercnt = 0;
758				break;
759			case EINTR:
760				sc->sc_state |= INTERRUPTED;
761				return(err);
762			case EINVAL:
763				/* advanced mode not avail */
764				log(LOG_NOTICE, LPT_NAME "%d: advanced mode not avail, polling\n", unit);
765				break;
766			default:
767				return(err);
768			}
769		} else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
770			lprintf(("i"));
771			/* if the printer is ready for a char, */
772			/* give it one */
773			if ((sc->sc_state & OBUSY) == 0){
774				lprintf(("\nC %d. ", sc->sc_xfercnt));
775				pl = spltty();
776				lpt_intr(sc->lpt_unit);
777				(void) splx(pl);
778			}
779			lprintf(("W "));
780			if (sc->sc_state & OBUSY)
781				if ((err = tsleep((caddr_t)sc,
782					 LPPRI|PCATCH, LPT_NAME "write", 0))) {
783					sc->sc_state |= INTERRUPTED;
784					return(err);
785				}
786		}
787
788		/* check to see if we must do a polled write */
789		if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
790			lprintf(("p"));
791
792			err = lpt_pushbytes(sc);
793
794			if (err)
795				return(err);
796		}
797	}
798
799	/* we have not been interrupted, release the ppbus */
800	lpt_release_ppbus(sc);
801
802	return(0);
803}
804
805/*
806 * lpt_intr -- handle printer interrupts which occur when the printer is
807 * ready to accept another char.
808 *
809 * do checking for interrupted write call.
810 */
811
812static void
813lpt_intr(int unit)
814{
815	struct lpt_data *sc = lptdata[unit];
816	int sts;
817	int i;
818
819	/* we must own the bus to use it */
820	if ((sc->sc_state & HAVEBUS) == 0)
821		return;
822
823	/*
824	 * Is printer online and ready for output?
825	 *
826	 * Avoid falling back to lptout() too quickly.  First spin-loop
827	 * to see if the printer will become ready ``really soon now''.
828	 */
829	for (i = 0; i < 100 &&
830	     ((sts=ppb_rstr(&sc->lpt_dev)) & RDY_MASK) != LP_READY; i++) ;
831
832	if ((sts & RDY_MASK) == LP_READY) {
833		sc->sc_state = (sc->sc_state | OBUSY) & ~EERROR;
834		sc->sc_backoff = hz/LPTOUTINITIAL;
835
836		if (sc->sc_xfercnt) {
837			/* send char */
838			/*lprintf(("%x ", *sc->sc_cp)); */
839			ppb_wdtr(&sc->lpt_dev, *sc->sc_cp++) ;
840			ppb_wctr(&sc->lpt_dev, sc->sc_control|LPC_STB);
841			/* DELAY(X) */
842			ppb_wctr(&sc->lpt_dev, sc->sc_control);
843
844			/* any more data for printer */
845			if(--(sc->sc_xfercnt) > 0) return;
846		}
847
848		/*
849		 * No more data waiting for printer.
850		 * Wakeup is not done if write call was interrupted.
851		 */
852		sc->sc_state &= ~OBUSY;
853
854		if(!(sc->sc_state & INTERRUPTED))
855			wakeup((caddr_t)sc);
856		lprintf(("w "));
857		return;
858	} else	{	/* check for error */
859		if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
860				(sc->sc_state & OPEN))
861			sc->sc_state |= EERROR;
862		/* lptout() will jump in and try to restart. */
863	}
864	lprintf(("sts %x ", sts));
865}
866
867static void
868lptintr(int unit)
869{
870	/* call the interrupt at required spl level */
871	int s = spltty();
872
873	lpt_intr(unit);
874
875	splx(s);
876	return;
877}
878
879static	int
880lptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
881{
882	int	error = 0;
883        struct	lpt_data *sc;
884        u_int	unit = LPTUNIT(minor(dev));
885	u_char	old_sc_irq;	/* old printer IRQ status */
886
887        sc = lptdata[unit];
888
889	switch (cmd) {
890	case LPT_IRQ :
891		if(sc->sc_irq & LP_HAS_IRQ) {
892			/*
893			 * NOTE:
894			 * If the IRQ status is changed,
895			 * this will only be visible on the
896			 * next open.
897			 *
898			 * If interrupt status changes,
899			 * this gets syslog'd.
900			 */
901			old_sc_irq = sc->sc_irq;
902			switch(*(int*)data) {
903			case 0:
904				sc->sc_irq &= (~LP_ENABLE_IRQ);
905				break;
906			case 1:
907				sc->sc_irq &= (~LP_ENABLE_EXT);
908				sc->sc_irq |= LP_ENABLE_IRQ;
909				break;
910			case 2:
911				/* classic irq based transfer and advanced
912				 * modes are in conflict
913				 */
914				sc->sc_irq &= (~LP_ENABLE_IRQ);
915				sc->sc_irq |= LP_ENABLE_EXT;
916				break;
917			case 3:
918				sc->sc_irq &= (~LP_ENABLE_EXT);
919				break;
920			default:
921				break;
922			}
923
924			if (old_sc_irq != sc->sc_irq )
925				log(LOG_NOTICE, LPT_NAME "%d: switched to %s %s mode\n",
926					unit,
927					(sc->sc_irq & LP_ENABLE_IRQ)?
928					"interrupt-driven":"polled",
929					(sc->sc_irq & LP_ENABLE_EXT)?
930					"extended":"standard");
931		} else /* polled port */
932			error = EOPNOTSUPP;
933		break;
934	default:
935		error = ENODEV;
936	}
937
938	return(error);
939}
940
941static int lpt_devsw_installed;
942
943static void
944lpt_drvinit(void *unused)
945{
946	dev_t dev;
947
948	if( ! lpt_devsw_installed ) {
949		dev = makedev(CDEV_MAJOR, 0);
950		cdevsw_add(&dev,&lpt_cdevsw, NULL);
951		lpt_devsw_installed = 1;
952    	}
953}
954
955SYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL)
956