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