Return to BSD News archive
Received: by minnie.vk1xwt.ampr.org with NNTP id AA489 ; Wed, 03 Feb 93 19:01:16 EST Path: sserve!manuel.anu.edu.au!munnari.oz.au!sgiblab!spool.mu.edu!olivea!decwrl!csus.edu!netcom.com!alm From: alm@netcom.com (Andrew Moore) Newsgroups: comp.unix.bsd Subject: [386BSD] Unofficial interruptless printer driver kit Keywords: interruptless lpt printer driver Message-ID: <1993Feb2.221148.102@netcom.com> Date: 2 Feb 93 22:11:48 GMT Organization: Netcom - Online Communication Services (408 241-9760 guest) Lines: 671 If I get no complaints about the following collection of lpt patches and notes, then I will try to post it to agate.berkeley.edu and to ref.tfs.com as interruptless-lpt-kit.shar. -Andrew Moore <alm@netcom.com> #!/bin/sh # This is a shell archive (produced by shar 3.49) # To extract the files from this archive, save it to a file, remove # everything above the "!/bin/sh" line above, and type "sh file_name". # # made 02/02/1993 21:19 UTC by alm@netcom2 # Source directory /u13/alm/tmp # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 2509 -rw-r--r-- LPT-INSTALL-NOTES # 10070 -rw-r--r-- interruptless-lpt.c # 1593 -rw-r--r-- sample.conf.c.patch # 2324 -rw-r--r-- sample.lpt.filters # # ============= LPT-INSTALL-NOTES ============== if test -f 'LPT-INSTALL-NOTES' -a X"$1" != X"-c"; then echo 'x - skipping LPT-INSTALL-NOTES (File already exists)' else echo 'x - extracting LPT-INSTALL-NOTES (Text)' sed 's/^X//' << 'SHAR_EOF' > 'LPT-INSTALL-NOTES' && UNOFFICIAL INTERRUPTLESS LPT DRIVER KIT X CONTENTS X -Disclaimer [please read] -Steps for installing the driver -Sample conf.c patch [from Eric Haug's patches to the original lpt driver] -The interruptless lpt driver [by Wolfgang Stanglemeier with contributions X from Andy Valencia] -Sample filters and printcap entries for laser printers [by Reinier Kleipool] X DISCLAIMER X Following a suggestion by Chris Flatters, some troublesome code in the lptprobe() routine of the lpt driver is commented out. This allows the printer to be recognized on boot if it is not powered on. If your printer seems to misbehave, try removing the comments... X It is not certain whether the interruptless lpt driver will supercede Bill Jolitz's original driver (and Eric Haug's patches to it) in future releases of 386BSD. In the mean time, the interruptless driver seems to be necessary for printing binary data. As for performance, it is claimed that the interruptless driver is faster than the original, despite conventional wisdom which says that interrupt driven devices are faster. In addition, the interruptless driver seems to create less of a system load. X All the usual warnings and disclaimers. X STEPS FOR INSTALLING THE INTERRUPTLESS LPT DRIVER X 1) In the file /sys/i386/conf/YOUR_SYSTEM_NAME, add the line: X device lpt1 at isa? port "IO_LPT1" tty irq 7 vector lptintr X 2) In the file /sys/i386/conf/files.i386, add the line: X i386/isa/lpt.c optional lpt device-driver X 3) Modify the file /sys/i386/i386/conf.c following the sample patch X (see the file sample.conf.c.patch). The position of entries in the X cdevsw[] structure determine the device major number of the /dev X device file. The sample patch installs the lpt entries for device file X /dev/lpt major number 15. X 4) Create character lpt device files with the commands: X X $ mknod /dev/lpt0 c 15 48 X $ mknod /dev/lpt1 c 15 49 X $ mknod /dev/lpt2 c 15 50 X $ ln /dev/lpt1 /dev/lp X X where the major number (15) is determined by step (3) and minor numbers X (48, 49, 50) as per the lpt.c instructions (see the file X interruptless-lpt.c). X 5) In the file /etc/hosts.lpd file, for each machine with printer X access, add a line of the form: X machine_name.domain X 6) Replace /sys/i386/isa/lpt.c with the interruptless printer driver X (see the file interruptless-lpt.c). X 7) Recompile the kernel. X 8) If you have a laser printer, see the notes in the file X sample.lpt.filters about adding filters and configuring /etc/printcap. -Andrew Moore <alm@netcom.com> SHAR_EOF chmod 0644 LPT-INSTALL-NOTES || echo 'restore of LPT-INSTALL-NOTES failed' Wc_c="`wc -c < 'LPT-INSTALL-NOTES'`" test 2509 -eq "$Wc_c" || echo 'LPT-INSTALL-NOTES: original size 2509, current size' "$Wc_c" fi # ============= interruptless-lpt.c ============== if test -f 'interruptless-lpt.c' -a X"$1" != X"-c"; then echo 'x - skipping interruptless-lpt.c (File already exists)' else echo 'x - extracting interruptless-lpt.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'interruptless-lpt.c' && The following is a complete lpt.c replacement. X The driver supports up to 4 printers. The minor number is interpreted as follows: X X D D P E - - # # X DD: Debug, 00: no X 01: statistical data when closing device X 10: statistical data for every write call X 11: lots of silly data X P: Prime on open. X E: Errormessage. X Logs "no paper", "offline", "printer error" conditions X to the console. X ##: Device, 0: lpt0 X 1: lpt1 X 2: lpt2 (on display adapter) X This driver uses the ideas of Piercarlo Grandis polling printer driver. X ---- Cut Here ---- begin of /sys/i386/isa/lpt.c replacement ---- /* X * Copyright (c) 1990 William F. Jolitz, TeleMuse X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This software is a component of "386BSD" developed by X * William F. Jolitz, TeleMuse. X * 4. Neither the name of the developer nor the name "386BSD" X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ X * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS X * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. X * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT X * NOT MAKE USE OF THIS WORK. X * X * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED X * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN X * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES X * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING X * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND X * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE X * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS X * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. X * X * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X */ X /* X * Device Driver for AT parallel printer port X * Written by William Jolitz 12/18/90 X * Modified to run without interrupts X * 92-08-19 Wolfgang Stanglmeier <wolf@dentaro.GUN.de> X * Slight cleanup and reorganization, try to handle restarted syscalls X * 92-09-08 Andy Valencia <jtk@netcom.com> X */ X #include "lpt.h" #if NLPT > 0 X #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" X #include "i386/isa/isa_device.h" #include "i386/isa/lptreg.h" X /* internal used flags */ #define OPEN (0x01) /* device is open */ #define INIT (0x02) /* device in open procedure */ X /* flags from minor device */ #define LPT_PRIME (0x20) /* prime printer on open */ #define LPT_ERROR (0x10) /* log error conditions */ X #define LPT_FLAG(x) ((x) & 0xfc) #define LPT_UNIT(x) ((x) & 0x03) X /* 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) X /* tsleep priority */ #define LPPRI ((PZERO+8) | PCATCH) X int lptprobe(), lptattach(); struct isa_driver lptdriver = {lptprobe, lptattach, "lpt"}; X /* X * copy usermode data into sysmode buffer X */ #define BUFSIZE 1024 X /* ** Waittimes */ #define TIMEOUT (hz*16) /* Timeout while open device */ #define LONG (hz* 1) /* Timesteps while open */ X #define MAX_SPIN 255 /* max loop counter for busy wait */ X /* 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) X struct lpt_softc { X char *sc_cp; /* current data to print */ X int sc_count; /* bytes queued in sc_inbuf */ X short sc_data; /* printer data port */ X short sc_stat; /* printer control port */ X short sc_ctrl; /* printer status port */ X u_char sc_flags; /* flags (open and internal) */ X u_char sc_unit; /* unit-number */ X u_char sc_smax; /* current max busy loop cnt */ X char /* buffer for data */ X *sc_inbuf; } lpt_sc[NLPT]; X /* In fact, I need no interrupt, but how can I explain it to config ??? */ lptintr(unit) X int unit; { X /* dummy */ ; } X /* X * lptprobe() X * Probe for hardware X */ lptprobe(idp) X struct isa_device *idp; { X unsigned v, w, n = 0; X X /* status */ X do { X if (++n >= 4) X return (0); X X /* X * Status port should be read only, X * so readback value may not change X */ X outb(idp->id_iobase+lpt_status,0xf0); X v = inb(idp->id_iobase+lpt_status); X outb(idp->id_iobase+lpt_status,0); X w = inb(idp->id_iobase+lpt_status); X } while (v != w); X X /* control: the lower 5 bits of controlport should read back */ /* X outb(idp->id_iobase+lpt_control,0xff); X DELAY(100); X X w = inb(idp->id_iobase+lpt_control); X if ((w ^ 0xff) & LPC_MASK) return(0); X X outb(idp->id_iobase+lpt_control,0); X DELAY(100); X w = inb(idp->id_iobase+lpt_control); X if ((w ^ 0xe0) & LPC_MASK) X return(0); */ X return(1); } X /* X * lptattach() X * Install device X */ lptattach(isdp) X struct isa_device *isdp; { X struct lpt_softc *sc; X X sc = lpt_sc + isdp->id_unit; X sc->sc_unit = isdp->id_unit; X sc->sc_data = isdp->id_iobase + lpt_data; X sc->sc_stat = isdp->id_iobase + lpt_status; X sc->sc_ctrl = isdp->id_iobase + lpt_control; X outb(sc->sc_ctrl, LPC_NINIT); X return (1); } X /* X * lptopen() X * New open on device. X * X * We forbid all but first open X */ lptopen(dev, flag) X dev_t dev; X int flag; { X struct lpt_softc *sc; X int delay; /* slept time in 1/hz seconds of tsleep */ X int err; X u_char sta, unit; X X unit= LPT_UNIT(minor(dev)); X sta = LPT_FLAG(minor(dev)); X X /* minor number out of limits ? */ X if (unit >= NLPT) X return (ENXIO); X sc = lpt_sc + unit; X X /* Attached ? */ X if (!sc->sc_ctrl) { /* not attached */ X return(ENXIO); X } X X /* Printer busy ? */ X if (sc->sc_flags) { /* too late .. */ X return(EBUSY); X } X X /* Have memory for buffer? */ X sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); X if (sc->sc_inbuf == 0) X return(ENOMEM); X X /* Init printer */ X sc->sc_flags = sta | INIT; X if (sc->sc_flags & LPT_PRIME) { X outb(sc->sc_ctrl, 0); X } X X /* Select printer */ X outb(sc->sc_ctrl, LPC_SEL|LPC_NINIT); X X /* and wait for ready .. */ X for (delay=0; NOT_READY(); delay+= LONG) { X if (delay >= TIMEOUT) { /* too long waited .. */ X sc->sc_flags = 0; X return (EBUSY); X } X X /* sleep a moment */ X if ((err = tsleep (sc, LPPRI, "lpt: open", LONG)) != X EWOULDBLOCK) { X sc->sc_flags = 0; X return (EBUSY); X } X } X X /* Printer ready .. set variables */ X sc->sc_flags |= OPEN; X sc->sc_count = 0; X X return(0); } X /* X * pushbytes() X * Workhorse for actually spinning and writing bytes to printer X */ static pushbytes(sc) X struct lpt_softc *sc; { X int spin, err, tic; X char ch; X X /* loop for every character .. */ X while (sc->sc_count > 0) { X /* printer data */ X ch = *(sc->sc_cp); X sc->sc_cp += 1; X sc->sc_count -= 1; X outb(sc->sc_data, ch); X X /* Busy wait for printer ready .. */ X spin = tic = 0; X while (NOT_READY()) { X if (++spin >= sc->sc_smax) { X /* X * Now sleep, every cycle a X * little longer .. X */ X tic = tic + tic + 1; X err = tsleep(sc, LPPRI, "lpt: write", tic); X if (err != EWOULDBLOCK) { X return (err); X } X } X } X X /* strobe */ X outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL|LPC_STB); X outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL); X X /* Adapt busy-wait length... */ X if (spin >= sc->sc_smax) { /* was sleep wait */ X if (sc->sc_smax<MAX_SPIN) X sc->sc_smax++; X } X if (spin*2 < sc->sc_smax) { X sc->sc_smax--; X } X } X return(0); } X /* X * lptclose() X * Close on lp. Try to flush data in buffer out. X */ lptclose(dev, flag) X dev_t dev; X int flag; { X struct lpt_softc *sc = lpt_sc + LPT_UNIT(minor(dev)); X X /* If there's queued data, try to flush it */ X (void)pushbytes(sc); X X /* really close .. quite simple :-) */ X outb(sc->sc_ctrl, LPC_NINIT); X sc->sc_flags = 0; X free(sc->sc_inbuf, M_DEVBUF); X sc->sc_inbuf = 0; /* Sanity */ X return(0); } X /* X * lptwrite() X * Copy from user's buffer, then print X */ lptwrite(dev, uio) X dev_t dev; X struct uio *uio; { X struct lpt_softc *sc = lpt_sc + LPT_UNIT(minor(dev)); X int err; X X /* Write out old bytes from interrupted syscall */ X if (sc->sc_count > 0) { X err = pushbytes(sc); X if (err) X return(err); X } X X /* main loop */ X while ((sc->sc_count = MIN(BUFSIZE, uio->uio_resid)) > 0) { X /* get from user-space */ X sc->sc_cp = sc->sc_inbuf; X uiomove(sc->sc_inbuf, sc->sc_count, uio); X err = pushbytes(sc); X if (err) X return(err); X } X return(0); } #endif /* NLP > 0 */ ---- Cut Here ---- end of /sys/i386/isa/lpt.c replacement ---- X SHAR_EOF chmod 0644 interruptless-lpt.c || echo 'restore of interruptless-lpt.c failed' Wc_c="`wc -c < 'interruptless-lpt.c'`" test 10070 -eq "$Wc_c" || echo 'interruptless-lpt.c: original size 10070, current size' "$Wc_c" fi # ============= sample.conf.c.patch ============== if test -f 'sample.conf.c.patch' -a X"$1" != X"-c"; then echo 'x - skipping sample.conf.c.patch (File already exists)' else echo 'x - extracting sample.conf.c.patch (Text)' sed 's/^X//' << 'SHAR_EOF' > 'sample.conf.c.patch' && The following patch illustrates how to set up conf.c for lpt device major 15. X The definition of IO_LPT1 is in /sys/i386/isa/isa.h you may replace "IO_LPT1" with 0x378 or wherever your hardware is at. X The lpt port hardware is expected to be at 0x378 and jumpered to interrupt 7. NOTE: a monochrome adapter will use address 0x3BC and maybe interrupt 7. The maybe indicates that i know certain board do not handle interrupts properly (DOS does not use them). (the DOS idea of LPT1 is address 3BC). X This patch installs lpt as character major device 15 The conf.c file is in /sys/i386/i386/conf.c X ---- Cut Here ---- begin of conf.c patch ---- *** conf.c.distr Sat May 30 18:48:08 1992 --- conf.c Sat Jul 18 19:01:52 1992 *************** *** 165,170 **** --- 165,179 ---- X #define com_tty NULL X #endif X + #include "lpt.h" + #if NLPT > 0 + int lptopen(),lptclose(),lptwrite(),lptioctl(); + #else + #define lptopen enxio + #define lptclose enxio + #define lptwrite enxio + #endif + X int logopen(),logclose(),logread(),logioctl(),logselect(); X X int ttselect(), seltrue(); *************** *** 214,219 **** --- 223,234 ---- X { asopen, asclose, rawread, rawwrite, /*D*/ X asioctl, enodev, nullop, NULL, X seltrue, enodev, asstrategy }, + { enodev, enodev, enodev, enodev, /*E*/ + enodev, enodev, nullop, NULL, + seltrue, enodev, enodev }, + { lptopen, lptclose, nullop, lptwrite, /*F*/ + enodev, nullop, nullop, NULL, + seltrue, enodev, enodev }, X }; X int nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]); X ---- Cut Here ---- end of conf.c patch ---- X SHAR_EOF chmod 0644 sample.conf.c.patch || echo 'restore of sample.conf.c.patch failed' Wc_c="`wc -c < 'sample.conf.c.patch'`" test 1593 -eq "$Wc_c" || echo 'sample.conf.c.patch: original size 1593, current size' "$Wc_c" fi # ============= sample.lpt.filters ============== if test -f 'sample.lpt.filters' -a X"$1" != X"-c"; then echo 'x - skipping sample.lpt.filters (File already exists)' else echo 'x - extracting sample.lpt.filters (Text)' sed 's/^X//' << 'SHAR_EOF' > 'sample.lpt.filters' && Following illustrates how to setup /etc/printcap for laser printers. X >I successfully installed the lp patches, and the port is seen. >But when I print, the port or printer seem to just hang. The form feed >light on the laser comes on, but that is all. Nothing else happens. >lpc reports the status as printing, but thats it. If I cat directly to >/dev/lp ( set up as c 14 0) the same happens. > >Can anyone please help me ? X X ---------- X Yes! X X Probably the CR definition of the laserjet isn't setup correctly. I use an input filter script to set all the correct parameters on the ljet. X here is my /etc/printcap file: ------------------------------ /etc/printcap ---------------------------- X # @(#)printcap 5.3 (Berkeley) 6/30/90 X lp|local line printer:\ X :lp=/dev/lpt1:sd=/var/spool/lpd:lf=/var/log/lpd-errs:sh:\ X :if=/usr/local/filters/if_ljet3:\ X :vf=/usr/local/filters/vf_lett3:\ X :df=/usr/local/filters/df_ljet3: ------------------------------------------------------------------------ And this is my homebrew if= input filter script: ( be shure you have the execve magic number patch installed, otherwise X #!/bin/sh will not work!) -------------------------- /usr/local/filters/if_ljet3 ----------------- X #!/bin/sh printf "\033E\033&k2G" cat - printf "\033E" -------------------------------------------------------------------------- And here an filter that attempts to print two pages side by side. (use lpr -d) ------------------------- /usr/local/filters/df_ljet3 -------------------- X #!/bin/sh # Page layout variables LINES=76 TOPMARGIN=5 LEFTMARGIN=0 VMI=5 GUTTER=7 # internal variables: DO NOT CHANGE width=`expr 162 + 2 \* $GUTTER` # Reset the printer printf "\033E" # set line termination to cr->cr; lf->cr+lf; ff->cr+ff printf "\033&k2G" # select landscape orientation printf "\033&l1O" # setup the page: vmi, enable perf skip printf "\033&l${VMI}c1L" # Top margin TOPMARGIN lines printf "\033&l${TOPMARGIN}E" # Text Length $LINES lines printf "\033&l${LINES}F" # left margin of LEFTMARGIN chars printf "\033&a${LEFTMARGIN}L" # select 16.6 pitch font printf "\033(s16.6H" cat - | sed "//d" | pr -2 -n:${GUTTER} -w${width} -e -f -l${LINES} -v - printf "\033E" --------------------------------------------------------------------------- X Hope this helps, X Reinier Kleipool. reink@hpuamsa.neth.hp.com SHAR_EOF chmod 0644 sample.lpt.filters || echo 'restore of sample.lpt.filters failed' Wc_c="`wc -c < 'sample.lpt.filters'`" test 2324 -eq "$Wc_c" || echo 'sample.lpt.filters: original size 2324, current size' "$Wc_c" fi exit 0