|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 5853 (0x16dd)
Types: TextFile
Notes: UNIX file
Names: »olp.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦2d53db1df⟧ UNIX Filesystem
└─⟦this⟧ »sys/z8001/drv/olp.c«
/* (-lgl
* The information contained herein is a trade secret of Mark Williams
* Company, and is confidential information. It is provided under a
* license agreement, and may be copied or disclosed only under the
* terms of that agreement. Any reproduction or disclosure of this
* material without the express written authorization of Mark Williams
* Company or persuant to the license agreement is unlawful.
*
* COHERENT Version 0.7.3
* Copyright (c) 1982, 1983, 1984.
* An unpublished work by Mark Williams Company, Chicago.
* All rights reserved.
-lgl) */
/*
* Centronics parallel printer interface driver for Commodore Z8000M
* (uses the Z8036 chip).
*
* April 1984.
*
*/
#include <coherent.h>
#include <con.h>
#include <errno.h>
#include <io.h>
#include <proc.h>
#include <uproc.h>
#include <stat.h>
int lpload();
int lpuload();
int lpwrite();
int lpopen();
int lpclose();
int lpintr();
int nulldev();
int nonedev();
CON lpcon = {
DFCHR, /* Flags */
3, /* Major index */
lpopen, /* Open */
lpclose, /* Close */
nulldev, /* Block */
nonedev, /* Read */
lpwrite, /* Write */
nonedev, /* Ioctl */
nulldev, /* Powerfail */
nulldev, /* Timeout */
lpload, /* Load */
lpuload /* Unload */
};
/*
* Various ports and masks. All initialization of the Z8036
* is done in the mach since there are other devices that
* use the chip. If you want to change LPIRQ you must also
* modify its definition in the mach.
*/
#define LPPORT 0x1D /* Printer port */
#define BUSYPORT 0x1F /* BUSY port */
#define ACKPORT 0x9D /* Acknowledge port */
#define STROBEPORT 0x9F /* Strobe port */
#define SETSTROBE 0x70 /* Sets strobe line */
#define CLEARSTROBE 0x78 /* Clears strobe line */
#define ACKMASK 0x02 /* Mask for acknowledge bit */
#define BUSYMASK 0x01 /* Mask for busy bit */
#define PBCS 0x93 /* Z8036 #2 port B cmd & stat reg */
#define CLRIPIUS 0x20 /* Mask to clear IP and IUS */
#define LPIRQ 0x70 /* Printer interrupt */
#define MAXBUF 256 /* # of bytes in buffer */
#define LOLIM 30 /* Low buffer limit for wakeup */
/*
* Printer database.
*/
struct lpinfo {
int lpcol; /* Current horizontal position */
int lpnbuf; /* # of bytes in buffer */
char *lpin; /* Input pointer */
char *lpout; /* Output pointer */
char lpflag; /* Flags */
char lpbuf[MAXBUF]; /* Buffer */
} lp;
/* lpflag bits */
#define LPOPEN 0x01 /* Printer is open */
#define LPSLEEP 0x02 /* Sleeping on buffer event */
#define LPRAW 0x04 /* Raw mode */
/*
* On load, set up the circular
* buffer pointers in the printer database,
* then grab the interrupt vector.
* The data lines are initialised, as follows in md.s:
* 8036 #1, port b, non-inverting: output data lines
* 8036 #1, port c, bit 0, non-inverting: input busy line
* 8036 #2, port b, bit 1, inverting: inpupt acknowledge
* 8036 #2, port c, bit 3, non-inverting: output strobe
*/
lpload()
{
lp.lpin = &lp.lpbuf[0];
lp.lpout = &lp.lpbuf[0];
setivec(LPIRQ, &lpintr);
}
/*
* Unload the driver and close up shop
*/
lpuload()
{
clrivec(LPIRQ);
}
/*
* The open routine makes sure
* that only one process can have the
* printer open at once, and copies the
* RAW bit of the minor into the local
* printer flags.
*/
lpopen(dev, mode)
dev_t dev;
{
if ((lp.lpflag&LPOPEN) != 0) {
u.u_error = EDBUSY;
return;
}
lp.lpflag = LPOPEN;
if ((minor(dev)&0x01) != 0)
lp.lpflag |= LPRAW;
}
/*
* The close routine drains the
* circular buffer in the per printer
* database, and then marks the device
* as no longer open.
*/
lpclose(dev)
dev_t dev;
{
register int s;
s = sphi();
while (lp.lpnbuf != 0) {
lp.lpflag |= LPSLEEP;
sleep((char *)&lp, 0, 0, 0);
}
spl(s);
lp.lpflag = 0;
}
/*
* The write routine copies the
* characters from the user buffer to
* the printer buffer, expanding tabs and
* keeping track of the current horizontal
* position of the print head.
*/
lpwrite(dev, iop)
dev_t dev;
IO *iop;
{
register int c;
register int s;
while ((c=iogetc(iop)) >= 0) {
if ((lp.lpflag&LPRAW) == 0) {
switch (c) {
case '\t':
do {
lpchar(' ');
} while ((++lp.lpcol&07) != 0);
continue;
case '\n':
lpchar('\r');
case '\r':
case '\f':
lp.lpcol = 0;
break;
case '\b':
--lp.lpcol;
break;
default:
++lp.lpcol;
}
}
lpchar(c);
if (SELF->p_ssig!=0 && nondsig()) {
u.u_error = EINTR;
break;
}
}
s = sphi();
lpstart();
spl(s);
}
/*
* Put a character into the
* printer buffer. Make sure that there is
* room to do so, and wait for the interrupt
* driven part to make more room if this is
* indeed necessary.
*/
lpchar(c)
{
register int s;
s = sphi();
while (lp.lpnbuf >= MAXBUF) {
lpstart();
lp.lpflag |= LPSLEEP;
sleep((char *)&lp, 0, 0, 0);
}
++lp.lpnbuf;
if (lp.lpin == &lp.lpbuf[MAXBUF])
lp.lpin = &lp.lpbuf[0];
*lp.lpin++ = c;
spl(s);
}
/*
* Start up the printer, if it
* is not already printing. Copy characters
* to the printer until it goes busy.
* Always called with printer interrupts
* disabled.
*/
lpstart()
{
if (lp.lpnbuf!=0 && (inb(BUSYPORT)&BUSYMASK)==0) {
--lp.lpnbuf;
if (lp.lpout == &lp.lpbuf[MAXBUF])
lp.lpout = &lp.lpbuf[0];
outb(LPPORT, *lp.lpout++); /* Load char on output lines */
outb(STROBEPORT, SETSTROBE); /* Strobe it! */
}
}
/*
* Interrupt routine. Poke the printer
* to get it going. Wake up the process level
* half of the driver, if necessary.
*/
lpintr()
{
register int s;
s = sphi();
outb(ACKPORT, inb(ACKPORT) & ~ACKMASK); /* Clear acknowledge bit */
outb(STROBEPORT, CLEARSTROBE); /* Clear strobe */
lpstart();
if ((lp.lpflag&LPSLEEP)!=0 && lp.lpnbuf<LOLIM) {
lp.lpflag &= ~LPSLEEP;
wakeup((char *)&lp);
}
outb(PBCS, CLRIPIUS); /* Clear IP & IUS */
spl(s);
}