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