8100: #   / * general TTY subroutines */
8101: 
8102: #include "../param.h"
8103: #include "../systm.h"
8104: #include "../user.h"
8105: #include "../tty.h"
8106: #include "../proc.h"
8107: #include "../inode.h"
8108: #include "../file.h"
8109: #include "../reg.h"
8110: #include "../conf.h"
8111: 
8112: /* Input mapping table-- if an entry is non-zero, when the
8113:  * corresponding character is typed preceded by "\" the escape
8114:  * sequence is replaced by the table value.  Mostly used for
8115:  * upper-case only terminals.
8116:  */
8117: char    maptab[]
8118: {
8119:         000,000,000,000,004,000,000,000,
8120:         000,000,000,000,000,000,000,000,
8121:         000,000,000,000,000,000,000,000,
8122:         000,000,000,000,000,000,000,000,
8123:         000,'|',000,'#',000,000,000,'`',
8124:         '{','}',000,000,000,000,000,000,
8125:         000,000,000,000,000,000,000,000,
8126:         000,000,000,000,000,000,000,000,
8127:         '@',000,000,000,000,000,000,000,
8128:         000,000,000,000,000,000,000,000,
8129:         000,000,000,000,000,000,000,000,
8130:         000,000,000,000,000,000,'~',000,
8131:         000,'A','B','C','D','E','F','G',
8132:         'H','I','J','K','L','M','N','O',
8133:         'P','Q','R','S','T','U','V','W',
8134:         'X','Y','Z',000,000,000,000,000,
8135: };
8136: /* ---------------------------       */
8137: /* The actual structure of a clist block manipulated by
8138:  * getc and putc (mch.s)
8139:  */
8140: struct cblock {
8141:         struct cblock *c_next;
8142:         char info[6];
8143: };
8144: /* ---------------------------       */
8145: /* The character lists-- space for 6*NCLIST characters */
8146: struct cblock cfree[NCLIST];
8147: /* List head for unused character blocks. */
8148: struct cblock *cfreelist;
8149: 
8150: /* structure of device registers for KL, DL, and DC
8151:  * interfaces-- more particularly, those for which the
8152:  * SSTART bit is off and can be treated by general routines
8153:  * (that is, not DH).
8154:  */
8155: struct {
8156:         int ttrcsr;
8157:         int ttrbuf;
8158:         int tttcsr;
8159:         int tttbuf;
8160: };
8161: /* ---------------------------       */
8162: /* The routine implementing the gtty system call.
8163:  * Just call lower level routine and pass back values.
8164:  */
8165: gtty()
8166: {
8167:         int v[3];
8168:         register *up, *vp;
8169: 
8170:         vp = v;
8171:         sgtty(vp);
8172:         if (u.u_error)
8173:                 return;
8174:         up = u.u_arg[0];
8175:         suword(up, *vp++);
8176:         suword(++up, *vp++);
8177:         suword(++up, *vp++);
8178: }
8179: /* ---------------------------       */
8180: /* The routine implementing the stty system call.
8181:  * Read in values and call lower level.
8182:  */
8183: stty()
8184: {
8185:         register int *up;
8186: 
8187:         up = u.u_arg[0];
8188:         u.u_arg[0] = fuword(up);
8189:         u.u_arg[1] = fuword(++up);
8190:         u.u_arg[2] = fuword(++up);
8191:         sgtty(0);
8192: }
8193: /* ---------------------------       */
8194: /* Stuff common to stty and gtty.
8195:  * Check legality and switch out to individual
8196:  * device routine.
8197:  * v  is 0 for stty; the parameters are taken from u.u_arg[].
8198:  * c  is non-zero for gtty and is the place in which the device
8199:  * routines place their information.
8200:  */
8201: sgtty(v)
8202: int *v;
8203: {
8204:         register struct file *fp;
8205:         register struct inode *ip;
8206:         if ((fp = getf(u.u_ar0[R0])) == NULL)
8207:                 return;
8208:         ip = fp->f_inode;
8209:         if ((ip->i_mode&IFMT) != IFCHR) {
8210:                 u.u_error = ENOTTY;
8211:                 return;
8212:         }
8213:         (*cdevsw[ip->i_addr[0].d_major].d_sgtty)(ip->i_addr[0], v);
8214: }
8215: /* ---------------------------       */
8216: /* Wait for output to drain, then flush input waiting. */
8217: wflushtty(atp)
8218: struct tty *atp;
8219: {
8220:         register struct tty *tp;
8221:         tp = atp;
8222:         spl5();
8223:         while (tp->t_outq.c_cc) {
8224:                 tp->t_state =| ASLEEP;
8225:                 sleep(&tp->t_outq, TTOPRI);
8226:         }
8227:         flushtty(tp);
8228:         spl0();
8229: }
8230: /* ---------------------------       */
8231: /* Initialize clist by freeing all character blocks, then count
8232:  * number of character devices. (Once-only routine)
8233:  */
8234: cinit()
8235: {
8236:         register int ccp;
8237:         register struct cblock *cp;
8238:         register struct cdevsw *cdp;
8239:         ccp = cfree;
8240:         for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) {
8241:                 cp->c_next = cfreelist;
8242:                 cfreelist = cp;
8243:         }
8244:         ccp = 0;
8245:         for(cdp = cdevsw; cdp->d_open; cdp++)
8246:                 ccp++;
8247:         nchrdev = ccp;
8248: }
8249: /* ---------------------------       */
8250: /* flush all TTY queues
8251:  */
8252: flushtty(atp)
8253: struct tty *atp;
8254: {
8255:         register struct tty *tp;
8256:         register int sps;
8257:         tp = atp;
8258:         while (getc(&tp->t_canq) >= 0);
8259:         while (getc(&tp->t_outq) >= 0);
8260:         wakeup(&tp->t_rawq);
8261:         wakeup(&tp->t_outq);
8262:         sps = PS->integ;
8263:         spl5();
8264:         while (getc(&tp->t_rawq) >= 0);
8265:         tp->t_delct = 0;
8266:         PS->integ = sps;
8267: }
8268: /* ---------------------------       */
8269: /* transfer raw input list to canonical list,
8270:  * doing erase-kill processing and handling escapes.
8271:  * It waits until a full line has been typed in cooked mode,
8272:  * or until any character has been typed in raw mode.
8273:  */
8274: canon(atp)
8275: struct tty *atp;
8276: {
8277:         register char *bp;
8278:         char *bp1;
8279:         register struct tty *tp;
8280:         register int c;
8281: 
8282:         tp = atp;
8283:         spl5();
8284:         while (tp->t_delct==0) {
8285:                 if ((tp->t_state&CARR_ON)==0)
8286:                         return(0);
8287:                 sleep(&tp->t_rawq, TTIPRI);
8288:         }
8289:         spl0();
8290: loop:
8291:         bp = &canonb[2];
8292:         while ((c=getc(&tp->t_rawq)) >= 0) {
8293:                 if (c==0377) {
8294:                         tp->t_delct--;
8295:                         break;
8296:                 }
8297:                 if ((tp->t_flags&RAW)==0) {
8298:                         if (bp[-1]!='\\') {
8299:                                 if (c==tp->t_erase) {
8300:                                         if (bp > &canonb[2])
8301:                                                 bp--;
8302:                                         continue;
8303:                                 }
8304:                                 if (c==tp->t_kill)
8305:                                         goto loop;
8306:                                 if (c==CEOT)
8307:                                         continue;
8308:                         } else
8309:                         if (maptab[c] && (maptab[c]==c || (tp->t_flags&LCASE))) {
8310:                                 if (bp[-2] != '\\')
8311:                                         c = maptab[c];
8312:                                 bp--;
8313:                         }
8314:                 }
8315:                 *bp++ = c;
8316:                 if (bp>=canonb+CANBSIZ)
8317:                         break;
8318:         }
8319:         bp1 = bp;
8320:         bp = &canonb[2];
8321:         c = &tp->t_canq;
8322:         while (bp<bp1)
8323:                 putc(*bp++, c);
8324:         return(1);
8325: }
8326: /* ---------------------------       */
8327: /* Place a character on raw TTY input queue, putting in delimiters
8328:  * and waking up top half as needed.
8329:  * Also echo if required.
8330:  * The arguments are the character and the appropriate
8331:  * tty structure.
8332:  */
8333: ttyinput(ac, atp)
8334: struct tty *atp;
8335: {
8336:         register int t_flags, c;
8337:         register struct tty *tp;
8338: 
8339:         tp = atp;
8340:         c = ac;
8341:         t_flags = tp->t_flags;
8342:         if ((c =& 0177) == '\r' && t_flags&CRMOD)
8343:                 c = '\n';
8344:         if ((t_flags&RAW)==0 && (c==CQUIT || c==CINTR)) {
8345:                 signal(tp, c==CINTR? SIGINT:SIGQIT);
8346:                 flushtty(tp);
8347:                 return;
8348:         }
8349:         if (tp->t_rawq.c_cc>=TTYHOG) {
8350:                 flushtty(tp);
8351:                 return;
8352:         }
8353:         if (t_flags&LCASE && c>='A' && c<='Z')
8354:                 c =+ 'a'-'A';
8355:         putc(c, &tp->t_rawq);
8356:         if (t_flags&RAW || c=='\n' || c==004) {
8357:                 wakeup(&tp->t_rawq);
8358:                 if (putc(0377, &tp->t_rawq)==0)
8359:                         tp->t_delct++;
8360:         }
8361:         if (t_flags&ECHO) {
8362:                 ttyoutput(c, tp);
8363:                 ttstart(tp);
8364:         }
8365: }
8366: /* ---------------------------       */
8367: /* put character on TTY output queue, adding delays,
8368:  * expanding tabs, and handling the CR/NL bit.
8369:  * It is called both from the top half for output, and from
8370:  * interrupt level for echoing.
8371:  * The arguments are the character and the tty structure.
8372:  */
8373: ttyoutput(ac, tp)
8374: struct tty *tp;
8375: {
8376:         register int c;
8377:         register struct tty *rtp;
8378:         register char *colp;
8379:         int ctype;
8380: 
8381:         rtp = tp;
8382:         c = ac&0177;
8383:         /* Ignore EOT in normal mode to avoid hanging up
8384:          * certain terminals.
8385:          */
8386:         if (c==004 && (rtp->t_flags&RAW)==0)
8387:                 return;
8388:         /* Turn tabs to spaces as required
8389:          */
8390:         if (c=='\t' && rtp->t_flags&XTABS) {
8391:                 do
8392:                         ttyoutput(' ', rtp);
8393:                 while (rtp->t_col&07);
8394:                 return;
8395:         }
8396:         /* for upper-case-only terminals,
8397:          * generate escapes.
8398:          */
8399:         if (rtp->t_flags&LCASE) {
8400:                 colp = "({)}!|^~'`";
8401:                 while(*colp++)
8402:                         if(c == *colp++) {
8403:                                 ttyoutput('\\', rtp);
8404:                                 c = colp[-2];
8405:                                 break;
8406:                         }
8407:                 if ('a'<=c && c<='z')
8408:                         c =+ 'A' - 'a';
8409:         }
8410:         /* turn <nl> to <cr><lf> if desired.
8411:          */
8412:         if (c=='\n' && rtp->t_flags&CRMOD)
8413:                 ttyoutput('\r', rtp);
8414:         if (putc(c, &rtp->t_outq))
8415:                 return;
8416:         /* Calculate delays.
8417:          * The numbers here represent clock ticks
8418:          * and are not necessarily optimal for all terminals.
8419:          * The delays are indicated by characters above 0200,
8420:          * thus (unfortunately) restricting the transmission
8421:          * path to 7 bits.
8422:          */
8423:         colp = &rtp->t_col;
8424:         ctype = partab[c];
8425:         c = 0;
8426:         switch (ctype&077) {
8427:         /* ordinary */
8428:         case 0:
8429:                 (*colp)++;
8430:         /* non-printing */
8431:         case 1:
8432:                 break;
8433:         /* backspace */
8434:         case 2:
8435:                 if (*colp)
8436:                         (*colp)--;
8437:                 break;
8438:         /* newline */
8439:         case 3:
8440:                 ctype = (rtp->t_flags >> 8) & 03;
8441:                 if(ctype == 1) { /* tty 37 */
8442:                         if (*colp)
8443:                                 c = max((*colp>>4) + 3, 6);
8444:                 } else
8445:                 if(ctype == 2) { /* vt05 */
8446:                         c = 6;
8447:                 }
8448:                 *colp = 0;
8449:                 break;
8450:         /* tab */
8451:         case 4:
8452:                 ctype = (rtp->t_flags >> 10) & 03;
8453:                 if(ctype == 1) { /* tty 37 */
8454:                         c = 1 - (*colp | ~07);
8455:                         if(c < 5)
8456:                                 c = 0;
8457:                 }
8458:                 *colp =| 07;
8459:                 (*colp)++;
8460:                 break;
8461:         /* vertical motion */
8462:         case 5:
8463:                 if(rtp->t_flags & VTDELAY) /* tty 37 */
8464:                         c = 0177;
8465:                 break;
8466:         /* carriage return */
8467:         case 6:
8468:                 ctype = (rtp->t_flags >> 12) & 03;
8469:                 if(ctype == 1) { /* tn 300 */
8470:                         c = 5;
8471:                 } else
8472:                 if(ctype == 2) { /* ti 700 */
8473:                         c = 10;
8474:                 }
8475:                 *colp = 0;
8476:         }
8477:         if(c)
8478:                 putc(c|0200, &rtp->t_outq);
8479: }
8480: /* ---------------------------       */
8481: /* Restart typewriter output following a delay
8482:  * timeout.
8483:  * The name of the routine is passed to the timeout
8484:  * subroutine and it is called during a clock interrupt.
8485:  */
8486: ttrstrt(atp)
8487: {
8488:         register struct tty *tp;
8489: 
8490:         tp = atp;
8491:         tp->t_state =& ~TIMEOUT;
8492:         ttstart(tp);
8493: }
8494: /* ---------------------------       */
8495: /*
8496:  * Start output on the typewriter. It is used from the top half
8497:  * after some characters have been put on the output queue,
8498:  * from the interrupt routine to transmit the next
8499:  * character, and after a timeout has finished.
8500:  * If the SSTART bit is off for the tty the work is done here,
8501:  * using the protocol of the single-line interfaces (KL, DL, DC);
8502:  * otherwise the address word of the tty structure is
8503:  * taken to be the name of the device-dependent startup routine.
8504:  */
8505: ttstart(atp)
8506: struct tty *atp;
8507: {
8508:         register int *addr, c;
8509:         register struct tty *tp;
8510:         struct { int (*func)(); };
8511: 
8512:         tp = atp;
8513:         addr = tp->t_addr;
8514:         if (tp->t_state&SSTART) {
8515:                 (*addr.func)(tp);
8516:                 return;
8517:         }
8518:         if ((addr->tttcsr&DONE)==0 || tp->t_state&TIMEOUT)
8519:                 return;
8520:         if ((c=getc(&tp->t_outq)) >= 0) {
8521:                 if (c<=0177)
8522:                         addr->tttbuf = c | (partab[c]&0200);
8523:                 else {
8524:                         timeout(ttrstrt, tp, c&0177);
8525:                         tp->t_state =| TIMEOUT;
8526:                 }
8527:         }
8528: }
8529: /* ---------------------------       */
8530: /* Called from device's read routine after it has
8531:  * calculated the tty-structure given as argument.
8532:  * The pc is backed up for the duration of this call.
8533:  * In case of a caught interrupt, an RTI will re-execute.
8534:  */
8535: ttread(atp)
8536: struct tty *atp;
8537: {
8538:         register struct tty *tp;
8539: 
8540:         tp = atp;
8541:         if ((tp->t_state&CARR_ON)==0)
8542:                 return;
8543:         if (tp->t_canq.c_cc || canon(tp))
8544:                 while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0);
8545: }
8546: /* ---------------------------       */
8547: /* Called from the device's write routine after it has
8548:  * calculated the tty-structure given as argument.
8549:  */
8550: ttwrite(atp)
8551: struct tty *atp;
8552: {
8553:         register struct tty *tp;
8554:         register int c;
8555:         tp = atp;
8556:         if ((tp->t_state&CARR_ON)==0)
8557:                 return;
8558:         while ((c=cpass())>=0) {
8559:                 spl5();
8560:                 while (tp->t_outq.c_cc > TTHIWAT) {
8561:                         ttstart(tp);
8562:                         tp->t_state =| ASLEEP;
8563:                         sleep(&tp->t_outq, TTOPRI);
8564:                 }
8565:                 spl0();
8566:                 ttyoutput(c, tp);
8567:         }
8568:         ttstart(tp);
8569: }
8570: /* ---------------------------       */
8571: /* Common code for gtty and stty functions on typewriters.
8572:  * If v is non-zero then gtty is being done and information is
8573:  * passed back therein;
8574:  * if it is zero stty is being done and the input information is in the
8575:  * u_arg array.
8576:  */
8577: ttystty(atp, av)
8578: int *atp, *av;
8579: {
8580:         register  *tp, *v;
8581:         tp = atp;
8582:         if(v = av) {
8583:                 *v++ = tp->t_speeds;
8584:                 v->lobyte = tp->t_erase;
8585:                 v->hibyte = tp->t_kill;
8586:                 v[1] = tp->t_flags;
8587:                 return(1);
8588:         }
8589:         wflushtty(tp);
8590:         v = u.u_arg;
8591:         tp->t_speeds = *v++;
8592:         tp->t_erase = v->lobyte;
8593:         tp->t_kill = v->hibyte;
8594:         tp->t_flags = v[1];
8595:         return(0);
8596: }
8597: /* ---------------------------       */