DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦c3529f070⟧ TextFile

    Length: 5853 (0x16dd)
    Types: TextFile
    Notes: UNIX file
    Names: »olp.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦2d53db1df⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »sys/z8001/drv/olp.c« 

TextFile

/* (-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);
}