# /* * CD-11 Card Reader Driver * * History: written by Steve Holmgren (CAC) ? * Mods by R. Balocca (CAC) 77Nov30 */ #include "../../h/param.h" #include "../../h/conf.h" #include "../../h/user.h" #define CDADDR 0772460 #define GO 01 #define DATAPACK 02 #define HOPCHECK 04 #define ONLINE 010 /* set by the TRANSITION to online */ #define XBA 060 #define IENABLE 0100 #define READY 0200 #define POWCLR 0400 #define NOMEM 01000 #define DATALATE 02000 #define DATAERR 04000 #define REREAD 07000 /* any of these bits, and no data came in */ #define OFFLINE 010000 #define NOTUSED 020000 /* hardware eof button option */ #define RDRCHECK 040000 #define ERROR 0100000 /* * these defines are on cd.cdstate */ #define CLOSED 0 #define CD_OPEN 1 #define EOFSEEN 2 #define CDSIZE 80 #define EOFCHAR 052 #define CDPRI 10 struct { int cdcsr; int cdcc; int cdba; int cddb; }; struct { char *curcol; char *endcol; char cdstate; char cdbuf[CDSIZE + 1]; } cd; /* * Note the sleep in this start routine. This does not * follow the `philosophy' of Unix xxstart routines. * The reason this works is because there is no concurrency * in this driver. If double buffering or some such should * be used, this sleep should be moved out of here. */ cdstart() { CDADDR -> cdcsr =| IENABLE; /* N.B.: wait for online */ while( CDADDR->cdcsr&OFFLINE ) sleep( &cd, CDPRI ); CDADDR -> cdba = &cd.cdbuf [0]; /* load mem addr reg */ CDADDR -> cdcc = -CDSIZE; /* load col count reg*/ CDADDR -> cdcsr =| DATAPACK|GO; /* packed format and go */ } cdopen(dev,flag) { if( cd.cdstate != CLOSED ) { /* still open */ u.u_error = ENXIO; return; } cd.cdstate = CD_OPEN; cd.curcol = cd.endcol = 0; CDADDR -> cdcsr =| POWCLR; /* reset reader */ } cdclose(dev,flag) { CDADDR -> cdcsr =| POWCLR; /* reset reader */ cd.cdstate = CLOSED; } /* * This routine is inverted: there probably should be a routine for * reading a char and cdread should be something like: * * while( (c=getch())>0 && passc(c)>0); * * --or at least this is my style... */ cdread() { register char *curp; register char *endp; if(cd.cdstate == EOFSEEN) return; curp = cd.curcol; endp = cd.endcol; do { /* is this the end of this buf */ if( curp == endp ) { endp = cdget(); /* get another card */ /* check for eof */ curp = &cd.cdbuf[0]; if( curp == endp ) /* indicates EOFSEEN */ return; } } while( passc( *curp++ ) >= 0 ); /* reset pointers for next time in */ cd.curcol = curp; cd.endcol = endp; } cdget() { register char * p; for(;;) { cdclear(); spl4(); cdstart(); while( (CDADDR->cdcsr&READY) == 0 ) sleep( &cd, CDPRI ); /* wait for card */ spl0(); /* ^^ we apparantly can get an interrupt due to * transition to online at this point. Does * my solution of putting cd_online() in cdstart * work (and fix this?)? */ if( CDADDR->cdcsr >= 0 ) /* Error free? */ return cdtran(); else { if( CDADDR->cdcsr & REREAD ) { printf("Reread last card\n"); } else { p = cdtran(); if(cd.cdstate == EOFSEEN) return p; } printf("CD %o %o\n",CDADDR->cdcsr,CDADDR->cdba); } } } /* * This routine should perhaps use the queue stuff and create a canonical * queue. This would speed the reader up (essentially multi-buffering would * be possible). It would however mean that it would take more cpu * to handle the card reader... (But it would be charged to the user, on the * Illinois system... Oh, hell, it isn't worth it. */ cdtran() { register char *endp; register char *startp; startp = &cd.cdbuf[0]; /* strip off trailing blanks */ for(endp = startp+80; *--endp == 0 && endp >= startp; ); if(endp == startp && *startp == EOFCHAR) { cd.cdstate = EOFSEEN; return startp; } /* translate characters */ while( startp <= endp ) *startp++ = cdascii( *startp ); *startp++ = '\n'; return startp; /* stick in a newline */ } /* yes fans this really is the interrupt */ cdint() { wakeup (&cd); } char cdtab[] { ' ' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,' ' ,':' ,'#' ,'@' ,'\'' ,'=' ,'"' ,'9' ,'0' ,'/' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y' ,' ' ,']' ,',' ,'%' ,'_' ,'>' ,'?' ,'Z' ,'-' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,' ' ,'!' ,'$' ,'*' ,')' ,';' ,'\\' ,'R' ,'&' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,'G' ,'H' ,' ' ,'[' ,'.' ,'<' ,'(' ,'+' ,'|' ,'I' }; /* * This anonymous piece of magic converts from hollerith to * ascii. Note that it does not use the full code: no lower * case or ascii compatible control characters (i.e. vt, nl, * etc.) */ cdascii(c) char c; { register c1, c2; c1 = c & 0377; if (c1>=0200) c1 =- 040; c2 = c1; while ((c2 =- 040) >= 0) c1 =- 017; if (c1 >= sizeof cdtab) return ' '; else return cdtab[c1]; } cdclear() { register char * p; for(p = &cd.cdbuf[0]; p<&cd.cdbuf[CDSIZE+1]; ) *p++ = 0; }