Return to BSD News archive
Newsgroups: comp.unix.bsd Path: sserve!manuel!munnari.oz.au!uniwa!cujo!marsh!cproto From: cproto@marsh.cs.curtin.edu.au (Computer Protocol) Subject: 386bsd 0.1 printer driver source resubmitted Message-ID: <cproto.715011443@marsh> Summary: 386bsd printer driver source resubmitted Keywords: 386bsd /dev/lp0 lpt printer parallel port Sender: news@cujo.curtin.edu.au (News Manager) Organization: Curtin University of Technology Date: Fri, 28 Aug 1992 14:17:23 GMT Lines: 585 Hi there, as a number of people requested it, I resubmit my trivial but working printer driver. Add file lp.c and apply the other changes. Do the following: config YOURCONF cd ../../compile/YOURCONF make depend make mv /386bsd /386bsd.save mv 386bsd / Create the device entry by doing a mknod /dev/lp0 c 14 0 Reboot using: sync;sync;fastboot Print using something like: cat printfile > /dev/lp0 Have fun Regards - Tibor Sashegyi - cproto@abel.cs.curtin.edu.au ------------- /sys/i386/isa/lp.c -------------- /* ** parallel port printer driver ** by Tibor Sashegyi 19/04/92 ** (ideas from everywhere) ** stage 2 */ #include "lp.h" #if NLP > 0 #include "param.h" #include "systm.h" #include "proc.h" #include "user.h" #include "conf.h" #include "file.h" #include "uio.h" #include "kernel.h" #include "syslog.h" #include "buf.h" #include "i386/isa/isa_device.h" /* ** printer port base addresses */ #define LPB_1_BASE 0x378 /* base i/o address printer 1 */ #define LPB_2_BASE 0x3BC /* base i/o address printer 2 */ #define LPB_3_BASE 0x278 /* base i/o address printer 3 */ /* ** i/o registers */ #define LPR_DATA 0x00 /* data register */ #define LPR_STAT 0x01 /* status register */ #define LPR_CTRL 0x02 /* control register */ /* ** control bits */ #define LPC_INIT 0x08 /* select and init printer */ #define LPC_STROBE 0x1D /* strobe data */ #define LPC_READY 0x1C /* idle IRQ enabled */ #define LPC_SELECT 0x0C /* select */ /* ** status bits */ #define LPS_ERROR 0x08 /* 0 general error */ #define LPS_SELECT 0x10 /* 1 selected */ #define LPS_PAPER 0x20 /* 1 out of paper */ #define LPS_BUSY 0x80 /* 0 busy */ /* ** lp control block */ #define LPF_ACTIVE 0x01 #define LPF_OPEN 0x02 #define LPF_BUSY 0x04 #define LPF_PAPER 0x08 #define LPF_ERROR 0x10 #define MAXBUF 0x100 struct lpctrl { int unit; int port; char flags; int error; int count; char *cp; char buf[MAXBUF]; } lp_ctrl[NLP]; /* ** misc */ #define LPWATCH 1 int lpprobe(), lpattach(), lpphysio(), lpstrategy(); void lpwatchdog(), lpintr(), lpiowait(), lpiodone(); /* ** define autoconfig entries */ struct isa_driver lpdriver = { lpprobe, lpattach, "lp" }; #define UNIT(x) minor(x) /* ** the following delay value is about right for my machine ** fix it for anything else */ #define CPUSPEED 7 #define LPDELAY(n) { register int N = (n) * CPUSPEED; while (--N > 0); } /* ** probe for device ** I really should probe for the parallel port ** and maybe even the printer, but I trust the ** configuration (silly me). */ int lpprobe(idev) struct isa_device *idev; { if (idev->id_unit >= NLP) return(0); if ( idev->id_iobase != LPB_1_BASE && idev->id_iobase != LPB_2_BASE && idev->id_iobase != LPB_3_BASE) { printf("lp base out of range:%x\n", idev->id_iobase); return(0); } return(1); } /* ** attach device */ int lpattach(idev) struct isa_device *idev; { int unit = idev->id_unit; int port = idev->id_iobase; struct lpctrl *lpc = &lp_ctrl[unit]; lpc->unit = unit; lpc->port = port; lpc->flags = LPF_ACTIVE; /* ** init printer (pulse width at least 50 us) */ outb(port + LPR_CTRL, LPC_INIT); LPDELAY(51); /* ** keep selected */ outb(port + LPR_CTRL, LPC_SELECT); return (1); } /* ** open device */ lpopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p; { int unit = UNIT(dev); struct lpctrl *lpc = &lp_ctrl[unit]; char val; /* ** make sure device is configured */ if (unit >= NLP || (lpc->flags & LPF_ACTIVE) == 0) return(ENXIO); /* ** only one open ! */ if (lpc->flags & LPF_OPEN) return(EBUSY); /* ** check direction */ if (flag & FREAD) return(ENODEV); /* ** check printer status */ val = inb(lpc->port + LPR_STAT); if (val & LPS_PAPER) { uprintf("lp%d: out of paper\n", unit); return(EIO); } if ((val & LPS_ERROR) == 0 || (val & LPS_SELECT) == 0) { uprintf("lp%d: not ready\n", unit); return(EIO); } /* ** start watchdog timer */ timeout(lpwatchdog, lpc, LPWATCH*hz); /* ** enable interrupts and mark as opened */ outb(lpc->port + LPR_CTRL, LPC_READY); lpc->flags |= LPF_OPEN; return(0); } /* ** close device */ int lpclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p; { int unit = UNIT(dev); struct lpctrl *lpc = &lp_ctrl[unit]; /* ** disable interrupts but keep selected, mark as closed */ outb(lpc->port + LPR_CTRL, LPC_SELECT); lpc->flags &= ~LPF_OPEN; return(0); } /* ** write to device */ int lpwrite(dev, uio) dev_t dev; struct uio *uio; { return (uioapply(lpphysio, lpstrategy, dev, uio)); } /* ** check access, lock and call lpstrategy ** to output next printer buffer */ int lpphysio(strat, dev, off, rw, base, len, p) int (*strat)(); dev_t dev; int rw, off; caddr_t base; int *len; struct proc *p; { int error; int rest = *len; int cnt; caddr_t addr = base; rw = rw == UIO_READ ? B_READ : 0; /* ** check if accessible */ if (rw == B_READ && !useracc(base, *len, B_WRITE)) return (EFAULT); if (rw == B_WRITE && !useracc(base, *len, B_READ)) return (EFAULT); /* ** lock in core */ vslock (base, *len); /* ** perform transfer */ error = 0; while(error == 0 && rest > 0) { cnt = min(rest, MAXBUF); rest -= cnt; error = lpstrategy(UNIT(dev), addr, cnt); addr += cnt; } /* ** unlock */ vsunlock (base, *len, 0); *len = 0; return (error); } /* ** fetch next buffer and start output */ int lpstrategy(unit, addr, len) int unit; caddr_t addr; int len; { struct lpctrl *lpc = &lp_ctrl[unit]; int s; lpc->count = len; if (copyin(addr, lpc->buf, len)) { lpiodone(lpc); return(EFAULT); } lpc->cp = lpc->buf; lpc->flags |= LPF_BUSY; lpc->error = 0; s = splhigh(); lpintr(unit); splx(s); /* ** wait for i/o to complete */ lpiowait(lpc); return(lpc->error); } /* ** output next characters until printer becomes busy ** interrupt driven except for the first time */ void lpintr(unit) int unit; { struct lpctrl *lpc = &lp_ctrl[unit]; int port = lpc->port; char val; /* ** check for spurious interrupt */ if (!(lpc->flags & LPF_BUSY)) return; /* ** any more to print */ while (lpc->count) { val = inb(lpc->port + LPR_STAT); if ((val & LPS_BUSY) == 0) return; /* ** output the character */ outb(port + LPR_DATA, *lpc->cp++); --lpc->count; /* ** valid data must be present for at least 0.5 us */ LPDELAY(1); /* ** strobe for 1 us */ outb(port + LPR_CTRL, LPC_STROBE); LPDELAY(1); outb(port + LPR_CTRL, LPC_READY); /* ** valid data must be present for at least 0.5 us */ LPDELAY(1); } lpiodone(lpc); } /* ** wait for i/o to finish */ void lpiowait(lpc) struct lpctrl *lpc; { while (lpc->flags & LPF_BUSY) { if (lpc->error = tsleep(lpc, PRIBIO|PCATCH, NULL, 0)) lpc->flags &= ~LPF_BUSY; } } /* ** wakeup strategy function */ void lpiodone(lpc) struct lpctrl *lpc; { lpc->flags &= ~LPF_BUSY; wakeup(lpc); } /* ** handle watchdog timeout */ void lpwatchdog(lpc) struct lpctrl *lpc; { char val; int s; /* ** are we still running ? */ s = splhigh(); /* bit of an overkill ?!? */ if ((lpc->flags & LPF_OPEN) == 0) { splx(s); return; } /* ** check printer status */ val = inb(lpc->port + LPR_STAT); /* ** report errors only once */ if (val & LPS_PAPER && (lpc->flags & LPF_PAPER) == 0) { printf("lp%d: out of paper, please fix\n", lpc->unit); lpc->flags |= LPF_PAPER; } if (lpc->flags & LPF_PAPER && (val & LPS_PAPER) == 0) lpc->flags &= ~LPF_PAPER; if ((val & LPS_ERROR) == 0 && (lpc->flags & LPF_ERROR) == 0) { printf("lp%d: not ready, please fix\n", lpc->unit); lpc->flags |= LPF_ERROR; } if (lpc->flags & LPF_ERROR && (val & LPS_ERROR) == 0) lpc->flags &= ~LPF_ERROR; /* ** restart watchdog timer */ timeout(lpwatchdog, lpc, LPWATCH*hz); splx(s); } #endif ----------------- /sys/i386/conf/files.i386 -------------- add this: i386/isa/lp.c optional lp device-driver --------------- /sys/i386/conf/YOURCONF ------------------- add this: device lp0 at isa? port "IO_LPT1" irq 7 vector lpintr --------------- /sys/i386/i386/conf.c ---------------------- apply the following patch: *** /sys/i386/i386/conf.c Sat May 30 23:48:08 1992 --- conf.c Tue Aug 25 22:34:52 1992 *************** *** 165,170 **** --- 165,179 ---- #define com_tty NULL #endif + #include "lp.h" + #if NLP > 0 + int lpopen(),lpclose(),lpwrite(); + #else + #define lpopen enxio + #define lpclose enxio + #define lpwrite enxio + #endif + int logopen(),logclose(),logread(),logioctl(),logselect(); int ttselect(), seltrue(); *************** *** 214,219 **** --- 223,231 ---- { asopen, asclose, rawread, rawwrite, /*D*/ asioctl, enodev, nullop, NULL, seltrue, enodev, asstrategy }, + { lpopen, lpclose, enodev, lpwrite, /*E*/ + enodev, enodev, nullop, NULL, + seltrue, enodev, NULL}, }; int nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]); -------------------------- end of hack -------------------------