1*5614Swnj /* tty.c 4.19 82/01/24 */ 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 /* 285*5614Swnj * Prevent more opens on channel 286*5614Swnj */ 287*5614Swnj case TIOCEXCL: 288*5614Swnj tp->t_state |= TS_XCLUDE; 289*5614Swnj break; 290*5614Swnj 291*5614Swnj case TIOCNXCL: 292*5614Swnj tp->t_state &= ~TS_XCLUDE; 293*5614Swnj break; 294*5614Swnj 295*5614Swnj /* 29639Sbill * Set new parameters 29739Sbill */ 29839Sbill case TIOCSETP: 299191Sbill case TIOCSETN: 30039Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 30139Sbill u.u_error = EFAULT; 30239Sbill return(1); 30339Sbill } 304121Sbill (void) spl5(); 3054484Swnj if (tp->t_flags&RAW || iocb.sg_flags&RAW || 3064484Swnj com == TIOCSETP) 3074484Swnj wflushtty(tp); 3084484Swnj else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 3094484Swnj if (iocb.sg_flags & CBREAK) { 3104484Swnj catq(&tp->t_rawq, &tp->t_canq); 3114484Swnj tq = tp->t_rawq; 3124484Swnj tp->t_rawq = tp->t_canq; 3134484Swnj tp->t_canq = tq; 3144484Swnj } else { 3154484Swnj tp->t_local |= LPENDIN; 3164484Swnj ttwakeup(tp); 317174Sbill } 318174Sbill } 3194484Swnj tp->t_ispeed = iocb.sg_ispeed; 3204484Swnj tp->t_ospeed = iocb.sg_ospeed; 321174Sbill tp->t_erase = iocb.sg_erase; 322174Sbill tp->t_kill = iocb.sg_kill; 323174Sbill tp->t_flags = iocb.sg_flags; 3243941Sbugs if (tp->t_flags & RAW) { 3255408Swnj tp->t_state &= ~TS_TTSTOP; 3263941Sbugs ttstart(tp); 3273941Sbugs } 328121Sbill (void) spl0(); 32939Sbill break; 33039Sbill 33139Sbill /* 332903Sbill * Send current parameters to user 33339Sbill */ 33439Sbill case TIOCGETP: 335174Sbill iocb.sg_ispeed = tp->t_ispeed; 336174Sbill iocb.sg_ospeed = tp->t_ospeed; 337174Sbill iocb.sg_erase = tp->t_erase; 338174Sbill iocb.sg_kill = tp->t_kill; 339174Sbill iocb.sg_flags = tp->t_flags; 34039Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 34139Sbill u.u_error = EFAULT; 34239Sbill break; 34339Sbill 34439Sbill /* 34539Sbill * Hang up line on last close 34639Sbill */ 34739Sbill case TIOCHPCL: 3485408Swnj tp->t_state |= TS_HUPCLS; 34939Sbill break; 35039Sbill 3513942Sbugs case TIOCFLUSH: { 3523942Sbugs int flags; 3533942Sbugs if (addr == 0) 3543942Sbugs flags = FREAD|FWRITE; 3553942Sbugs else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 3563942Sbugs u.u_error = EFAULT; 3573983Sroot return(1); 3583942Sbugs } 3593942Sbugs flushtty(tp, flags); 36039Sbill break; 3613944Sbugs } 36239Sbill 3635408Swnj case FIONBIO: { 3645408Swnj int nbio; 3655408Swnj if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 3665408Swnj u.u_error = EFAULT; 3675408Swnj return(1); 3685408Swnj } 3695408Swnj if (nbio) 3705408Swnj tp->t_state |= TS_NBIO; 3715408Swnj else 3725408Swnj tp->t_state &= ~TS_NBIO; 3735408Swnj break; 3745408Swnj } 3755408Swnj 37639Sbill /* 377903Sbill * Set and fetch special characters 37839Sbill */ 37939Sbill case TIOCSETC: 380174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 38139Sbill u.u_error = EFAULT; 38239Sbill break; 38339Sbill 38439Sbill case TIOCGETC: 385174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 38639Sbill u.u_error = EFAULT; 38739Sbill break; 38839Sbill 389174Sbill /* local ioctls */ 390903Sbill /* 391903Sbill * Set/get local special characters. 392903Sbill */ 393174Sbill case TIOCSLTC: 394174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 395174Sbill u.u_error = EFAULT; 396174Sbill break; 397174Sbill 398174Sbill case TIOCGLTC: 399174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 400174Sbill u.u_error = EFAULT; 401174Sbill break; 402174Sbill 403903Sbill /* 404903Sbill * Return number of characters immediately available. 405903Sbill */ 406174Sbill case FIONREAD: { 4074484Swnj off_t nread = ttnread(tp); 408174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 409174Sbill u.u_error = EFAULT; 410174Sbill break; 411174Sbill } 412174Sbill 413174Sbill /* 414174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 415174Sbill */ 416174Sbill case TIOCSPGRP: 417728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 418728Sbill u.u_error = EFAULT; 419174Sbill break; 420174Sbill 421174Sbill case TIOCGPGRP: 422174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 423174Sbill u.u_error = EFAULT; 424174Sbill break; 425174Sbill 426174Sbill /* 427174Sbill * Modify local mode word. 428174Sbill */ 429174Sbill case TIOCLBIS: 430728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 431728Sbill u.u_error = EFAULT; 432728Sbill else 433728Sbill tp->t_local |= temp; 434174Sbill break; 435174Sbill 436174Sbill case TIOCLBIC: 437728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 438728Sbill u.u_error = EFAULT; 439728Sbill else 440728Sbill tp->t_local &= ~temp; 441174Sbill break; 442174Sbill 443174Sbill case TIOCLSET: 444728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 445728Sbill u.u_error = EFAULT; 446728Sbill else 447728Sbill tp->t_local = temp; 448174Sbill break; 449174Sbill 450174Sbill case TIOCLGET: 451174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 452174Sbill u.u_error = EFAULT; 453174Sbill break; 454174Sbill 455903Sbill /* 456903Sbill * Return number of characters in 457903Sbill * the output. 458903Sbill */ 459213Sbill case TIOCOUTQ: 460213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 461213Sbill u.u_error = EFAULT; 462213Sbill break; 463213Sbill 464903Sbill /* 465903Sbill * Simulate typing of a character at the terminal. 466903Sbill */ 467887Sbill case TIOCSTI: 468887Sbill c = fubyte(addr); 469887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 470887Sbill u.u_error = EFAULT; 471887Sbill else 472887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 473887Sbill break; 4745573Swnj 4755573Swnj case TIOCSTOP: 4765573Swnj c = spl5(); 4775573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4785573Swnj tp->t_state |= TS_TTSTOP; 4795573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4805573Swnj } 4815573Swnj splx(c); 4825573Swnj break; 4835573Swnj 4845573Swnj case TIOCSTART: 4855573Swnj c = spl5(); 4865573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4875573Swnj tp->t_state &= ~TS_TTSTOP; 4885573Swnj tp->t_local &= ~LFLUSHO; 4895573Swnj ttstart(tp); 4905573Swnj } 4915573Swnj splx(c); 4925573Swnj break; 4935573Swnj 494174Sbill /* end of locals */ 495887Sbill 49639Sbill default: 49739Sbill return(0); 49839Sbill } 49939Sbill return(1); 50039Sbill } 5014484Swnj 5024484Swnj ttnread(tp) 5034484Swnj struct tty *tp; 5044484Swnj { 5054484Swnj int nread = 0; 5064484Swnj 5074484Swnj if (tp->t_local & LPENDIN) 5084484Swnj ttypend(tp); 5094484Swnj nread = tp->t_canq.c_cc; 5104484Swnj if (tp->t_flags & (RAW|CBREAK)) 5114484Swnj nread += tp->t_rawq.c_cc; 5124484Swnj return (nread); 5134484Swnj } 5144484Swnj 5155408Swnj ttselect(dev, rw) 5164484Swnj dev_t dev; 5175408Swnj int rw; 5184484Swnj { 5194484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5204484Swnj int nread; 5215408Swnj int s = spl5(); 5224484Swnj 5235408Swnj switch (rw) { 5244484Swnj 5254484Swnj case FREAD: 5264484Swnj nread = ttnread(tp); 5274484Swnj if (nread > 0) 5285408Swnj goto win; 5294938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5305408Swnj tp->t_state |= TS_RCOLL; 5314484Swnj else 5324484Swnj tp->t_rsel = u.u_procp; 5335408Swnj break; 5344484Swnj 5355408Swnj case FWRITE: 5365408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5375408Swnj goto win; 5385408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5395408Swnj tp->t_state |= TS_WCOLL; 5405408Swnj else 5415408Swnj tp->t_wsel = u.u_procp; 5425408Swnj break; 5434484Swnj } 5445408Swnj splx(s); 5455408Swnj return (0); 5465408Swnj win: 5475408Swnj splx(s); 5485408Swnj return (1); 5494484Swnj } 550