1*5573Swnj /* tty.c 4.18 82/01/19 */ 239Sbill 339Sbill /* 4903Sbill * TTY subroutines common to more than one line discipline 539Sbill */ 639Sbill #include "../h/param.h" 739Sbill #include "../h/systm.h" 839Sbill #include "../h/dir.h" 939Sbill #include "../h/user.h" 1039Sbill #include "../h/tty.h" 1139Sbill #include "../h/proc.h" 1239Sbill #include "../h/inode.h" 1339Sbill #include "../h/file.h" 1439Sbill #include "../h/reg.h" 1539Sbill #include "../h/conf.h" 1639Sbill #include "../h/buf.h" 17340Sbill #include "../h/dk.h" 1839Sbill 1939Sbill char partab[]; 2039Sbill 21146Sbill /* 2239Sbill * Input mapping table-- if an entry is non-zero, when the 2339Sbill * corresponding character is typed preceded by "\" the escape 2439Sbill * sequence is replaced by the table value. Mostly used for 2539Sbill * upper-case only terminals. 2639Sbill */ 2739Sbill 2839Sbill char maptab[] ={ 2939Sbill 000,000,000,000,000,000,000,000, 3039Sbill 000,000,000,000,000,000,000,000, 3139Sbill 000,000,000,000,000,000,000,000, 3239Sbill 000,000,000,000,000,000,000,000, 3339Sbill 000,'|',000,000,000,000,000,'`', 3439Sbill '{','}',000,000,000,000,000,000, 3539Sbill 000,000,000,000,000,000,000,000, 3639Sbill 000,000,000,000,000,000,000,000, 3739Sbill 000,000,000,000,000,000,000,000, 3839Sbill 000,000,000,000,000,000,000,000, 3939Sbill 000,000,000,000,000,000,000,000, 4039Sbill 000,000,000,000,000,000,'~',000, 4139Sbill 000,'A','B','C','D','E','F','G', 4239Sbill 'H','I','J','K','L','M','N','O', 4339Sbill 'P','Q','R','S','T','U','V','W', 4439Sbill 'X','Y','Z',000,000,000,000,000, 4539Sbill }; 4639Sbill 47925Sbill short tthiwat[16] = 48925Sbill { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 49925Sbill short ttlowat[16] = 50925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 51925Sbill 5239Sbill #define OBUFSIZ 100 5339Sbill 5439Sbill /* 5539Sbill * set default control characters. 5639Sbill */ 5739Sbill ttychars(tp) 5839Sbill register struct tty *tp; 5939Sbill { 60174Sbill 6139Sbill tun.t_intrc = CINTR; 6239Sbill tun.t_quitc = CQUIT; 6339Sbill tun.t_startc = CSTART; 6439Sbill tun.t_stopc = CSTOP; 6539Sbill tun.t_eofc = CEOT; 6639Sbill tun.t_brkc = CBRK; 6739Sbill tp->t_erase = CERASE; 6839Sbill tp->t_kill = CKILL; 69174Sbill /* begin local */ 70208Sbill tlun.t_suspc = CTRL(z); 71208Sbill tlun.t_dsuspc = CTRL(y); 72174Sbill tlun.t_rprntc = CTRL(r); 73174Sbill tlun.t_flushc = CTRL(o); 74174Sbill tlun.t_werasc = CTRL(w); 75174Sbill tlun.t_lnextc = CTRL(v); 76174Sbill tp->t_local = 0; 77174Sbill tp->t_lstate = 0; 78174Sbill /* end local */ 7939Sbill } 8039Sbill 8139Sbill /* 82903Sbill * Wait for output to drain, then flush input waiting. 8339Sbill */ 84903Sbill wflushtty(tp) 855408Swnj register struct tty *tp; 8639Sbill { 8739Sbill 88903Sbill (void) spl5(); 895408Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON) { 90903Sbill (*tp->t_oproc)(tp); 915408Swnj tp->t_state |= TS_ASLEEP; 92903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 93903Sbill } 945426Swnj flushtty(tp, FREAD); 95903Sbill (void) spl0(); 9639Sbill } 9739Sbill 9839Sbill /* 99903Sbill * flush all TTY queues 10039Sbill */ 101903Sbill flushtty(tp, rw) 102903Sbill register struct tty *tp; 10339Sbill { 104903Sbill register s; 105903Sbill 106903Sbill s = spl6(); 107903Sbill if (rw & FREAD) { 108903Sbill while (getc(&tp->t_canq) >= 0) 109903Sbill ; 110903Sbill wakeup((caddr_t)&tp->t_rawq); 111903Sbill } 112903Sbill if (rw & FWRITE) { 113903Sbill wakeup((caddr_t)&tp->t_outq); 1145408Swnj tp->t_state &= ~TS_TTSTOP; 1155426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 116903Sbill while (getc(&tp->t_outq) >= 0) 117903Sbill ; 118903Sbill } 119903Sbill if (rw & FREAD) { 120903Sbill while (getc(&tp->t_rawq) >= 0) 121903Sbill ; 122903Sbill tp->t_delct = 0; 123903Sbill tp->t_rocount = 0; /* local */ 124903Sbill tp->t_rocol = 0; 125903Sbill tp->t_lstate = 0; 126903Sbill } 127903Sbill splx(s); 12839Sbill } 12939Sbill 130903Sbill /* 131903Sbill * Send stop character on input overflow. 132903Sbill */ 133903Sbill ttyblock(tp) 134903Sbill register struct tty *tp; 13539Sbill { 136903Sbill register x; 137903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 138903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 139903Sbill flushtty(tp, FREAD|FWRITE); 1405408Swnj tp->t_state &= ~TS_TBLOCK; 141903Sbill } 142903Sbill if (x >= TTYHOG/2) { 143903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 1445408Swnj tp->t_state |= TS_TBLOCK; 145903Sbill tp->t_char++; 146903Sbill ttstart(tp); 147903Sbill } 148903Sbill } 14939Sbill } 15039Sbill 15139Sbill /* 152903Sbill * Restart typewriter output following a delay 153903Sbill * timeout. 154903Sbill * The name of the routine is passed to the timeout 155903Sbill * subroutine and it is called during a clock interrupt. 156121Sbill */ 157903Sbill ttrstrt(tp) 158121Sbill register struct tty *tp; 159121Sbill { 160121Sbill 1613351Swnj if (tp == 0) { 1623351Swnj printf("ttrstrt: arg was 0!\n"); 1633351Swnj return; 1643351Swnj } 1655408Swnj tp->t_state &= ~TS_TIMEOUT; 166903Sbill ttstart(tp); 167121Sbill } 168121Sbill 169121Sbill /* 170903Sbill * Start output on the typewriter. It is used from the top half 171903Sbill * after some characters have been put on the output queue, 172903Sbill * from the interrupt routine to transmit the next 173903Sbill * character, and after a timeout has finished. 17439Sbill */ 175903Sbill ttstart(tp) 176903Sbill register struct tty *tp; 17739Sbill { 178903Sbill register s; 17939Sbill 180903Sbill s = spl5(); 1815408Swnj if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0) 182903Sbill (*tp->t_oproc)(tp); 183903Sbill splx(s); 18439Sbill } 18539Sbill 18639Sbill /* 187903Sbill * Common code for tty ioctls. 18839Sbill */ 1891780Sbill /*ARGSUSED*/ 1901904Swnj ttioctl(tp, com, addr, flag) 19139Sbill register struct tty *tp; 19239Sbill caddr_t addr; 19339Sbill { 1941904Swnj int dev; 19539Sbill unsigned t; 196174Sbill struct sgttyb iocb; 197191Sbill struct clist tq; 19839Sbill extern int nldisp; 199887Sbill register c; 200728Sbill int temp; 20139Sbill 202903Sbill /* 203915Sbill * This is especially so that isatty() will 204915Sbill * fail when carrier is gone. 205915Sbill */ 2065408Swnj if ((tp->t_state&TS_CARR_ON) == 0) { 207915Sbill u.u_error = EBADF; 208915Sbill return (1); 209915Sbill } 210915Sbill 2111904Swnj dev = tp->t_dev; 212915Sbill /* 213903Sbill * If the ioctl involves modification, 214903Sbill * insist on being able to write the device, 215903Sbill * and hang if in the background. 216903Sbill */ 21739Sbill switch(com) { 21839Sbill 219915Sbill case TIOCSETD: 220915Sbill case TIOCSETP: 221915Sbill case TIOCSETN: 222903Sbill case TIOCFLUSH: 223903Sbill case TIOCSETC: 224903Sbill case TIOCSLTC: 225903Sbill case TIOCSPGRP: 226903Sbill case TIOCLBIS: 227903Sbill case TIOCLBIC: 228903Sbill case TIOCLSET: 229903Sbill case TIOCSTI: 230915Sbill /* this is reasonable, but impractical... 231903Sbill if ((flag & FWRITE) == 0) { 232903Sbill u.u_error = EBADF; 233903Sbill return (1); 234903Sbill } 235915Sbill */ 236903Sbill while (tp->t_line == NTTYDISC && 237903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 238903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 239903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 240903Sbill u.u_signal[SIGTTOU] != SIG_HOLD && 241903Sbill (u.u_procp->p_flag&SDETACH)==0) { 242903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 243903Sbill sleep((caddr_t)&lbolt, TTOPRI); 244903Sbill } 245903Sbill break; 246903Sbill } 247903Sbill 24839Sbill /* 249903Sbill * Process the ioctl. 25039Sbill */ 251903Sbill switch(com) { 252903Sbill 253903Sbill /* 254903Sbill * Get discipline number 255903Sbill */ 25639Sbill case TIOCGETD: 25739Sbill t = tp->t_line; 25839Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 25939Sbill u.u_error = EFAULT; 26039Sbill break; 26139Sbill 26239Sbill /* 263903Sbill * Set line discipline 26439Sbill */ 26539Sbill case TIOCSETD: 26639Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 26739Sbill u.u_error = EFAULT; 26839Sbill break; 26939Sbill } 27039Sbill if (t >= nldisp) { 27139Sbill u.u_error = ENXIO; 27239Sbill break; 27339Sbill } 274174Sbill (void) spl5(); 27539Sbill if (tp->t_line) 27639Sbill (*linesw[tp->t_line].l_close)(tp); 27739Sbill if (t) 27839Sbill (*linesw[t].l_open)(dev, tp, addr); 27939Sbill if (u.u_error==0) 28039Sbill tp->t_line = t; 281174Sbill (void) spl0(); 28239Sbill break; 28339Sbill 28439Sbill /* 28539Sbill * Set new parameters 28639Sbill */ 28739Sbill case TIOCSETP: 288191Sbill case TIOCSETN: 28939Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 29039Sbill u.u_error = EFAULT; 29139Sbill return(1); 29239Sbill } 293121Sbill (void) spl5(); 2944484Swnj if (tp->t_flags&RAW || iocb.sg_flags&RAW || 2954484Swnj com == TIOCSETP) 2964484Swnj wflushtty(tp); 2974484Swnj else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 2984484Swnj if (iocb.sg_flags & CBREAK) { 2994484Swnj catq(&tp->t_rawq, &tp->t_canq); 3004484Swnj tq = tp->t_rawq; 3014484Swnj tp->t_rawq = tp->t_canq; 3024484Swnj tp->t_canq = tq; 3034484Swnj } else { 3044484Swnj tp->t_local |= LPENDIN; 3054484Swnj ttwakeup(tp); 306174Sbill } 307174Sbill } 3084484Swnj tp->t_ispeed = iocb.sg_ispeed; 3094484Swnj tp->t_ospeed = iocb.sg_ospeed; 310174Sbill tp->t_erase = iocb.sg_erase; 311174Sbill tp->t_kill = iocb.sg_kill; 312174Sbill tp->t_flags = iocb.sg_flags; 3133941Sbugs if (tp->t_flags & RAW) { 3145408Swnj tp->t_state &= ~TS_TTSTOP; 3153941Sbugs ttstart(tp); 3163941Sbugs } 317121Sbill (void) spl0(); 31839Sbill break; 31939Sbill 32039Sbill /* 321903Sbill * Send current parameters to user 32239Sbill */ 32339Sbill case TIOCGETP: 324174Sbill iocb.sg_ispeed = tp->t_ispeed; 325174Sbill iocb.sg_ospeed = tp->t_ospeed; 326174Sbill iocb.sg_erase = tp->t_erase; 327174Sbill iocb.sg_kill = tp->t_kill; 328174Sbill iocb.sg_flags = tp->t_flags; 32939Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 33039Sbill u.u_error = EFAULT; 33139Sbill break; 33239Sbill 33339Sbill /* 33439Sbill * Hang up line on last close 33539Sbill */ 33639Sbill case TIOCHPCL: 3375408Swnj tp->t_state |= TS_HUPCLS; 33839Sbill break; 33939Sbill 3403942Sbugs case TIOCFLUSH: { 3413942Sbugs int flags; 3423942Sbugs if (addr == 0) 3433942Sbugs flags = FREAD|FWRITE; 3443942Sbugs else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 3453942Sbugs u.u_error = EFAULT; 3463983Sroot return(1); 3473942Sbugs } 3483942Sbugs flushtty(tp, flags); 34939Sbill break; 3503944Sbugs } 35139Sbill 3525408Swnj case FIONBIO: { 3535408Swnj int nbio; 3545408Swnj if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 3555408Swnj u.u_error = EFAULT; 3565408Swnj return(1); 3575408Swnj } 3585408Swnj if (nbio) 3595408Swnj tp->t_state |= TS_NBIO; 3605408Swnj else 3615408Swnj tp->t_state &= ~TS_NBIO; 3625408Swnj break; 3635408Swnj } 3645408Swnj 36539Sbill /* 366903Sbill * Set and fetch special characters 36739Sbill */ 36839Sbill case TIOCSETC: 369174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 37039Sbill u.u_error = EFAULT; 37139Sbill break; 37239Sbill 37339Sbill case TIOCGETC: 374174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 37539Sbill u.u_error = EFAULT; 37639Sbill break; 37739Sbill 378174Sbill /* local ioctls */ 379903Sbill /* 380903Sbill * Set/get local special characters. 381903Sbill */ 382174Sbill case TIOCSLTC: 383174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 384174Sbill u.u_error = EFAULT; 385174Sbill break; 386174Sbill 387174Sbill case TIOCGLTC: 388174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 389174Sbill u.u_error = EFAULT; 390174Sbill break; 391174Sbill 392903Sbill /* 393903Sbill * Return number of characters immediately available. 394903Sbill */ 395174Sbill case FIONREAD: { 3964484Swnj off_t nread = ttnread(tp); 397174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 398174Sbill u.u_error = EFAULT; 399174Sbill break; 400174Sbill } 401174Sbill 402174Sbill /* 403174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 404174Sbill */ 405174Sbill case TIOCSPGRP: 406728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 407728Sbill u.u_error = EFAULT; 408174Sbill break; 409174Sbill 410174Sbill case TIOCGPGRP: 411174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 412174Sbill u.u_error = EFAULT; 413174Sbill break; 414174Sbill 415174Sbill /* 416174Sbill * Modify local mode word. 417174Sbill */ 418174Sbill case TIOCLBIS: 419728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 420728Sbill u.u_error = EFAULT; 421728Sbill else 422728Sbill tp->t_local |= temp; 423174Sbill break; 424174Sbill 425174Sbill case TIOCLBIC: 426728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 427728Sbill u.u_error = EFAULT; 428728Sbill else 429728Sbill tp->t_local &= ~temp; 430174Sbill break; 431174Sbill 432174Sbill case TIOCLSET: 433728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 434728Sbill u.u_error = EFAULT; 435728Sbill else 436728Sbill tp->t_local = temp; 437174Sbill break; 438174Sbill 439174Sbill case TIOCLGET: 440174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 441174Sbill u.u_error = EFAULT; 442174Sbill break; 443174Sbill 444903Sbill /* 445903Sbill * Return number of characters in 446903Sbill * the output. 447903Sbill */ 448213Sbill case TIOCOUTQ: 449213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 450213Sbill u.u_error = EFAULT; 451213Sbill break; 452213Sbill 453903Sbill /* 454903Sbill * Simulate typing of a character at the terminal. 455903Sbill */ 456887Sbill case TIOCSTI: 457887Sbill c = fubyte(addr); 458887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 459887Sbill u.u_error = EFAULT; 460887Sbill else 461887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 462887Sbill break; 463*5573Swnj 464*5573Swnj case TIOCSTOP: 465*5573Swnj c = spl5(); 466*5573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 467*5573Swnj tp->t_state |= TS_TTSTOP; 468*5573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 469*5573Swnj } 470*5573Swnj splx(c); 471*5573Swnj break; 472*5573Swnj 473*5573Swnj case TIOCSTART: 474*5573Swnj c = spl5(); 475*5573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 476*5573Swnj tp->t_state &= ~TS_TTSTOP; 477*5573Swnj tp->t_local &= ~LFLUSHO; 478*5573Swnj ttstart(tp); 479*5573Swnj } 480*5573Swnj splx(c); 481*5573Swnj break; 482*5573Swnj 483174Sbill /* end of locals */ 484887Sbill 48539Sbill default: 48639Sbill return(0); 48739Sbill } 48839Sbill return(1); 48939Sbill } 4904484Swnj 4914484Swnj ttnread(tp) 4924484Swnj struct tty *tp; 4934484Swnj { 4944484Swnj int nread = 0; 4954484Swnj 4964484Swnj if (tp->t_local & LPENDIN) 4974484Swnj ttypend(tp); 4984484Swnj nread = tp->t_canq.c_cc; 4994484Swnj if (tp->t_flags & (RAW|CBREAK)) 5004484Swnj nread += tp->t_rawq.c_cc; 5014484Swnj return (nread); 5024484Swnj } 5034484Swnj 5045408Swnj ttselect(dev, rw) 5054484Swnj dev_t dev; 5065408Swnj int rw; 5074484Swnj { 5084484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5094484Swnj int nread; 5105408Swnj int s = spl5(); 5114484Swnj 5125408Swnj switch (rw) { 5134484Swnj 5144484Swnj case FREAD: 5154484Swnj nread = ttnread(tp); 5164484Swnj if (nread > 0) 5175408Swnj goto win; 5184938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5195408Swnj tp->t_state |= TS_RCOLL; 5204484Swnj else 5214484Swnj tp->t_rsel = u.u_procp; 5225408Swnj break; 5234484Swnj 5245408Swnj case FWRITE: 5255408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5265408Swnj goto win; 5275408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5285408Swnj tp->t_state |= TS_WCOLL; 5295408Swnj else 5305408Swnj tp->t_wsel = u.u_procp; 5315408Swnj break; 5324484Swnj } 5335408Swnj splx(s); 5345408Swnj return (0); 5355408Swnj win: 5365408Swnj splx(s); 5375408Swnj return (1); 5384484Swnj } 539