/* * Line printer driver */ #include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "@(#)lp.c 3.5 18:40:10 - 83/03/01 "; #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 lpaddr; /* 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 */ } lp; /* 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 */ lpopen(dev, flag) { if(lp.state&ISOPEN || (ss(lpaddr)&(NO_PAPER|INTLOCK|DU))) { u.u_error = EIO; return; } trace(01<<8,"lpopen",0); lp.state = ISOPEN; lp.flag = INITFLAGS; if (lp.mxc == 0) { lp.mxc = LPWIDTH; lp.mxl = LPDEPTH; } oc(lpaddr, ENABLE); lpcanon(FORM); } /* * close - line printer */ lpclose(dev, flag) { lpcanon(FORM); trace(01<<8,"lpclose",0); lp.state = 0; } /* * user write to line printer */ lpwrite() { register c; while ((c=cpass()) >= 0) lpcanon(c); } /* * lpcanon - character transformations */ lpcanon(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 (lp.flag & RAW) { lpoutput(c); return; } if (lp.flag & LCASE) { /* Uppercase-only printer */ if (c>='a' && c<='z') c += 'A'-'a'; else { p = "({)}!|^~'`"; while (*p++) if (c == *p++) { lpcanon(p[-2]); lp.ccc--; c = '-'; break; } } } switch(c&0x7f) { case '\t': lp.ccc = (lp.ccc + 8) & ~7; return; case FORM: case '\n': if(lp.mcc != 0 || lp.mlc != 0 || lp.flag & P_WASTE) { if(lp.mcc) { lpoutput('\r'); /* cause line to print */ } lp.mlc++; if(lp.mlc > lp.mxl && lp.mxl) c = FORM; lpoutput(c); if (c == FORM) lp.mlc = 0; lp.mcc = 0; } /* now fall through to '\r' code */ case '\r': lp.ccc = 0; if (lp.flag & IND) lp.ccc = 8; return; case '\b': if (lp.ccc > 0) lp.ccc--; return; case 0x07: lpoutput(c); /* ring bell, no char advance */ return; case ' ': lp.ccc++; return; case VTAB: if(lp.mcc) lpcanon('\n'); while(lp.mlc & 7) lpcanon('\n'); return; default: if ((c & 0x7f) < 0x20) /* non printing - ignore */ return; if(lp.ccc < lp.mcc) { lpoutput('\r'); /* cause overprint */ lp.mcc = 0; } if (lp.ccc < lp.mxc) { while(lp.ccc > lp.mcc) { lpoutput(' '); lp.mcc++; } lpoutput(c); lp.mcc++; } lp.ccc++; } } /* * start transmission to printer */ lpstart() { register c; register s; trace(02<<8,"lpstart",lpaddr); trace(01<<8,"lpstat",ss(lpaddr)); while( (s = ss(lpaddr)) == 0 && (c = getc(&lp.outq)) >= 0 ) { trace(010<<8,"lpchar",c); wd(lpaddr, c); } trace(01<<8,"lpstat",s); } /* * line printer interrupt */ lpint(dev, stat) { trace(02<<8,"lpint",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))) { lpstart(); if(lp.outq.c_cc <= LPLWAT && lp.state & ASLEEP) { trace(04<<8,"lpwakeup",lp.outq.c_cc); lp.state &= ~ASLEEP; wakeup(&lp); } } } /* * write a character to line printer */ lpoutput(c) { trace(02<<8,"lpoutput",c); spl4(); while(lp.outq.c_cc >= LPHWAT) { lp.state |= ASLEEP; trace(04<<8,"lpsleep",lp.outq.c_cc); sleep(&lp, LPPRI); } putc(c, &lp.outq); lpstart(); spl0(); } /* * ioctl: * allow several line printer attributes to be dynamically altered */ lpioctl(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; } lp.mxc = ioc6.ioc6_erase; lp.mxl = ioc6.ioc6_kill; lp.flag = ioc6.ioc6_flags; break; } #endif if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { u.u_error = EFAULT; break; } lp.mxc = iocb.ioc_erase; lp.mxl = iocb.ioc_kill; lp.flag = iocb.ioc_flags; break; case TIOCGETP: #ifdef SVC6 if (u.u_svc6) { ioc6.ioc6_erase = lp.mxc; ioc6.ioc6_kill = lp.mxl; ioc6.ioc6_flags = lp.flag; if (copyout((caddr_t)&ioc6, addr, sizeof(ioc6))) u.u_error = EFAULT; break; } #endif iocb.ioc_erase = lp.mxc; iocb.ioc_kill = lp.mxl; iocb.ioc_flags = lp.flag; if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) u.u_error = EFAULT; break; } }