# /* * Genisco display driver * * Bruce Borden 4-Sep-77 * VTUNIX Modifications */ #include "../h/param.h" #include "../h/conf.h" #include "../h/buf.h" #include "../h/user.h" #include "../h/old_tty.h" #include "../h/proc.h" /* #define GNTTTY 1 /* define for v-terminal driver */ #define GNRAND 1 /* define for Rand Genisco */ /* #define GNHIRES 1 /* define for high-resolution config */ /* #define GNNOSC 1 /* define for NOSC Genisco */ /* #define RANDEBUG 1 /* horrible kludge for debugging */ struct { int gnopen; /* open count */ char *gnbp; /* buffer pointer */ char *gnbuf; /* buffer data area */ char *gnenbuf; /* room for one more defn */ char gnpc; /* program counter of pgp (saved during dump) */ char gnstate; /* see states below */ } gn; /* gnstate flags */ #define BUSY 01 /* Buffer busy flag */ #define WAITING 02 /* Someone waiting for the buffer */ #define GNTIO 04 /* io in progress from term device */ /* external page device registers */ struct { int noop; int strt; int clr; int iopls; int doc; int dob; int doa; int nio; }; #define GEN 0167730 /* 0167750 for HI-RES B/W */ #ifdef GNNOSC #ifdef GNHIRES #define GEN 0167750 #endif #endif #define GNPRI 1 /* sleep priority - pretty high */ gnopen(dev) { gn.gnopen++; if(gn.gnbp == 0) { gn.gnbp = getblk(NODEV); gn.gnbuf = gn.gnbp->b_addr; gn.gnenbuf = &gn.gnbuf[512-26]; /* 24 chars needed for defn */ } /* so have 2 for slop */ } gnclose(dev) { if(--gn.gnopen == 0) { gn.gnstate = 0; if(gn.gnbp != 0) { #ifdef BUFMOD brelse(gn.gnbp,&bfreelist); #endif #ifndef BUFMOD brelse(gn.gnbp); #endif BUFMOD gn.gnbp = 0; } } } /* Returns at Priority Level 5 with Genisco BUFFER not busy */ /* but with state flagged buffer BUSY */ gnwait() { spl5(); while (gn.gnstate&BUSY) { gn.gnstate =| WAITING; sleep(gn.gnbp,GNPRI); /* wait on the buffer */ } gn.gnstate =& ~WAITING; gn.gnstate =| BUSY; /* spl0(); */ } gnint() { GEN->nio = 0; /* ack the interrupt, i hope */ GEN->clr++; #ifdef GNTTTY if (gn.gnstate&GNTIO) { gn.gnstate =& ~(GNTIO|BUSY); gntstart(); } else #endif wakeup(&gn); } gnread(dev) { register c, tc, n; switch(dev.d_minor) { case 0: /* dump pgp memory */ c = u.u_count; if(u.u_offset[1] + u.u_count >= 512) { if(u.u_offset[1] >= 512) return; /* eof */ c = 512-u.u_offset[1]; } gnwait(); /* Returns at level 5 */ gn.gnpc = GEN->dob.hibyte & 0377; /* save the pgp pc */ GEN->noop++; GEN->doa = (gn.gnbuf>>1)&077777; /* address */ GEN->noop++; GEN->dob = -256; /* word count */ GEN->clr++; /* set direction */ GEN->doc = 0; /* address */ GEN->clr++; /* start it */ sleep(&gn, GNPRI); /* wait for completion */ if (GEN->dob != 0) u.u_error = EIO; GEN->doc = gn.gnpc; /* restore the pgp pc */ GEN->noop++; spl0(); iomove(gn.gnbp, u.u_offset[1], c, B_READ); break; case 1: /* read from pgp */ gnwait(); while(u.u_count) { tc = c = min(u.u_count,512); if (c&01) tc++; GEN->doa = (gn.gnbuf>>1)&077777; GEN->clr++; GEN->dob = -(tc>>1); GEN->strt++; /* start the pgp */ sleep(&gn, GNPRI); /* wait for completion */ /* resid count */ if (n = GEN->dob.lobyte) c = tc + (n|0177400) << 1; iomove(gn.gnbp, 0, c, B_READ); if (n) break; } } spl0(); gn.gnstate =& ~BUSY; /* Buffer no longer busy */ #ifdef GNTTTY gntstart(); /* start term i/o if needed */ #endif if((gn.gnstate&(WAITING|BUSY)) == WAITING) wakeup(gn.gnbp); /* wake them up */ } gnwrite(dev) { register tc, c, n; switch(dev.d_minor) { case 0: /* load */ c = u.u_count; if(c <= 0 || u.u_offset[1] >= 512) return; if(u.u_offset[1] + c > 512) c = 512 - u.u_offset[1]; n = u.u_offset[1]; gnwait(); iomove(gn.gnbp,u.u_offset[1],c,B_WRITE); /* Handle odd boundaries and counts */ if (n&01) { c++; gn.gnbuf[--n] = '\0'; } if ((n+c)&01) gn.gnbuf[n + c++] = '\0'; GEN->doa = ((gn.gnbuf+n)>>1)&077777; GEN->iopls++; GEN->dob = -(c>>1); GEN->noop++; GEN->doc = n>>1; GEN->clr++; /* start it */ sleep(&gn, GNPRI); /* wait for completion */ if (GEN->dob != 0) u.u_error = EIO; break; case 1: /* write */ gnwait(); while(u.u_count) { tc = c = min(u.u_count,512); iomove(gn.gnbp,0,c,B_WRITE); if (c&01) /* If count is odd, pad with null */ gn.gnbuf[tc++] = '\0'; GEN->doa = (gn.gnbuf>>1)&077777; GEN->iopls++; /* set write */ GEN->dob = -(tc>>1); GEN->strt = 0; sleep(&gn, GNPRI); /* wait for completion */ n = GEN->dob.lobyte; /* printf ("n = %d ucount = %d\n",n,u.u_count); */ if (n) { u.u_count =- (((n|0177400)<<1) + (c&01)); break; } } } spl0(); gn.gnstate =& ~BUSY; /* Buffer no longer busy */ #ifdef GNTTTY gntstart(); /* start term i/o if needed */ #endif /* if anyone wants the buf */ if((gn.gnstate&(WAITING|BUSY)) == WAITING) wakeup(gn.gnbp); /* wake them up */ } gnsgty(dev,v) int *v; { if(v) { /* gtty */ v[0] = 0; v[1] = GEN->doc; GEN->noop++; v[2] = GEN->dob.hibyte & 0377; GEN->noop++; return; } switch(u.u_arg[0]) { case 0100001: /* start */ if(u.u_arg[2].hibyte) GEN->nio++; /* bad addr - no set */ else GEN->doc = u.u_arg[2]; GEN->strt++; return; case 0100002: /* stop or single step */ GEN->nio = 0; GEN->iopls++; return; } u.u_error = EINVAL; /* bad argument */ } #ifdef GNTTTY /* Genisco Virtual Terminal Interface */ /************ Declarations for terminal devices *************/ #define NGNWINS 16 /* # of windows pgp can handle */ #ifdef GNHIRES #define GNCWIDTH 12 /* Width of Genisco characters */ #define GNCHEIGHT 24 /* Height of Genisco characters */ #endif #ifndef GNHIRES #define GNCWIDTH 6 /* Width of Genisco characters */ #define GNCHEIGHT 12 /* Height of Genisco characters */ #endif #define GNFLAG 0200 /* Flag char for Genisco escapes */ #define GNSETWIN 0176 /* Genisco set window command is */ /* GNFLAG followed by GNSETWIN */ #define HISPEED 14 /* use OPTIONA as speed */ #define GNTLINES 42 #define GNTCOLS 85 #define GNQUANTA 50 /* Num chars output per window */ #ifdef GNNOSC /* NOSC defns *********************/ #define NGNCRT 3 /* Number of Genisco CRTs on sys */ int gnplanes[NGNCRT] { 07, 070, 0700 } ; #endif /************/ #ifdef RANDEBUG /* debug defns *********************/ #define NGNCRT 3 /* Number of Genisco CRTs on sys */ int gnplanes[NGNCRT] { 01, 02, 04 } ; #endif /************/ #ifdef GNRAND /* RAND defns *********************/ #define NGNCRT 1 /* Number of Genisco CRTs on sys */ #ifdef GNHIRES int gnplanes[NGNCRT] { 017 } ; #endif #ifndef GNHIRES int gnplanes[NGNCRT] { 007 } ; #endif #endif /************/ struct tty gnt11[NGNCRT]; char gntmap[NGNWINS]; extern struct vterm vt_structures[]; /************ End declarations for terminal devices *********/ gntopen(dev, flag) { register struct tty *tp; register struct vterm *vt; extern gntstart(), gntwmap(); if(dev.d_minor >= NGNCRT) { u.u_error = ENXIO; return; } tp = &gnt11[dev.d_minor]; if((tp->t_state&ISOPEN) == 0) { tp->t_state = ISOPEN|CARR_ON|SSTART; tp->t_flags = CRMOD; tp->t_addr = gntstart; tp->t_dev = dev; tp->t_speed = HISPEED | (HISPEED<<8); gnopen(-1); /* Get a sys buffer if needed */ if(vt_open(tp)) /* turn into a vt */ return; vt = tp->t_vterm; if(gntwmap(vt)) { u.u_error = ENOSPC; return; } vt->v_curw.w_lrhc.integ = vt->v_maxw.w_lrhc.integ = ((GNTLINES-1)<<8)|(GNTCOLS-1); vt->v_flags =| LEVEL8; /* 8-Bit Data Path flag */ vt->v_flags =& ~VTLOCK; /* Not KBD locked! */ vt->v_caddr = gntwmap; } } gntclose(dev) { register struct tty *tp; tp = &gnt11[dev.d_minor]; tp->t_state = 0; gnwait(); /* wait for buf not busy */ gn.gnstate =& ~BUSY; /* don't really want the buf at all */ spl0(); vt_ttclose(tp); gnclose(-1); /* just don't want this to give up */ /* active buffer */ } gntwrite(dev) { ttwrite(gnt11[dev.d_minor].t_vterm); } gntread(dev) { ttread(gnt11[dev.d_minor].t_vterm); } gntsgtty(dev, v) { register struct tty *tp; tp = &gnt11[dev.d_minor]; if(vt_ttsgtty(tp->t_vterm, v) == 0) tp->t_flags =& ~(NLDELAY|TBDELAY|CRDELAY|VTDELAY); } gntstart() { register struct tty *tp; register struct vterm *vt; register char *cp; /***int sps; ***/ int windef[5], cnt, quant; static struct tty *curtty; char *cw; if(gn.gnstate&BUSY) return; /***sps = PS->integ; spl5(); ***/ cp = gn.gnbuf; if((tp = curtty) == 0) if((tp = gntgwork()) == 0) goto out; /* No Work for the nonce */ else goto setwin; /* This must be new window */ do { if(tp->t_state&KBDSYNC) { /* Currently, this has no meaning */ tp->t_state =& ~KBDSYNC; if(tp->t_kbd) { tp->t_screen = tp->t_kbd; if(tp->t_screen->v_outq.c_cc) goto setwin; } } if((vt = tp->t_screen) == 0 || vt->v_state&VT_CLOSED) goto next; /* This screen unusable */ if(vt->v_flags & VIRGIN) /* window redefined! */ goto setwin; quant = GNQUANTA; /* smoothing factor */ while(quant-- && (cnt = getc(&vt->v_outq)) >= 0) { if(cnt == 0 || cnt == GNFLAG) { *cp++ = GNFLAG; *cp++ = ~cnt; } else *cp++ = cnt; if(cp >= &gn.gnbuf[510]) /* leave room for 2 chars */ goto send; } if(vt->v_state&VT_OSLEEP && vt->v_outq.c_cc <= TTLOWAT) { vt->v_state =& ~VT_OSLEEP; wakeup(&vt->v_outq); /* wake oput blocked procs */ } next: if(cp >= gn.gnenbuf || !(gnt_nxo(tp) || (tp = gntgwork()))) break; /* No more to do */ setwin: vt = tp->t_screen; *cp++ = GNFLAG; /* Select this window */ if((*cp++ = vt->v_mapw) == 0) panic("Missing Mapped Genisco Window"); if(vt->v_flags&VIRGIN) { /* First time ?? */ cw = &vt->v_curw; /* Current Window def */ windef[0] = cw->w_ulhc.cr_row * GNCHEIGHT; windef[1] = (cw->w_lrhc.cr_row + 1) * GNCHEIGHT + windef[0]; windef[2] = cw->w_ulhc.cr_col * GNCWIDTH; windef[3] = (cw->w_lrhc.cr_col + 1) * GNCWIDTH + windef[2]; windef[4] = gnplanes[tp->t_dev.d_minor]; *cp++ = GNFLAG; *cp++ = GNSETWIN; for(cw = windef; cw < &windef[5];) /* This line: * if(*cw == 0 || *cw == GNFLAG) { * had sign extension problems... the following line only works * if GNFLAG == 0200!! */ if((*cw & 0177) == 0) { *cp++ = GNFLAG; *cp++ = ~*cw++; } else *cp++ = *cw++; vt->v_flags =& ~VIRGIN; /* No Longer Virgin */ } curtty = tp; } while(cp < gn.gnenbuf); /* Glutton... eat till full */ send: if(cnt = cp - gn.gnbuf) { if(cnt&01) { *cp++ = 0; cnt++; } #ifdef DEBUG VT_DB3 { printf("GNN:Writing %d:", cnt); for(cp=gn.gnbuf; cp<&gn.gnbuf[cnt];cp++) { if(((cp-gn.gnbuf)%10) == 0) printf("\n"); printf(" %o", *cp&0377); } printf("\n"); } #endif GEN->doa = (gn.gnbuf>>1)&077777; GEN->iopls++; /* set write */ GEN->dob = -(cnt>>1); GEN->strt = 0; gn.gnstate =| BUSY|GNTIO; /* flag buf busy & term i/o */ /* in progress */ } else if(gn.gnstate & WAITING) /* If no term i/o, start any */ wakeup(gn.gnbp); /* direct i/o if desired */ out: ; /* PS->integ = sps; */ } gntgwork() { register struct tty *tp; register struct vterm *vt; /* Redundant code below... mob:12/19/77 */ /* for(tp = gnt11; tp < &gnt11[NGNCRT]; tp++) if((tp->t_state&ISOPEN) && vt_nxo(tp)) return(tp); */ for(tp = gnt11; tp < &gnt11[NGNCRT]; tp++) if((tp->t_state&ISOPEN) && gnt_nxo(tp)) return(tp); return(0); } gntgvt(dev) { int minor; if((minor = dev.d_minor) >= NGNCRT) return(0); return(gnt11[minor].t_vterm); } gnt_nxo(atp) struct tty *atp; { register struct tty *tp; register struct vterm *vt; tp = atp; if(vt = vt_nxo(tp)) return(vt); if((vt = tp->t_screen)->v_outq.c_cc) return(vt); return(0); } gntwmap(avt) struct vterm *avt; { register struct vterm *vt; register int i; if((vt = avt) == 0) panic("Zero VT"); if(i = vt->v_mapw) { gntmap[i - 1] = 0; vt->v_mapw = 0; return(0); } else { for(i = 0; i < NGNWINS; i++) if(gntmap[i] == 0) { gntmap[i] = (vt - vt_structures) + 1; vt->v_mapw = i + 1; return(0); } return(1); } }