# /* * VERSATEC printer/plotter driver * * for the VERSATEC driven by the 9600bd DL11 attached to the 'switch box' * * BASSER DEPT. OF COMPUTER SCIENCE - april '76 - PRDL */ #include "../defines.h" #include "../param.h" #include "../user.h" #include "dl11.h" /* #define CYBER /* deal with Cyber printer control */ #define VSPRI 9 /* 'sleep' constants */ #define VSLWAT (PLOTLENGTH*2) #define VSHWAT (PLOTLENGTH*3) #define START_TIMEOUT (10*HZ) /* wait 10 secs for response from Versatec */ #define VSDELAY 5 /* minimum length line */ struct v { /* character Q header */ int cc; /* count */ int cf; /* first */ int cl; /* last */ int flag; /* state flags */ int vcol; /* accumulated horizontal movement */ int col; /* real horizontal movement */ int v_nl; /* accumulated vertical movement */ int nl; /* real vertical movement */ int spaced_out; #ifdef CYBER int c_rep; /* char to be repeated */ #endif } vs; #define plotposn col #define FLUSH 01 /* flag bits */ #define EJECT 02 #define IND 04 #define RUN 010 #define ASLEEP 020 #define PLOT 040 #define OPEN 0100 #define CLOSE 0200 #define MODES (IND|EJECT) /* special chars * * those chars that cause delays on versatec have bit 8 set */ #define DO_EOT 0204 #define FORM 014 #define DC1 021 #define DO_LF 0212 /* real line feed */ #define DO_FORM 0214 /* real form feed */ #define DO_CR 0215 /* used to test versatec ready */ #define DO_DC1 0221 /* signifies start of plot line */ #define DO_SPAC 0300 /* used to concatenate spaces */ #define LENGTH 54 /* line length of versatec page */ #define MAXCOL 132 /* char width of versatec print line */ #define PLOTLENGTH 128 /* bytes per versatec plot line */ #ifdef CYBER /* recognise special chars */ #define VT 013 #define REP_S 0377 /* repeat space */ #define REP_0 0376 /* repeat '0' */ #define KRON_EOF 006 #define KRON_EOR 022 #endif #define set =| #define reset =& ~ /* * open device */ vsopen ( dev , flag ) { register struct v *vp = &vs; register struct timout *tp; extern struct timout *timeout(); extern wakeup(); extern vsrint(), vswint(); SPLVS(); if ( dl11[VS] ) { /* exclusive use */ fail: u.u_error = EOPENFAIL; spl0(); return; } vp->flag = 0; dl11[VS] = LPR; dl11v[VS].rintad = &vsrint; dl11v[VS].wintad = &vswint; if ( vp->cc ) while ( getc( vp ) >= 0 ); vp->col = 0; vscanon( DO_CR ); if ( tp = timeout( wakeup, vp, START_TIMEOUT ) ) { sleep( vp, -1 ); if ( untimeout( tp, wakeup, vp ) ) goto out; } VSADDR->dlrs = 0; dl11[VS] = 0; goto fail; out: vp->flag = (OPEN|EJECT|IND); vp->vcol = 8; /* margin */ vp->v_nl = 0; vp->spaced_out = 0; #ifdef CYBER vp->c_rep = 0; #endif vscanon( FORM ); spl0(); } /* * set/read parameters for printing and give device characteristics * * first argument has significance as follows * bit 01: flush buffer * bit 02: eject last page on close * bit 04: indent all lines to first tab position * second argument is length of page * third argument is width of page */ vssgtty( dev , av ) int *av; { register struct v *vp; register *f; if ( f = av ) { *f++ = vs.flag & MODES; *f++ = LENGTH; *f++ = MAXCOL; return( 1 ); } vp = &vs; f = &vs.flag; *f reset MODES; SPLVS(); if ( u.u_arg[0] & FLUSH ) { while ( getc( vp ) >= 0 ); vscanon( DO_EOT ); }else while ( vp->cc ) { *f set FLUSH; sleep( vp , VSPRI ); *f reset FLUSH; } spl0(); *f set (u.u_arg[0] & MODES); return( 0 ); } /* * close device */ vsclose ( dev ) { register struct v *vp; register struct timout *tp; extern struct timout *timeout(); extern wakeup(); vp = &vs; vp->flag reset OPEN; SPLVS(); if ( vp->flag & RUN ) { if ( tp = timeout( wakeup, vp, HZ ) ) sleep( vp , -1 ); if ( !untimeout( tp, wakeup, vp ) ) { spl0(); goto out; } } spl0(); vp->flag reset PLOT; if ( vp->flag & EJECT ) { vp->flag set CLOSE; vscanon( DO_FORM ); return; } out: dl11[VS] = 0; VSADDR->dlrs = 0; } /* * write to device */ vswrite() { register c; while (( c = cpass() ) >= 0 ) vscanon( c & 0177 ); } /* * plot on device */ vsplot () { register c; vs.flag set PLOT; while (( c = cpass() )>= 0 ) vsoutput(c); } /* * put char in device Q, & deal with special chars. */ vscanon ( c ) register c; { register struct v *vp; register x; vp = &vs; #ifdef CYBER if ( x = vp->c_rep ) { vp->c_rep = 0; if ( x == '0' ) do vscanon( x ); while ( --c ); else vp->vcol =+ c; /* spaces */ return; } #endif if ( c > ' ' && !(c & 0200) ) { while ( vp->v_nl >= LENGTH ) vscanon( DO_FORM ); /* do page feeds */ while ( vp->v_nl > vp->nl ) vscanon( DO_LF ); /* do line feeds */ if ( vp->vcol++ < MAXCOL ) { if ((x = vp->vcol - ++vp->col) > 0) { /* do horizontal movement */ while ( --x & 0300 ) { vsoutput( DO_SPAC|077 ); x =- 077; } vsoutput( DO_SPAC | x ); vp->col = vp->vcol; } vsoutput( c ); } }else if ( c == ' ' ) vp->vcol++; /* accumulate horiz. movement */ else switch ( c ) { case '\n': vp->v_nl++; /* accumulate vertical movement */ case '\r': vp->vcol = ( vp->flag & IND ? 8 : 0 ); return; case '\t': vp->vcol =| 7; vp->vcol++; return; case '\b': if ( --vp->vcol < 0 ) vp->vcol = 0; return; #ifdef CYBER case VT: vp->v_nl =| 7; vp->v_nl++; return; case REP_S: vp->c_rep = ' '; return; case REP_0: vp->c_rep = '0'; return; case KRON_EOF: case KRON_EOR: #endif case FORM: if ( vp->nl == 0 ) return; /* if top of page already */ c = DO_FORM; case DO_FORM: while ( (vp->v_nl =- LENGTH) >= LENGTH ); /* concatenate multiple blank pages */ if ( vp->v_nl < 0 ) vp->v_nl = 0; vp->nl = 0; goto newline; case DO_LF: vp->nl++; case DO_EOT: newline: if ((x = VSDELAY - vp->col) > 0) vsoutput( DO_SPAC|x ); case DO_CR: vp->col = 0; vsoutput ( c ); return; } } /* * put chars on device Q up to high water mark */ vsoutput ( c ) { register struct v *vp; extern lbolt; vp = &vs; while ( putc ( c , vp ) ) sleep( &lbolt , VSPRI ); if (( vp->flag & RUN ) == 0 ) { vp->flag set RUN; SPLVS(); vsrint(); spl0(); } if ( vp->cc >= VSHWAT ) { vp->flag set ASLEEP; sleep ( vp , VSPRI ); } } /* * print 1 char ( called @ interrupt time ) */ vswint() { register struct v *vp; register c, x; vp = &vs; if ( vp->spaced_out ) { vp->spaced_out--; VSADDR->dlwb = ' '; return; } if ( ( c = getc(vp) ) >= 0 ) { if ( vp->flag & PLOT ) { if ( vp->plotposn ) { plot: /* plot a byte */ if ( --vp->plotposn == 0 ) goto wait; }else { VSADDR->dlwb = DC1; vp->plotposn = PLOTLENGTH-1; while ( !(VSADDR->dlws & DONE) ); } }else if ( c & 0200 ) { if ( c & 0100 ) { vp->spaced_out = c & 077; c = ' '; }else { wait: /* wait for ready interrupt */ VSADDR->dlws reset IENABLE; VSADDR->dlrs set IENABLE; x = VSADDR->dlrb; /* clear buffer */ if ( vp->cc <= VSLWAT && vp->flag & ASLEEP ) { vp->flag reset ASLEEP; wakeup(vp); } } } VSADDR->dlwb = c; }else { x = vp->flag; vp->flag =& ~(RUN|ASLEEP); if ( (x & (OPEN|FLUSH)) != OPEN ) { if ( x & PLOT && vp->plotposn ) goto plot; if ( x & CLOSE ) dl11[VS] = 0; else wakeup( vp ); } else if ( x & ASLEEP ) wakeup( vp ); VSADDR->dlws reset IENABLE; } } /* * read interrupts here ( generated by ready flag in Versatec ) */ vsrint() { VSADDR->dlrs reset IENABLE; VSADDR->dlws set IENABLE; vswint(); }