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