home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!sun-barr!ames!data.nas.nasa.gov!taligent!apple!motcsd!xhost92.csd.mot.com!ajv
- From: ajv@xhost92.csd.mot.com
- Newsgroups: comp.unix.bsd
- Subject: Re: replacement for lpt.c without interrupts
- Message-ID: <7070@motcsd.csd.mot.com>
- Date: 9 Sep 92 06:00:18 GMT
- References: <1992Aug11.201127.1600@jbsys.com>,<PCG.92Aug6161828@aberdb.aber.ac.uk> <1992Sep6.143703.5848@dentaro.GUN.de>
- Sender: usenet@motcsd.csd.mot.com
- Lines: 389
-
- wolf@dentaro.GUN.de (Wolfgang Stanglmeier) writes:
-
- >I hacked the 386bsd LPT-driver to work without interrupts.
- >The busy loop timeout value adapts automatically to
- >the printer and system speed.
-
- <excellent driver follows...>
-
- I was working on something very much along the same lines. However,
- Mr. Stanglmeier hit the nail right on the head first. I have rolled
- in some of my other work on handling syscall restarts, and in the
- process applied my BSD-kernel style of indentation. What follows is
- substantially the same driver, with my own minor improvements.
-
- Kudos, Mr. Stanglmeier! My printer thanks you. :-)
-
- Andy Valencia
- ajv@csd.mot.com (for now)
- jtk@netcom.com (if it bounces)
-
- /*
- * Copyright (c) 1990 William F. Jolitz, TeleMuse
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This software is a component of "386BSD" developed by
- * William F. Jolitz, TeleMuse.
- * 4. Neither the name of the developer nor the name "386BSD"
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
- * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
- * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
- * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
- * NOT MAKE USE OF THIS WORK.
- *
- * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
- * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
- * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
- * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
- * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
- * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
- * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
- * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
- /*
- * Device Driver for AT parallel printer port
- * Written by William Jolitz 12/18/90
- * Modified to run without interrupts
- * 92-08-19 Wolfgang Stanglmeier <wolf@dentaro.GUN.de>
- * Slight cleanup and reorganization, try to handle restarted syscalls
- * 92-09-08 Andy Valencia <jtk@netcom.com>
- */
-
- #include "lpt.h"
- #if NLPT > 0
-
- #include "param.h"
- #include "buf.h"
- #include "systm.h"
- #include "ioctl.h"
- #include "tty.h"
- #include "proc.h"
- #include "user.h"
- #include "uio.h"
- #include "kernel.h"
- #include "malloc.h"
-
- #include "i386/isa/isa_device.h"
- #include "i386/isa/lptreg.h"
-
- /* internal used flags */
- #define OPEN (0x01) /* device is open */
- #define INIT (0x02) /* device in open procedure */
-
- /* flags from minor device */
- #define LPT_PRIME (0x20) /* prime printer on open */
- #define LPT_ERROR (0x10) /* log error conditions */
-
- #define LPT_FLAG(x) ((x) & 0xfc)
- #define LPT_UNIT(x) ((x) & 0x03)
-
- /* Printer Ready condition */
- #define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR)
- #define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
- #define NOT_READY() ((inb(sc->sc_stat)^LPS_INVERT)&LPS_MASK)
-
- /* tsleep priority */
- #define LPPRI ((PZERO+8) | PCATCH)
-
- int lptprobe(), lptattach();
- struct isa_driver lptdriver = {lptprobe, lptattach, "lpt"};
-
- /*
- * copy usermode data into sysmode buffer
- */
- #define BUFSIZE 1024
-
- /*
- ** Waittimes
- */
- #define TIMEOUT (hz*16) /* Timeout while open device */
- #define LONG (hz* 1) /* Timesteps while open */
-
- #define MAX_SPIN 255 /* max loop counter for busy wait */
-
- /* Valid Controlbits for probe ...
- **
- ** The lower 5 bits of controlport should be
- ** readable and writable,
- **
- ** .... but if my deskjet is power down, it clobbers
- ** some lines, and the port will not be configured.
- ** So I mask them out
- */
- #define LPC_MASK (0xfa)
-
- struct lpt_softc {
- char *sc_cp; /* current data to print */
- int sc_count; /* bytes queued in sc_inbuf */
- short sc_data; /* printer data port */
- short sc_stat; /* printer control port */
- short sc_ctrl; /* printer status port */
- u_char sc_flags; /* flags (open and internal) */
- u_char sc_unit; /* unit-number */
- u_char sc_smax; /* current max busy loop cnt */
- char /* buffer for data */
- *sc_inbuf;
- } lpt_sc[NLPT];
-
- /* In fact, I need no interrupt, but how can I explain it to config ??? */
- lptintr(unit)
- int unit;
- {
- /* dummy */ ;
- }
-
- /*
- * lptprobe()
- * Probe for hardware
- */
- lptprobe(idp)
- struct isa_device *idp;
- {
- unsigned v, w, n = 0;
-
- /* status */
- do {
- if (++n >= 4)
- return (0);
-
- /*
- * Status port should be read only,
- * so readback value may not change
- */
- outb(idp->id_iobase+lpt_status,0xf0);
- v = inb(idp->id_iobase+lpt_status);
- outb(idp->id_iobase+lpt_status,0);
- w = inb(idp->id_iobase+lpt_status);
- } while (v != w);
-
- /* control: the lower 5 bits of controlport should read back */
- outb(idp->id_iobase+lpt_control,0xff);
- DELAY(100);
-
- w = inb(idp->id_iobase+lpt_control);
- if ((w ^ 0xff) & LPC_MASK) return(0);
-
- outb(idp->id_iobase+lpt_control,0);
- DELAY(100);
- w = inb(idp->id_iobase+lpt_control);
- if ((w ^ 0xe0) & LPC_MASK)
- return(0);
- return(1);
- }
-
- /*
- * lptattach()
- * Install device
- */
- lptattach(isdp)
- struct isa_device *isdp;
- {
- struct lpt_softc *sc;
-
- sc = lpt_sc + isdp->id_unit;
- sc->sc_unit = isdp->id_unit;
- sc->sc_data = isdp->id_iobase + lpt_data;
- sc->sc_stat = isdp->id_iobase + lpt_status;
- sc->sc_ctrl = isdp->id_iobase + lpt_control;
- outb(sc->sc_ctrl, LPC_NINIT);
- return (1);
- }
-
- /*
- * lptopen()
- * New open on device.
- *
- * We forbid all but first open
- */
- lptopen(dev, flag)
- dev_t dev;
- int flag;
- {
- struct lpt_softc *sc;
- int delay; /* slept time in 1/hz seconds of tsleep */
- int err;
- u_char sta, unit;
-
- unit= LPT_UNIT(minor(dev));
- sta = LPT_FLAG(minor(dev));
-
- /* minor number out of limits ? */
- if (unit >= NLPT)
- return (ENXIO);
- sc = lpt_sc + unit;
-
- /* Attached ? */
- if (!sc->sc_ctrl) { /* not attached */
- return(ENXIO);
- }
-
- /* Printer busy ? */
- if (sc->sc_flags) { /* too late .. */
- return(EBUSY);
- }
-
- /* Have memory for buffer? */
- sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
- if (sc->sc_inbuf == 0)
- return(ENOMEM);
-
- /* Init printer */
- sc->sc_flags = sta | INIT;
- if (sc->sc_flags & LPT_PRIME) {
- outb(sc->sc_ctrl, 0);
- }
-
- /* Select printer */
- outb(sc->sc_ctrl, LPC_SEL|LPC_NINIT);
-
- /* and wait for ready .. */
- for (delay=0; NOT_READY(); delay+= LONG) {
- if (delay >= TIMEOUT) { /* too long waited .. */
- sc->sc_flags = 0;
- return (EBUSY);
- }
-
- /* sleep a moment */
- if ((err = tsleep (sc, LPPRI, "lpt: open", LONG)) !=
- EWOULDBLOCK) {
- sc->sc_flags = 0;
- return (EBUSY);
- }
- }
-
- /* Printer ready .. set variables */
- sc->sc_flags |= OPEN;
- sc->sc_count = 0;
-
- return(0);
- }
-
- /*
- * pushbytes()
- * Workhorse for actually spinning and writing bytes to printer
- */
- static
- pushbytes(sc)
- struct lpt_softc *sc;
- {
- int spin, err, tic;
- char ch;
-
- /* loop for every character .. */
- while (sc->sc_count > 0) {
- /* printer data */
- ch = *(sc->sc_cp);
- sc->sc_cp += 1;
- sc->sc_count -= 1;
- outb(sc->sc_data, ch);
-
- /* Busy wait for printer ready .. */
- spin = tic = 0;
- while (NOT_READY()) {
- if (++spin >= sc->sc_smax) {
- /*
- * Now sleep, every cycle a
- * little longer ..
- */
- tic = tic + tic + 1;
- err = tsleep(sc, LPPRI, "lpt: write", tic);
- if (err != EWOULDBLOCK) {
- return (err);
- }
- }
- }
-
- /* strobe */
- outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL|LPC_STB);
- outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL);
-
- /* Adapt busy-wait length... */
- if (spin >= sc->sc_smax) { /* was sleep wait */
- if (sc->sc_smax<MAX_SPIN)
- sc->sc_smax++;
- }
- if (spin*2 < sc->sc_smax) {
- sc->sc_smax--;
- }
- }
- return(0);
- }
-
- /*
- * lptclose()
- * Close on lp. Try to flush data in buffer out.
- */
- lptclose(dev, flag)
- dev_t dev;
- int flag;
- {
- struct lpt_softc *sc = lpt_sc + LPT_UNIT(minor(dev));
-
- /* If there's queued data, try to flush it */
- (void)pushbytes(sc);
-
- /* really close .. quite simple :-) */
- outb(sc->sc_ctrl, LPC_NINIT);
- sc->sc_flags = 0;
- free(sc->sc_inbuf, M_DEVBUF);
- sc->sc_inbuf = 0; /* Sanity */
- return(0);
- }
-
- /*
- * lptwrite()
- * Copy from user's buffer, then print
- */
- lptwrite(dev, uio)
- dev_t dev;
- struct uio *uio;
- {
- struct lpt_softc *sc = lpt_sc + LPT_UNIT(minor(dev));
- int err;
-
- /* Write out old bytes from interrupted syscall */
- if (sc->sc_count > 0) {
- err = pushbytes(sc);
- if (err)
- return(err);
- }
-
- /* main loop */
- while ((sc->sc_count = MIN(BUFSIZE, uio->uio_resid)) > 0) {
- /* get from user-space */
- sc->sc_cp = sc->sc_inbuf;
- uiomove(sc->sc_inbuf, sc->sc_count, uio);
- err = pushbytes(sc);
- if (err)
- return(err);
- }
- return(0);
- }
- #endif /* NLP > 0 */
-