Ausam/sys/dmr/lp.c-elec
#
/*
* Copyright 1976 Ian Johnstone.
*
*
* This line printer driver will handle printers
* in the best most efficient way. Maybe.
* No upper to lower case conversion.
* Recognize zero, blank suppression.
* Support adjustable size pages.
* Support 013 as skip to perforations.
* Talk to DEC and other ( CDC ) printers.
* Support special CDC skips.
* Kronos eor/eof taken as form feeds. 022, 006
* Stty calls supported to change modes.
*
*/
#include "../defines.h"
#include "../param.h"
#include "../conf.h"
#include "../user.h"
#include "../proc.h"
#include "../buf.h"
/*
* status register bits
*/
#define IENABLE 0100
#define READY 0200
#define NLP 1 /* no. of line printers */
#define LPPRI 3
/*
* some status & mode bits
*/
#define WOPEN 0000001 /* device open for writing */
#define CLOSIN 0000002 /* device closing */
#define TRNS 0000004 /* if half ASCII (May be undefined) */
#define CDC 0000010 /* if cdc special skips */
#define VTAB 0000020 /* support vertical tabs */
#define FLUSH 0000040 /* when set flush all */
#define FEED 0000100 /* if always take ff's, lf's */
#define NOEJECT 0000200 /* if disable auto skip */
#define TMPNOEJ 0000400 /* if temporary NOEJECT */
#define SIXLPI 0001000 /* 11" paper at 6 lines/inch */
/* this fixes a glitch in UNSW interface */
#define POWROFF 0040000 /* printer has been powered off */
#define ERROR 0100000 /* Error bit set in status register */
#ifdef TRNS
#define MODES (TRNS|CDC|VTAB|FLUSH|FEED|NOEJECT|SIXLPI)
#else
#define MODES (CDC|VTAB|FLUSH|FEED|NOEJECT|SIXLPI)
#endif TRNS
/*
* define characteristics of devices
*/
#define LPF0 (TRNS|CDC|VTAB) /* cdc printer */
#define MAXCOL 136 /* cdc printer */
#define PL 60 /* page length */
#define BMAX 04 /* maximum number of buffers used per device */
int lpages; /* pages printed since last boot (in toto) */
struct lpdev
{
int lpsr;
int lpbuf;
};
struct { int lpuf;}; /* dummy for lpint only */
struct lpst
{
int flag; /* control flags */
int bfree; /* number of buffers unused */
struct buf *bfwd; /* first buffer in chain */
struct buf *blst; /* last buffer in chain */
struct lpdev *lpaddr; /* device register address */
int ejline; /* lines per page (settable) */
unsigned maxcol; /* max cols per line (settable) */
unsigned ocol; /* output column */
unsigned icol; /* input column */
int lino; /* output line */
int lini; /* input line */
unsigned vtcnt; /* count for vertical tabs */
int bc; /* byte count (-ve) */
char *ba; /* next char in buffer */
char fc; /* duplicated char if non-zero */
}
lp0 /* define lp0 */
{
LPF0, /* flags */
BMAX, /* bfree */
0, 0, /* bfwd, blst */
0177514, /* lpaddr */
PL, /* ejline */
MAXCOL, /* maxcol */
0, 0, /* ocol, icol */
0, 0, /* lino, lini */
0, /* vtcnt */
0, 0, /* bc, ba */
0, /* fc */
},
#ifdef TWO_PRINTERS
lp1 /* define lp1 */
{
LPF1, /* flags */
BMAX, /* bfree */
0, 0, /* bfwd, blst */
0160024, /* lpaddr */
PL, /* ejline */
MAXCOL, /* maxcol */
0, 0, /* ocol, icol */
0, 0, /* lino, lini */
0, /* vtcnt */
0, 0, /* bc, ba */
0, /* fc */
},
#endif TWO_PRINTERS
*lp11[NLP] /* define lp11 */
{
&lp0, /* printer 0 */
#ifdef TWO_PRINTERS
&lp1, /* printer 1 */
#endif TWO_PRINTERS
};
#define lperror (!fkword(plp->lpaddr) || plp->lpaddr->lpsr < 0)
lpopen(dev, flag)
{
register struct lpst *plp;
plp = lp11[dev.d_minor];
if(dev.d_minor >= NLP)
{
u.u_error = ENXIO;
return;
}
else if(flag)
{
register mode = FLUSH|ERROR;
if((plp->flag&WOPEN) || lperror)
{
u.u_error = EOPENFAIL;
return;
}
if(plp->flag & TMPNOEJ)
mode =| (NOEJECT | TMPNOEJ);
plp->flag =& ~mode;
plp->flag =| WOPEN;
plp->lpaddr->lpsr =| IENABLE;
plp->icol = plp->ocol = plp->lino = plp->lini = 0;
}
}
lpclose(dev, flag)
{
register struct lpst *plp = lp11[dev.d_minor];
if( plp->flag&WOPEN )
{
/* if final close after write */
spl4();
plp->flag =| CLOSIN;
if( plp->bfwd == 0 )
lpint(dev);
spl0();
}
}
lpwrite(dev)
{
register struct buf *bp;
register struct lpst *plp;
register int n;
plp = lp11[dev.d_minor];
spl4();
while(u.u_count && !u.u_error)
{
while(!plp->bfree)
{
sleep(plp,LPPRI);
}
if( plp->flag & FLUSH )
{
u.u_error = EIO;
break;
}
plp->bfree--;
bp = getblk(NODEV);
bp->av_forw = 0;
spl4();
if( (n = u.u_count) > 512 )
n = 512;
bp->b_wcount = -n;
iomove(bp, 0, n, B_WRITE);
if(!plp->bfwd)
{
plp->bfwd = plp->blst = bp;
#ifdef MAPPED_BUFFERS
plp->ba = b.buff;
#else MAPPED_BUFFERS
plp->ba = bp->b_addr;
#endif MAPPED_BUFFERS
plp->bc = bp->b_wcount;
lpint(dev);
}
else
{
plp->blst->av_forw = bp;
plp->blst = bp;
}
}
spl0();
}
lpint(dev)
{
register struct lpst *plp;
register int *lpa;
#ifdef MAPPED_BUFFERS
int ka5sav = ka5;
#endif MAPPED_BUFFERS
plp = lp11[dev.d_minor];
while(!fkword(plp->lpaddr));
if(plp->lpaddr->lpsr < 0)
{
if((plp->lpaddr->lpsr & POWROFF) && !(plp->flag & POWROFF))
{
plp->flag =| POWROFF;
printf("LP%d POWERED OFF\n", dev);
}
plp->flag =| ERROR;
plp->lpaddr->lpsr =& ~IENABLE;
timeout(lpint, dev, 1*HZ);
return;
}
plp->flag =& ~(ERROR|POWROFF);
plp->lpaddr->lpsr =| IENABLE;
if( plp->bfwd == 0 )
goto fin;
if( plp->flag & FLUSH )
{
register struct buf *bp;
bp = plp->bfwd;
do
{
lpa = bp->av_forw;
brelse(bp);
plp->bfree++;
} while( bp = lpa );
plp->bfwd = 0;
wakeup(plp);
goto fin;
}
lpa = &(plp->lpaddr->lpbuf);
if( plp->vtcnt )
{
lpa->lpuf = '\n';
plp->vtcnt--;
return;
}
#ifdef MAPPED_BUFFERS
bswtch(plp->bfwd);
#endif MAPPED_BUFFERS
loop:
while( (plp->lpaddr->lpsr & READY) && (plp->bc++ < 0) )
{
register int c1;
c1 = (*plp->ba++) & 0377;
if( plp->fc )
{
plp->icol =+ (--c1);
if(plp->fc == '0')
{
if(plp->icol > plp->maxcol)
c1 =- plp->icol - plp->maxcol;
while(c1-- > 0)
lpa->lpuf = '0';
}
plp->fc = 0;
continue;
}
switch( c1 )
{
case 0:
break;
case '\t':
plp->icol = (plp->icol+8) & ~7;
break;
case 0377:
plp->fc = c1 = ' ';
goto dflt;
case 0376:
plp->fc = c1 = '0';
goto dflt;
case 0375:
if( !(plp->flag & NOEJECT))
plp->flag =| (NOEJECT | TMPNOEJ);
break;
case 013:
if( plp->flag & VTAB )
{
if( plp->flag & CDC )
{
lpa->lpuf = 0100103;
}
else
{
plp->vtcnt = plp->ejline - plp->lino + 3;
if(plp->flag & SIXLPI)
plp->vtcnt--;
lpa->lpuf = '\n';
}
plp->icol = plp->ocol = 0;
if(plp->flag & SIXLPI)
c1 = -3;
else
c1 = -4;
plp->lini = plp->lino = c1;
}
break;
case 006: /* kronos eof */
case 022: /* kronos eor */
c1 = 014;
case 014:
case '\n':
if( plp->flag & FEED || plp->lini || plp->ocol )
{
plp->ocol = 0;
plp->lini++;
if( plp->lini >= plp->ejline &&
!(plp->flag & NOEJECT) )
{
c1 = 014;
}
if(c1 == 014)
{
lpa->lpuf = c1;
plp->lini = plp->lino = 0;
lpages++;
}
}
case '\r':
plp->icol = 0;
break;
case 010:
if(plp->icol > 0)
plp->icol--;
break;
case ' ':
plp->icol++;
break;
default:
dflt:
if(plp->lini > plp->lino)
{
if(plp->flag & CDC)
{
c1 = plp->lini - plp->lino;
if(c1 > 3)
c1 = 3;
lpa->lpuf = 0100120 + c1;
plp->lino =+ c1;
}
else
{
plp->vtcnt = plp->lini - plp->lino - 1;
plp->lino = plp->lini;
lpa->lpuf = '\n';
}
plp->fc = 0;
--plp->ba;
--plp->bc;
break;
}
if(plp->icol < plp->ocol)
{
lpa->lpuf = '\r';
plp->ocol = plp->fc = 0;
--plp->ba;
--plp->bc;
break;
}
if(plp->icol < plp->maxcol)
{
while(plp->icol > plp->ocol)
{
lpa->lpuf = ' ';
plp->ocol++;
}
#ifdef TRNS
if( plp->flag & TRNS )
{
switch( c1 )
{
case '{': c1 = '(';
goto esc;
case '}': c1 = ')';
goto esc;
case '`': c1 = '\'';
goto esc;
case '|': c1 = '!';
goto esc;
case '~': c1 = '^';
esc:
lpa->lpuf = c1;
*(--plp->ba) = '-';
--plp->bc;
plp->ocol = 0;
lpa->lpuf = '\r';
continue;
}
}
#endif TRNS
lpa->lpuf = c1;
plp->ocol++;
}
if( ++plp->icol == 0) plp->icol--;
}
}
if(plp->bc >= 0)
{
register struct buf *bp;
bp = plp->bfwd;
plp->bfwd = bp->av_forw;
brelse(bp);
if( !(plp->bfree++))
wakeup(plp);
if(bp = plp->bfwd)
{
#ifndef MAPPED_BUFFERS
plp->ba = bp->b_addr;
#else MAPPED_BUFFERS
plp->ba = b.buff;
bswtch(bp);
#endif MAPPED_BUFFERS
plp->bc = bp->b_wcount;
goto loop;
}
fin:
if( (plp->lpaddr->lpsr & READY) && (plp->flag & CLOSIN) )
{
plp->flag =& ~(WOPEN | CLOSIN);
plp->lpaddr->lpsr = 0;
if( plp->lino || plp->ocol )
plp->lpaddr->lpbuf = 014;
}
}
#ifdef MAPPED_BUFFERS
ka5 = ka5sav;
#endif MAPPED_BUFFERS
}
lpsgtty( dev, v )
register int *v;
{
register struct lpst *plp;
plp = lp11[dev.d_minor];
switch( v )
{
/*
* set
*/
case 0:
v = u.u_arg;
spl4(); /* look out for interrupt */
plp->flag = (*v++ & MODES) | (plp->flag & ~MODES); /* protect status */
spl0();
plp->ejline = *v++;
plp->maxcol = *v++;
return(0);
/*
* get
*/
default:
*v++ = plp->flag;
*v++ = plp->ejline;
*v++ = plp->maxcol;
return(1);
}
}
#ifdef POWER_FAIL
lppowf()
{
register struct lpst *plp;
register i;
for( i = 0; i < NLP; i++)
{
plp = lp11[i];
if( plp->flag & WOPEN)
plp->lpaddr->lpsr =| IENABLE;
}
}
#endif POWER_FAIL