V7addenda/lp.c
/*
* Line printer driver
*
* Notice nonstandard indirection in struct device
*/
#include "sys/param.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/tty.h"
struct device *lp_addr[];
int lp_cnt;
#define LPPRI (PZERO+8)
#define LPLOWAT 40
#define LPHIWAT 100
#define LPMAX 2
struct device {
int lpcsr, lpbuf;
};
struct lp {
struct clist l_outq;
char flag, ind;
int ccc, mcc, mlc;
int line, col;
} lp_dt[LPMAX];
#define OPEN 010
#define CAP 020
#define NOCR 040
#define ASLP 0100
#define FORM 014
lpopen(dev, flag)
{
register unit;
register struct lp *lp;
unit = dev&07;
if (unit >= lp_cnt || unit >= LPMAX ||
(lp = &lp_dt[unit])->flag || lp_addr[unit]->lpcsr <0 ) {
u.u_error = EIO;
return;
}
lp->flag = (dev&077)|OPEN;
lp->ind = 4;
lp->col = 80;
lp->line = 66;
lp_addr[unit]->lpcsr |= IENABLE;
lpoutput(unit, FORM);
}
lpclose(dev)
{
register unit;
unit = dev&07;
lpoutput(unit, FORM);
lp_dt[unit].flag = 0;
}
lpwrite(dev)
{
register unit;
register c;
register struct lp *lp;
unit = dev&07;
lp = &lp_dt[unit];
while (u.u_count) {
spl4();
while(lp->l_outq.c_cc > LPHIWAT) {
lpintr(unit);
lp->flag |= ASLP;
sleep(lp, LPPRI);
}
spl0();
c = fubyte(u.u_base++);
if (c < 0) {
u.u_error = EFAULT;
break;
}
u.u_count--;
lpoutput(unit, c);
}
spl4();
lpintr(unit);
spl0();
}
lpoutput(dev, c)
register dev, c;
{
register struct lp *lp;
lp = &lp_dt[dev];
if(lp->flag&CAP) {
if(c>='a' && c<='z')
c += 'A'-'a'; else
switch(c) {
case '{':
c = '(';
goto esc;
case '}':
c = ')';
goto esc;
case '`':
c = '\'';
goto esc;
case '|':
c = '!';
goto esc;
case '~':
c = '^';
esc:
lpoutput(dev, c);
lp->ccc--;
c = '-';
}
}
switch(c) {
case '\t':
lp->ccc = ((lp->ccc+8-lp->ind) & ~7) + lp->ind;
return;
case '\n':
lp->mlc++;
if(lp->mlc >= lp->line )
c = FORM;
case FORM:
lp->mcc = 0;
if (lp->mlc) {
putc(c, &lp->l_outq);
if(c == FORM)
lp->mlc = 0;
}
case '\r':
lp->ccc = lp->ind;
spl4();
lpintr(dev);
spl0();
return;
case 010:
if(lp->ccc > lp->ind)
lp->ccc--;
return;
case ' ':
lp->ccc++;
return;
default:
if(lp->ccc < lp->mcc) {
if (lp->flag&NOCR) {
lp->ccc++;
return;
}
putc('\r', &lp->l_outq);
lp->mcc = 0;
}
if(lp->ccc < lp->col) {
while(lp->ccc > lp->mcc) {
putc(' ', &lp->l_outq);
lp->mcc++;
}
putc(c, &lp->l_outq);
lp->mcc++;
}
lp->ccc++;
}
}
lpintr(dev)
register dev;
{
register struct lp *lp;
register c;
lp = &lp_dt[dev];
while (lp_addr[dev]->lpcsr&DONE && (c = getc(&lp->l_outq)) >= 0)
lp_addr[dev]->lpbuf = c;
if (lp->l_outq.c_cc <= LPLOWAT && lp->flag&ASLP) {
lp->flag &= ~ASLP;
wakeup(lp);
}
}
struct { char lobyte, hibyte;};
lpsgtty(dev, v)
register *v;
{
register struct lp *lp;
lp = &lp_dt[dev&07];
if (v) {
v->lobyte = lp->flag;
v->hibyte = lp->ind;
v[1] = lp->line;
v[2] = lp->col;
} else {
lp->flag = (u.u_arg[0].lobyte&077)|OPEN;
lp->ind = u.u_arg[0].hibyte&017;
lp->line = u.u_arg[1];
lp->col = u.u_arg[2];
}
}