Return to BSD News archive
Received: by minnie.vk1xwt.ampr.org with NNTP id AA490 ; Wed, 03 Feb 93 19:01:28 EST Path: sserve!manuel.anu.edu.au!munnari.oz.au!spool.mu.edu!caen!saimiri.primate.wisc.edu!copper!mercury.cair.du.edu!mnemosyne.cs.du.edu!nyx!smace From: smace@nyx.cs.du.edu (Scott Mace) Newsgroups: comp.unix.bsd Subject: [386BSD] lpdriver.shar --- a set of working lp drivers Message-ID: <1993Feb2.214555.16947@mnemosyne.cs.du.edu> Date: 2 Feb 93 21:45:55 GMT Sender: usenet@mnemosyne.cs.du.edu (netnews admin account) Organization: Nyx, Public Access Unix @ U. of Denver Math/CS dept. Lines: 1438 Here are two lpt drivers that I use on my systems. lpt.c and lp.c both work basically the same. ---cut here--- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # LPTEST # README # files.i386 # conf.c # lp.c # lpt.c # lpt.h # lptreg.h # echo x - LPTEST sed 's/^X//' >LPTEST << 'END-of-LPTEST' X# X# LPTEST -- Generic ISA machine -- lptest test kernel X# Xmachine "i386" Xcpu "i386" Xident LPTEST Xtimezone 6 dst Xmaxusers 16 Xoptions INET,NFS,XSERVER,UCONSOLE Xoptions "COMPAT_43" Xoptions "TCP_COMPAT_42" Xoptions "i387" X Xconfig "386bsd" root on sd0 swap on sd0 X Xcontroller isa0 X X#controller wd0 at isa? port "IO_WD1" bio irq 14 vector wdintr X#disk wd0 at wd0 drive 0 X#disk wd0 at wd0 drive 1 X Xcontroller fd0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr Xdisk fd0 at fd0 drive 0 Xdisk fd1 at fd0 drive 1 X Xdevice pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint Xdevice npx0 at isa? port "IO_NPX" irq 13 vector npxintr Xdevice com0 at isa? port "IO_COM1" tty irq 4 vector comintr Xdevice com1 at isa? port "IO_COM2" tty irq 3 vector comintr X X# Use lpt1 for the lpt.c and lp0 for lp.c Xdevice lpt1 at isa? port "IO_LPT1" tty irq 7 vector lptintr X#device lp0 at isa? port "IO_LPT1" irq 7 vector lpintr X X# sound blaster Xdevice sb0 at isa? port 0x220 bio irq 5 drq 1 vector sbintr X X# julian Escher's SCSI drivers Xcontroller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr X#controller aha1 at isa? port "IO_AHA1" bio irq 12 drq 7 vector ahaintr X#controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr Xcontroller scbus0 X Xdevice sd0 Xdevice sd1 Xdevice sd2 Xdevice sd3 X Xdevice st0 Xdevice st1 Xdevice st2 Xdevice st3 X Xdevice cd0 Xdevice cd1 X Xdevice we0 at isa? port 0x280 net irq 9 iomem 0xd0000 iosiz 8192 vector weintr X X Xpseudo-device loop Xpseudo-device ether Xpseudo-device sl Xpseudo-device log X#pseudo-device ddb Xpseudo-device pty 16 X Xpseudo-device swappager Xpseudo-device vnodepager Xpseudo-device devpager END-of-LPTEST echo x - README sed 's/^X//' >README << 'END-of-README' XHere is the lpt driver that I use on my system. X Xlpt.c original lpt driver with various patches X Xlp.c new lp driver (works like lpt.c) X Xlpt.c should work fine on many systems. If it doesn't, then use lp.c, Xwhich is a complete rewrite of a line printer driver. X Xlpt.c /sys/i386/isa Xlptreg.h /sys/i386/isa Xlp.c /sys/i386/isa X Xconf.c /sys/i386/i386 X Xfiles.i386 /sys/i386/conf XLPTEST my config file X Xmy conf.c should work with both the lpt and lp drivers. X XThese drivers should fix the problems with systems rebooting. X XThe major and minor numbers of the devices as per my conf.c X Xdevice major minor X/dev/lpt1 16 0 X/dev/lp0 17 0 X XSend any questions to emace@tenet.edu X END-of-README echo x - files.i386 sed 's/^X//' >files.i386 << 'END-of-files.i386' Xi386/i386/autoconf.c standard device-driver Xi386/i386/cons.c standard Xi386/isa/pccons.c optional pc device-driver Xi386/isa/clock.c standard Xi386/i386/in_cksum.c optional inet Xi386/i386/machdep.c standard config-dependent Xi386/i386/math_emulate.c standard Xi386/i386/mem.c standard Xi386/i386/pmap.c standard Xi386/i386/ns_cksum.c optional ns Xi386/i386/sys_machdep.c standard Xi386/i386/trap.c standard Xi386/i386/vm_machdep.c standard Xi386/isa/if_ne.c optional ne device-driver Xi386/isa/if_we.c optional we device-driver Xi386/isa/if_ec.c optional ec device-driver Xi386/isa/if_is.c optional is device-driver Xi386/isa/wd.c optional wd device-driver Xi386/isa/fd.c optional fd device-driver Xi386/isa/wt.c optional wt device-driver Xi386/isa/isa.c optional isa device-driver Xi386/isa/com.c optional com device-driver Xi386/isa/npx.c optional npx device-driver Xi386/isa/as.c optional as device-driver Xi386/isa/lpt.c optional lpt device-driver Xi386/isa/lp.c optional lp device-driver Xi386/isa/sb_driver.c optional sb device-driver Xi386/i386/db_disasm.c optional ddb Xi386/i386/db_interface.c optional ddb Xi386/i386/db_trace.c optional ddb Xi386/isa/aha1742.c optional ahb Xi386/isa/aha1542.c optional aha Xi386/isa/bt742a.c optional bt Xi386/isa/ultra14f.c optional uha Xscsi/st.c optional st Xscsi/sd.c optional sd Xscsi/cd.c optional cd Xscsi/ch.c optional ch Xscsi/scsiconf.c optional scbus END-of-files.i386 echo x - conf.c sed 's/^X//' >conf.c << 'END-of-conf.c' X/*- X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software contributed to Berkeley by X * William Jolitz. 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 product includes software developed by the University of X * California, Berkeley and its contributors. X * 4. Neither the name of the University nor the names of its contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 * @(#)conf.c 5.8 (Berkeley) 5/12/91 X */ Xstatic char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/conf.c,v 1.2 92/01/21 14:21:57 william Exp Locker: toor $"; X X#include "param.h" X#include "systm.h" X#include "buf.h" X#include "ioctl.h" X#include "tty.h" X#include "conf.h" X Xint nullop(), enxio(), enodev(), rawread(), rawwrite(), swstrategy(); Xint rawread(), rawwrite(), swstrategy(); X X#include "wd.h" X#if NWD > 0 Xint wdopen(),wdclose(),wdstrategy(),wdioctl(); Xint wddump(),wdsize(); X#else X#define wdopen enxio X#define wdclose enxio X#define wdstrategy enxio X#define wdioctl enxio X#define wddump enxio X#define wdsize NULL X#endif X X#include "as.h" X#if NAS > 0 Xint asopen(),asclose(),asstrategy(),asioctl(); Xint /*asdump(),*/assize(); X#define asdump enxio X#else X#define asopen enxio X#define asclose enxio X#define asstrategy enxio X#define asioctl enxio X#define asdump enxio X#define assize NULL X#endif X X#include "sd.h" X#if NSD > 0 Xint sdopen(),sdclose(),sdstrategy(),sdioctl(); Xint /*sddump(),*/sdsize(); X#define sddump enxio X#else X#define sdopen enxio X#define sdclose enxio X#define sdstrategy enxio X#define sdioctl enxio X#define sddump enxio X#define sdsize NULL X#endif X X#include "st.h" X#if NST > 0 Xint stopen(),stclose(),ststrategy(),stioctl(); X/*int stdump(),stsize();*/ X#define stdump enxio X#define stsize NULL X#else X#define stopen enxio X#define stclose enxio X#define ststrategy enxio X#define stioctl enxio X#define stdump enxio X#define stsize NULL X#endif X X#include "cd.h" X#if NCD > 0 Xint cdopen(),cdclose(),cdstrategy(),cdioctl(); Xint /*cddump(),*/cdsize(); X#define cddump enxio X#else X#define cdopen enxio X#define cdclose enxio X#define cdstrategy enxio X#define cdioctl enxio X#define cddump enxio X#define cdsize NULL X#endif X X#include "sb.h" X#if NSB > 0 Xint sb_open(), sb_close(), sb_ioctl(), sb_read(), sb_write(); X#else X#define sb_open enxio X#define sb_close enxio X#define sb_ioctl enxio X#define sb_read enxio X#define sb_write enxio X#endif X X#include "wt.h" X#if NWT > 0 Xint wtopen(),wtclose(),wtstrategy(),wtioctl(); Xint wtdump(),wtsize(); X#else X#define wtopen enxio X#define wtclose enxio X#define wtstrategy enxio X#define wtioctl enxio X#define wtdump enxio X#define wtsize NULL X#endif X X#include "fd.h" X#if NFD > 0 Xint Fdopen(),fdclose(),fdstrategy(); X#define fdioctl enxio X#define fddump enxio X#define fdsize NULL X#else X#define Fdopen enxio X#define fdclose enxio X#define fdstrategy enxio X#define fdioctl enxio X#define fddump enxio X#define fdsize NULL X#endif X Xint swstrategy(),swread(),swwrite(); X Xstruct bdevsw bdevsw[] = X{ X { wdopen, wdclose, wdstrategy, wdioctl, /*0*/ X wddump, wdsize, NULL }, X { enodev, enodev, swstrategy, enodev, /*1*/ X enodev, enodev, NULL }, X { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/ X fddump, fdsize, NULL }, X { wtopen, wtclose, wtstrategy, wtioctl, /*3*/ X wtdump, wtsize, B_TAPE }, X#if NSD > 0 X { sdopen, sdclose, sdstrategy, sdioctl, /*4*/ X sddump, sdsize, NULL }, X#else NSD > 0 X { asopen, asclose, asstrategy, asioctl, /*4*/ X asdump, assize, NULL }, X#endif NSD > 0 X { stopen, stclose, ststrategy, stioctl, /*5*/ X stdump, stsize, NULL }, X { cdopen, cdclose, cdstrategy, cdioctl, /*6*/ X cddump, cdsize, NULL }, X}; Xint nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]); X Xint cnopen(),cnclose(),cnread(),cnwrite(),cnioctl(),cnselect(); X Xint pcopen(),pcclose(),pcread(),pcwrite(),pcioctl(),pcmmap(); Xextern struct tty pccons; X Xint cttyopen(), cttyread(), cttywrite(), cttyioctl(), cttyselect(); X Xint mmrw(); X#define mmselect seltrue X X#include "pty.h" X#if NPTY > 0 Xint ptsopen(),ptsclose(),ptsread(),ptswrite(),ptsstop(); Xint ptcopen(),ptcclose(),ptcread(),ptcwrite(),ptcselect(); Xint ptyioctl(); Xstruct tty pt_tty[]; X#else X#define ptsopen enxio X#define ptsclose enxio X#define ptsread enxio X#define ptswrite enxio X#define ptcopen enxio X#define ptcclose enxio X#define ptcread enxio X#define ptcwrite enxio X#define ptyioctl enxio X#define pt_tty NULL X#define ptcselect enxio X#define ptsstop nullop X#endif X X#include "com.h" X#if NCOM > 0 Xint comopen(),comclose(),comread(),comwrite(),comioctl(); X#define comreset enxio Xextern struct tty com_tty[]; X#else X#define comopen enxio X#define comclose enxio X#define comread enxio X#define comwrite enxio X#define comioctl enxio X#define comreset enxio X#define com_tty NULL X#endif X X#include "lpt.h" X#if NLPT > 0 Xint lptopen(),lptclose(),lptwrite(),lptioctl(); X#else X#define lptopen enxio X#define lptclose enxio X#define lptwrite enxio X#endif X X#include "lp.h" X#if NLP > 0 Xint lpopen(),lpclose(),lpwrite(); X#else X#define lpopen enxio X#define lpclose enxio X#define lpwrite enxio X#endif X Xint logopen(),logclose(),logread(),logioctl(),logselect(); X Xint ttselect(), seltrue(); X X Xstruct cdevsw cdevsw[] = X{ X { cnopen, cnclose, cnread, cnwrite, /*0*/ X cnioctl, nullop, nullop, NULL, X cnselect, enodev, NULL }, X { cttyopen, nullop, cttyread, cttywrite, /*1*/ X cttyioctl, nullop, nullop, NULL, X cttyselect, enodev, NULL }, X { nullop, nullop, mmrw, mmrw, /*2*/ X enodev, nullop, nullop, NULL, X mmselect, enodev, NULL }, X { wdopen, wdclose, rawread, rawwrite, /*3*/ X wdioctl, enodev, nullop, NULL, X seltrue, enodev, wdstrategy }, X { nullop, nullop, rawread, rawwrite, /*4*/ X enodev, enodev, nullop, NULL, X enodev, enodev, swstrategy }, X { ptsopen, ptsclose, ptsread, ptswrite, /*5*/ X ptyioctl, ptsstop, nullop, pt_tty, X ttselect, enodev, NULL }, X { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/ X ptyioctl, nullop, nullop, pt_tty, X ptcselect, enodev, NULL }, X { logopen, logclose, logread, enodev, /*7*/ X logioctl, enodev, nullop, NULL, X logselect, enodev, NULL }, X { comopen, comclose, comread, comwrite, /*8*/ X comioctl, enodev, comreset, com_tty, X ttselect, enodev, NULL }, X { Fdopen, fdclose, rawread, rawwrite, /*9*/ X fdioctl, enodev, nullop, NULL, X seltrue, enodev, fdstrategy }, X { wtopen, wtclose, rawread, rawwrite, /*A*/ X wtioctl, enodev, nullop, NULL, X seltrue, enodev, wtstrategy }, X { enodev, enodev, enodev, enodev, /*B*/ X enodev, enodev, nullop, NULL, X seltrue, enodev, enodev }, X { pcopen, pcclose, pcread, pcwrite, /*C*/ X pcioctl, nullop, nullop, &pccons, X ttselect, pcmmap, NULL }, X#if NSD > 0 X { sdopen, sdclose, rawread, rawwrite, /*D*/ X sdioctl, enodev, nullop, NULL, X seltrue, enodev, sdstrategy }, X#else NSD > 0 X { asopen, asclose, rawread, rawwrite, /*D*/ X asioctl, enodev, nullop, NULL, X seltrue, enodev, asstrategy }, X#endif NSD > 0 X { stopen, stclose, rawread, rawwrite, /*E*/ X stioctl, enodev, nullop, NULL, X seltrue, enodev, ststrategy }, X { cdopen, cdclose, rawread, rawwrite, /*F*/ X cdioctl, enodev, nullop, NULL, X seltrue, enodev, cdstrategy }, X { lptopen, lptclose, nullop, lptwrite, /*10*/ X enodev, nullop, nullop, NULL, X seltrue, enodev, enodev }, X { lpopen, lpclose, enodev, lpwrite, /*11*/ X enodev, enodev, nullop, NULL, X seltrue, enodev, NULL }, X { enodev, enodev, enodev, enodev, /*12*/ X enodev, enodev, nullop, NULL, X seltrue, enodev, enodev }, X { enodev, enodev, enodev, enodev, /*13*/ X enodev, enodev, nullop, NULL, X seltrue, enodev, enodev }, X { enodev, enodev, enodev, enodev, /*14*/ X enodev, enodev, nullop, NULL, X seltrue, enodev, enodev }, X { sb_open, sb_close, sb_read, sb_write, /*15*/ X sb_ioctl, enodev, nullop, NULL, X seltrue, enodev, enodev }, X}; Xint nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]); X Xint mem_no = 2; /* major device number of memory special file */ X X/* X * Swapdev is a fake device implemented X * in sw.c used only internally to get to swstrategy. X * It cannot be provided to the users, because the X * swstrategy routine munches the b_dev and b_blkno entries X * before calling the appropriate driver. This would horribly X * confuse, e.g. the hashing routines. Instead, /dev/drum is X * provided as a character (raw) device. X */ Xdev_t swapdev = makedev(1, 0); END-of-conf.c echo x - lp.c sed 's/^X//' >lp.c << 'END-of-lp.c' X/* X** parallel port printer driver X** by Tibor Sashegyi 19/04/92 X** (ideas from everywhere) X** stage 2 X*/ X X#include "lp.h" X X#if NLP > 0 X X#include "param.h" X#include "systm.h" X#include "proc.h" X#include "user.h" X#include "conf.h" X#include "file.h" X#include "uio.h" X#include "kernel.h" X#include "syslog.h" X#include "buf.h" X X#include "i386/isa/isa_device.h" X X/* X** printer port base addresses X*/ X X X#define LPB_1_BASE 0x378 /* base i/o address printer 1 */ X#define LPB_2_BASE 0x3BC /* base i/o address printer 2 */ X#define LPB_3_BASE 0x278 /* base i/o address printer 3 */ X X/* X** i/o registers X*/ X X#define LPR_DATA 0x00 /* data register */ X#define LPR_STAT 0x01 /* status register */ X#define LPR_CTRL 0x02 /* control register */ X X/* X** control bits X*/ X X#define LPC_INIT 0x08 /* select and init printer */ X#define LPC_STROBE 0x1D /* strobe data */ X#define LPC_READY 0x1C /* idle IRQ enabled */ X#define LPC_SELECT 0x0C /* select */ X X/* X** status bits X*/ X X#define LPS_ERROR 0x08 /* 0 general error */ X#define LPS_SELECT 0x10 /* 1 selected */ X#define LPS_PAPER 0x20 /* 1 out of paper */ X#define LPS_BUSY 0x80 /* 0 busy */ X X/* X** lp control block X*/ X X#define LPF_ACTIVE 0x01 X#define LPF_OPEN 0x02 X#define LPF_BUSY 0x04 X#define LPF_PAPER 0x08 X#define LPF_ERROR 0x10 X X#define MAXBUF 0x100 X Xstruct lpctrl X { X int unit; X int port; X char flags; X int error; X int count; X char *cp; X char buf[MAXBUF]; X } lp_ctrl[NLP]; X X/* X** misc X*/ X X#define LPWATCH 1 X Xint lpprobe(), lpattach(), lpphysio(), lpstrategy(); Xvoid lpwatchdog(), lpintr(), lpiowait(), lpiodone(); X X/* X** define autoconfig entries X*/ X Xstruct isa_driver lpdriver = X { X lpprobe, lpattach, "lp" X }; X X#define UNIT(x) minor(x) X X/* X** the following delay value is about right for my machine X** fix it for anything else X*/ X X#define CPUSPEED 7 X#define LPDELAY(n) { register int N = (n) * CPUSPEED; while (--N > 0); } X X/* X** probe for device X** I really should probe for the parallel port X** and maybe even the printer, but I trust the X** configuration (silly me). X*/ X Xint lpprobe(idev) Xstruct isa_device *idev; X { X if (idev->id_unit >= NLP) X return(0); X X if ( idev->id_iobase != LPB_1_BASE X && idev->id_iobase != LPB_2_BASE X && idev->id_iobase != LPB_3_BASE) X { X printf("lp base out of range:%x\n", idev->id_iobase); X return(0); X } X X return(1); X } X X/* X** attach device X*/ X Xint lpattach(idev) Xstruct isa_device *idev; X { X int unit = idev->id_unit; X int port = idev->id_iobase; X struct lpctrl *lpc = &lp_ctrl[unit]; X X X lpc->unit = unit; X lpc->port = port; X lpc->flags = LPF_ACTIVE; X X /* X ** init printer (pulse width at least 50 us) X */ X X outb(port + LPR_CTRL, LPC_INIT); X LPDELAY(51); X X /* X ** keep selected X */ X X outb(port + LPR_CTRL, LPC_SELECT); X X return (1); X } X X/* X** open device X*/ X Xlpopen(dev, flag, mode, p) X dev_t dev; X int flag, mode; X struct proc *p; X { X int unit = UNIT(dev); X struct lpctrl *lpc = &lp_ctrl[unit]; X char val; X X /* X ** make sure device is configured X */ X X if (unit >= NLP || (lpc->flags & LPF_ACTIVE) == 0) X return(ENXIO); X X /* X ** only one open ! X */ X X if (lpc->flags & LPF_OPEN) X return(EBUSY); X X /* X ** check direction X */ X X if (flag & FREAD) X return(ENODEV); X X /* X ** check printer status X */ X X val = inb(lpc->port + LPR_STAT); X if (val & LPS_PAPER) X { X uprintf("lp%d: out of paper\n", unit); X return(EIO); X } X X if ((val & LPS_ERROR) == 0 || (val & LPS_SELECT) == 0) X { X uprintf("lp%d: not ready\n", unit); X return(EIO); X } X X /* X ** start watchdog timer X */ X X timeout(lpwatchdog, lpc, LPWATCH*hz); X X /* X ** enable interrupts and mark as opened X */ X X outb(lpc->port + LPR_CTRL, LPC_READY); X lpc->flags |= LPF_OPEN; X X return(0); X } X X/* X** close device X*/ X Xint lpclose(dev, flag, mode, p) X dev_t dev; X int flag, mode; X struct proc *p; X { X int unit = UNIT(dev); X struct lpctrl *lpc = &lp_ctrl[unit]; X X /* X ** disable interrupts but keep selected, mark as closed X */ X X outb(lpc->port + LPR_CTRL, LPC_SELECT); X lpc->flags &= ~LPF_OPEN; X X return(0); X } X X/* X** write to device X*/ X Xint lpwrite(dev, uio) X dev_t dev; X struct uio *uio; X{ X return (uioapply(lpphysio, lpstrategy, dev, uio)); X} X X/* X** check access, lock and call lpstrategy X** to output next printer buffer X*/ X Xint lpphysio(strat, dev, off, rw, base, len, p) X int (*strat)(); X dev_t dev; X int rw, off; X caddr_t base; X int *len; X struct proc *p; X{ X int error; X int rest = *len; X int cnt; X caddr_t addr = base; X X rw = rw == UIO_READ ? B_READ : 0; X X /* X ** check if accessible X */ X X if (rw == B_READ && !useracc(base, *len, B_WRITE)) X return (EFAULT); X X if (rw == B_WRITE && !useracc(base, *len, B_READ)) X return (EFAULT); X X /* X ** lock in core X */ X X vslock (base, *len); X X /* X ** perform transfer X */ X X error = 0; X while(error == 0 && rest > 0) X { X cnt = min(rest, MAXBUF); X rest -= cnt; X error = lpstrategy(UNIT(dev), addr, cnt); X addr += cnt; X } X X /* X ** unlock X */ X X vsunlock (base, *len, 0); X X *len = 0; X return (error); X } X X/* X** fetch next buffer and start output X*/ X Xint lpstrategy(unit, addr, len) X int unit; X caddr_t addr; X int len; X { X struct lpctrl *lpc = &lp_ctrl[unit]; X int s; X X lpc->count = len; X if (copyin(addr, lpc->buf, len)) X { X lpiodone(lpc); X return(EFAULT); X } X X lpc->cp = lpc->buf; X lpc->flags |= LPF_BUSY; X lpc->error = 0; X X s = splhigh(); X lpintr(unit); X splx(s); X X /* X ** wait for i/o to complete X */ X X lpiowait(lpc); X X return(lpc->error); X } X X/* X** output next characters until printer becomes busy X** interrupt driven except for the first time X*/ X Xvoid lpintr(unit) X int unit; X{ X struct lpctrl *lpc = &lp_ctrl[unit]; X int port = lpc->port; X char val; X X /* X ** check for spurious interrupt X */ X X if (!(lpc->flags & LPF_BUSY)) X return; X X /* X ** any more to print X */ X X while (lpc->count) X { X val = inb(lpc->port + LPR_STAT); X if ((val & LPS_BUSY) == 0) X return; X /* X ** output the character X */ X X outb(port + LPR_DATA, *lpc->cp++); X --lpc->count; X X /* X ** valid data must be present for at least 0.5 us X */ X X LPDELAY(1); X X /* X ** strobe for 1 us X */ X X outb(port + LPR_CTRL, LPC_STROBE); X LPDELAY(1); X outb(port + LPR_CTRL, LPC_READY); X X /* X ** valid data must be present for at least 0.5 us X */ X X LPDELAY(1); X } X X lpiodone(lpc); X } X X/* X** wait for i/o to finish X*/ X Xvoid lpiowait(lpc) X struct lpctrl *lpc; X { X while (lpc->flags & LPF_BUSY) X { X if (lpc->error = tsleep(lpc, PRIBIO|PCATCH, NULL, 0)) X lpc->flags &= ~LPF_BUSY; X } X } X X/* X** wakeup strategy function X*/ X Xvoid lpiodone(lpc) X struct lpctrl *lpc; X { X lpc->flags &= ~LPF_BUSY; X wakeup(lpc); X } X X/* X** handle watchdog timeout X*/ X Xvoid lpwatchdog(lpc) X struct lpctrl *lpc; X { X char val; X int s; X X /* X ** are we still running ? X */ X X s = splhigh(); /* bit of an overkill ?!? */ X X if ((lpc->flags & LPF_OPEN) == 0) X { X splx(s); X return; X } X X /* X ** check printer status X */ X X val = inb(lpc->port + LPR_STAT); X X /* X ** report errors only once X */ X X if (val & LPS_PAPER && (lpc->flags & LPF_PAPER) == 0) X { X printf("lp%d: out of paper, please fix\n", lpc->unit); X lpc->flags |= LPF_PAPER; X } X if (lpc->flags & LPF_PAPER && (val & LPS_PAPER) == 0) X lpc->flags &= ~LPF_PAPER; X X if ((val & LPS_ERROR) == 0 && (lpc->flags & LPF_ERROR) == 0) X { X printf("lp%d: not ready, please fix\n", lpc->unit); X lpc->flags |= LPF_ERROR; X } X if (lpc->flags & LPF_ERROR && (val & LPS_ERROR) == 0) X lpc->flags &= ~LPF_ERROR; X X /* X ** restart watchdog timer X */ X X timeout(lpwatchdog, lpc, LPWATCH*hz); X splx(s); X } X X#endif END-of-lp.c echo x - lpt.c sed 's/^X//' >lpt.c << 'END-of-lpt.c' X/* 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/* 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 X#include "lpt.h" X#if NLPT > 0 X X#include "param.h" X#include "buf.h" X#include "systm.h" X#include "ioctl.h" X#include "tty.h" X#include "proc.h" X#include "user.h" X#include "uio.h" X#include "kernel.h" X#include "malloc.h" X X#include "i386/isa/isa_device.h" X#include "i386/isa/lptreg.h" X X/* internal used flags */ X#define OPEN (0x01) /* device is open */ X#define INIT (0x02) /* device in open procedure */ X X/* flags from minor device */ X#define LPT_PRIME (0x20) /* prime printer on open */ X#define LPT_ERROR (0x10) /* log error conditions */ X X#define LPT_FLAG(x) ((x) & 0xfc) X#define LPT_UNIT(x) ((x) & 0x03) X X/* Printer Ready condition */ X#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) X#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) X#define NOT_READY() ((inb(sc->sc_stat)^LPS_INVERT)&LPS_MASK) X X/* tsleep priority */ X#define LPPRI ((PZERO+8) | PCATCH) X Xint lptprobe(), lptattach(); Xstruct isa_driver lptdriver = {lptprobe, lptattach, "lpt"}; X X/* X * copy usermode data into sysmode buffer X */ X#define BUFSIZE 1024 X X/* X** Waittimes X*/ X#define TIMEOUT (hz*16) /* Timeout while open device */ X#define LONG (hz* 1) /* Timesteps while open */ X X#define MAX_SPIN 255 /* max loop counter for busy wait */ X X/* Valid Controlbits for probe ... X** X** The lower 5 bits of controlport should be X** readable and writable, X** X** .... but if my deskjet is power down, it clobbers X** some lines, and the port will not be configured. X** So I mask them out X*/ X#define LPC_MASK (0xfa) X Xstruct 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; X} lpt_sc[NLPT]; X X/* In fact, I need no interrupt, but how can I explain it to config ??? */ Xlptintr(unit) X int unit; X{ X /* dummy */ ; X} X X/* X * lptprobe() X * Probe for hardware X */ Xlptprobe(idp) X struct isa_device *idp; X{ 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 X/* X * lptattach() X * Install device X */ Xlptattach(isdp) X struct isa_device *isdp; X{ 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 X/* X * lptopen() X * New open on device. X * X * We forbid all but first open X */ Xlptopen(dev, flag) X dev_t dev; X int flag; X{ 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 X/* X * pushbytes() X * Workhorse for actually spinning and writing bytes to printer X */ Xstatic Xpushbytes(sc) X struct lpt_softc *sc; X{ 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 X/* X * lptclose() X * Close on lp. Try to flush data in buffer out. X */ Xlptclose(dev, flag) X dev_t dev; X int flag; X{ 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 X/* X * lptwrite() X * Copy from user's buffer, then print X */ Xlptwrite(dev, uio) X dev_t dev; X struct uio *uio; X{ 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); X} X#endif /* NLP > 0 */ END-of-lpt.c echo x - lpt.h sed 's/^X//' >lpt.h << 'END-of-lpt.h' X#define NLPT 2 END-of-lpt.h echo x - lptreg.h sed 's/^X//' >lptreg.h << 'END-of-lptreg.h' X/*- X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software contributed to Berkeley by X * William Jolitz. X * X * %sccs.include.noredist.c% X * X * @(#)lptreg.h 1.1 (Berkeley) 12/19/90 X */ X X/* X * AT Parallel Port (for lineprinter) X * Interface port and bit definitions X * Written by William Jolitz 12/18/90 X * Copyright (C) William Jolitz 1990 X */ X X#define lpt_data 0 /* Data to/from printer (R/W) */ X X#define lpt_status 1 /* Status of printer (R) */ X#define LPS_NERR 0x08 /* printer no error */ X#define LPS_SEL 0x10 /* printer selected */ X#define LPS_OUT 0x20 /* printer out of paper */ X#define LPS_NACK 0x40 /* printer no ack of data */ X#define LPS_NBSY 0x80 /* printer no ack of data */ X X#define lpt_control 2 /* Control printer (R/W) */ X#define LPC_STB 0x01 /* strobe data to printer */ X#define LPC_AUTOL 0x02 /* automatic linefeed */ X#define LPC_NINIT 0x04 /* initialize printer */ X#define LPC_SEL 0x08 /* printer selected */ X#define LPC_ENA 0x10 /* printer out of paper */ END-of-lptreg.h exit ---cut here--- -- ********************************************************************* * Scott Mace internet: smace@nyx.cs.du.edu * * emace@tenet.edu * *********************************************************************