1*4484Swnj /* tty.c 4.13 81/10/11 */ 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) 8539Sbill register struct tty *tp; 8639Sbill { 8739Sbill 88903Sbill (void) spl5(); 89903Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 90903Sbill (*tp->t_oproc)(tp); 91903Sbill tp->t_state |= ASLEEP; 92903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 93903Sbill } 94903Sbill flushtty(tp, FREAD|FWRITE); 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); 114903Sbill tp->t_state &= ~TTSTOP; 115903Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 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); 140903Sbill tp->t_state &= ~TBLOCK; 141903Sbill } 142903Sbill if (x >= TTYHOG/2) { 143903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 144903Sbill tp->t_state |= 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 } 165903Sbill tp->t_state &= ~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(); 181903Sbill if((tp->t_state&(TIMEOUT|TTSTOP|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 */ 206915Sbill if ((tp->t_state&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(); 294*4484Swnj if (tp->t_flags&RAW || iocb.sg_flags&RAW || 295*4484Swnj com == TIOCSETP) 296*4484Swnj wflushtty(tp); 297*4484Swnj else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 298*4484Swnj if (iocb.sg_flags & CBREAK) { 299*4484Swnj catq(&tp->t_rawq, &tp->t_canq); 300*4484Swnj tq = tp->t_rawq; 301*4484Swnj tp->t_rawq = tp->t_canq; 302*4484Swnj tp->t_canq = tq; 303*4484Swnj } else { 304*4484Swnj tp->t_local |= LPENDIN; 305*4484Swnj ttwakeup(tp); 306174Sbill } 307174Sbill } 308*4484Swnj tp->t_ispeed = iocb.sg_ispeed; 309*4484Swnj 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) { 3143941Sbugs tp->t_state &= ~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: 33739Sbill tp->t_state |= 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 35239Sbill /* 353903Sbill * Set and fetch special characters 35439Sbill */ 35539Sbill case TIOCSETC: 356174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 35739Sbill u.u_error = EFAULT; 35839Sbill break; 35939Sbill 36039Sbill case TIOCGETC: 361174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 36239Sbill u.u_error = EFAULT; 36339Sbill break; 36439Sbill 365174Sbill /* local ioctls */ 366903Sbill /* 367903Sbill * Set/get local special characters. 368903Sbill */ 369174Sbill case TIOCSLTC: 370174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 371174Sbill u.u_error = EFAULT; 372174Sbill break; 373174Sbill 374174Sbill case TIOCGLTC: 375174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 376174Sbill u.u_error = EFAULT; 377174Sbill break; 378174Sbill 379903Sbill /* 380903Sbill * Return number of characters immediately available. 381903Sbill */ 382174Sbill case FIONREAD: { 383*4484Swnj off_t nread = ttnread(tp); 384174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 385174Sbill u.u_error = EFAULT; 386174Sbill break; 387174Sbill } 388174Sbill 389174Sbill /* 390174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 391174Sbill */ 392174Sbill case TIOCSPGRP: 393728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 394728Sbill u.u_error = EFAULT; 395174Sbill break; 396174Sbill 397174Sbill case TIOCGPGRP: 398174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 399174Sbill u.u_error = EFAULT; 400174Sbill break; 401174Sbill 402174Sbill /* 403174Sbill * Modify local mode word. 404174Sbill */ 405174Sbill case TIOCLBIS: 406728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 407728Sbill u.u_error = EFAULT; 408728Sbill else 409728Sbill tp->t_local |= temp; 410174Sbill break; 411174Sbill 412174Sbill case TIOCLBIC: 413728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 414728Sbill u.u_error = EFAULT; 415728Sbill else 416728Sbill tp->t_local &= ~temp; 417174Sbill break; 418174Sbill 419174Sbill case TIOCLSET: 420728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 421728Sbill u.u_error = EFAULT; 422728Sbill else 423728Sbill tp->t_local = temp; 424174Sbill break; 425174Sbill 426174Sbill case TIOCLGET: 427174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 428174Sbill u.u_error = EFAULT; 429174Sbill break; 430174Sbill 431903Sbill /* 432903Sbill * Return number of characters in 433903Sbill * the output. 434903Sbill */ 435213Sbill case TIOCOUTQ: 436213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 437213Sbill u.u_error = EFAULT; 438213Sbill break; 439213Sbill 440903Sbill /* 441903Sbill * Simulate typing of a character at the terminal. 442903Sbill */ 443887Sbill case TIOCSTI: 444887Sbill c = fubyte(addr); 445887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 446887Sbill u.u_error = EFAULT; 447887Sbill else 448887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 449887Sbill break; 450174Sbill /* end of locals */ 451887Sbill 45239Sbill default: 45339Sbill return(0); 45439Sbill } 45539Sbill return(1); 45639Sbill } 457*4484Swnj 458*4484Swnj ttnread(tp) 459*4484Swnj struct tty *tp; 460*4484Swnj { 461*4484Swnj int nread = 0; 462*4484Swnj 463*4484Swnj if (tp->t_local & LPENDIN) 464*4484Swnj ttypend(tp); 465*4484Swnj nread = tp->t_canq.c_cc; 466*4484Swnj if (tp->t_flags & (RAW|CBREAK)) 467*4484Swnj nread += tp->t_rawq.c_cc; 468*4484Swnj return (nread); 469*4484Swnj } 470*4484Swnj 471*4484Swnj ttselect(dev, flag) 472*4484Swnj dev_t dev; 473*4484Swnj int flag; 474*4484Swnj { 475*4484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 476*4484Swnj int nread; 477*4484Swnj 478*4484Swnj switch (flag) { 479*4484Swnj 480*4484Swnj case FREAD: 481*4484Swnj nread = ttnread(tp); 482*4484Swnj if (nread > 0) 483*4484Swnj return (1); 484*4484Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)select) 485*4484Swnj tp->t_state |= RCOLL; 486*4484Swnj else 487*4484Swnj tp->t_rsel = u.u_procp; 488*4484Swnj return (0); 489*4484Swnj 490*4484Swnj default: 491*4484Swnj return (1); 492*4484Swnj } 493*4484Swnj } 494