/* * Line printer driver */ #include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "@(#)lpa.c 3.2 14:59:53 - 83/04/11 "; #endif SCCS_ID #include "../h/param.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/tty.h" /* Configuration */ #define LPPRI 75 /* line printer wakeup priority */ #define LPLWAT 300 /* line printer low water mark */ #define LPHWAT 1000 /* line printer high water mark */ #define LPWIDTH 131 /* page width (not 132, as lp auto prints on 132nd char */ #define LPDEPTH 0 /* lines per page */ extern char lpaaddr; /* printer address */ struct { /* info about the printer */ struct clist outq; /* output char queue */ char flag; /* current mode */ char state; /* internal status */ short mcc; /* actual column posn */ short ccc; /* logical column posn */ short mlc; /* curr line # */ short mxc; /* max line width */ short mxl; /* max page depth */ } lpa; /* Printer status & commands */ #define ENABLE 0x40 #define DISARM 0xc0 #define NO_PAPER 0x40 #define INTLOCK 0x10 #define DU 0x01 #define P_WASTE ECHO /* if on, printer wastes paper */ #define IND CRMOD /* if on, lines are indented 8 spaces */ #define INITFLAGS (P_WASTE) /* Default flags */ #define FORM 0x0c #define VTAB 0x0b /* * open - line printer */ lpaopen(dev, flag) { if(lpa.state&ISOPEN || (ss(lpaaddr)&(NO_PAPER|INTLOCK|DU))) { u.u_error = EIO; return; } trace(01<<8,"lpaopen",0); lpa.state = ISOPEN; lpa.flag = INITFLAGS; if (lpa.mxc == 0) { lpa.mxc = LPWIDTH; lpa.mxl = LPDEPTH; } oc(lpaaddr, ENABLE); lpacanon(FORM); } /* * close - line printer */ lpaclose(dev, flag) { lpacanon(FORM); trace(01<<8,"lpaclose",0); lpa.state = 0; } /* * user write to line printer */ lpawrite() { register c; while ((c=cpass()) >= 0) lpacanon(c); } /* * lpacanon - character transformations */ lpacanon(ac) { register char c; register char *p; c = ac; if (c == '_') c |= 0x80; /* * Interdata line printer i/face * turns x'5f' into x'3c' ..... * * But it isn't smart enough to * recognize x'df', fortunately. */ if (lpa.flag & RAW) { lpaoutput(c); return; } if (lpa.flag & LCASE) { /* Uppercase-only printer */ if (c>='a' && c<='z') c += 'A'-'a'; else { p = "({)}!|^~'`"; while (*p++) if (c == *p++) { lpacanon(p[-2]); lpa.ccc--; c = '-'; break; } } } switch(c&0x7f) { case '\t': lpa.ccc = (lpa.ccc + 8) & ~7; return; case FORM: case '\n': if(lpa.mcc != 0 || lpa.mlc != 0 || lpa.flag & P_WASTE) { if(lpa.mcc) { lpaoutput('\r'); /* cause line to print */ } lpa.mlc++; if(lpa.mlc > lpa.mxl && lpa.mxl) c = FORM; lpaoutput(c); if (c == FORM) lpa.mlc = 0; lpa.mcc = 0; } /* now fall through to '\r' code */ case '\r': lpa.ccc = 0; if (lpa.flag & IND) lpa.ccc = 8; return; case '\b': if (lpa.ccc > 0) lpa.ccc--; return; case 0x07: lpaoutput(c); /* ring bell, no char advance */ return; case ' ': lpa.ccc++; return; case VTAB: if(lpa.mcc) lpacanon('\n'); while(lpa.mlc & 7) lpacanon('\n'); return; default: if ((c & 0x7f) < 0x20) /* non printing - ignore */ return; if(lpa.ccc < lpa.mcc) { lpaoutput('\r'); /* cause overprint */ lpa.mcc = 0; } if (lpa.ccc < lpa.mxc) { while(lpa.ccc > lpa.mcc) { lpaoutput(' '); lpa.mcc++; } lpaoutput(c); lpa.mcc++; } lpa.ccc++; } } /* * start transmission to printer */ lpastart() { register c; register s; trace(02<<8,"lpastart",lpaaddr); trace(01<<8,"lpastat",ss(lpaaddr)); while( (s = ss(lpaaddr)) == 0 && (c = getc(&lpa.outq)) >= 0 ) { trace(010<<8,"lpachar",c); wd(lpaaddr, c); } trace(01<<8,"lpastat",s); } /* * line printer interrupt */ lpaint(dev, stat) { trace(02<<8,"lpaint",stat); /*** if(stat & DU) printf("\nline printer offline\n"); else if (stat & NO_PAPER) printf("\nline printer paper out\n"); else { ***/ if(!(stat & (DU|NO_PAPER))) { lpastart(); if(lpa.outq.c_cc <= LPLWAT && lpa.state & ASLEEP) { trace(04<<8,"lpawakeup",lpa.outq.c_cc); lpa.state &= ~ASLEEP; wakeup(&lpa); } } } /* * write a character to line printer */ lpaoutput(c) { trace(02<<8,"lpaoutput",c); spl4(); while(lpa.outq.c_cc >= LPHWAT) { lpa.state |= ASLEEP; trace(04<<8,"lpasleep",lpa.outq.c_cc); sleep(&lpa, LPPRI); } putc(c, &lpa.outq); lpastart(); spl0(); } /* * ioctl: * allow several line printer attributes to be dynamically altered */ lpaioctl(dev, cmd, addr, flag) caddr_t addr; { struct ttiocb iocb; #ifdef SVC6 struct v6iocb ioc6; #endif switch (cmd) { case TIOCSETP: case TIOCSETN: #ifdef SVC6 if (u.u_svc6) { if (copyin(addr, (caddr_t)&ioc6, sizeof(ioc6))) { u.u_error = EFAULT; break; } lpa.mxc = ioc6.ioc6_erase; lpa.mxl = ioc6.ioc6_kill; lpa.flag = ioc6.ioc6_flags; break; } #endif if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { u.u_error = EFAULT; break; } lpa.mxc = iocb.ioc_erase; lpa.mxl = iocb.ioc_kill; lpa.flag = iocb.ioc_flags; break; case TIOCGETP: #ifdef SVC6 if (u.u_svc6) { ioc6.ioc6_erase = lpa.mxc; ioc6.ioc6_kill = lpa.mxl; ioc6.ioc6_flags = lpa.flag; if (copyout((caddr_t)&ioc6, addr, sizeof(ioc6))) u.u_error = EFAULT; break; } #endif iocb.ioc_erase = lpa.mxc; iocb.ioc_kill = lpa.mxl; iocb.ioc_flags = lpa.flag; if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) u.u_error = EFAULT; break; } }