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 *
*********************************************************************