1*5622Swnj /* tty.c 4.20 82/01/25 */ 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(); 89*5622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 90*5622Swnj && tp->t_oproc) { /* kludge for pty */ 91903Sbill (*tp->t_oproc)(tp); 925408Swnj tp->t_state |= TS_ASLEEP; 93903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 94903Sbill } 955426Swnj flushtty(tp, FREAD); 96903Sbill (void) spl0(); 9739Sbill } 9839Sbill 9939Sbill /* 100903Sbill * flush all TTY queues 10139Sbill */ 102903Sbill flushtty(tp, rw) 103903Sbill register struct tty *tp; 10439Sbill { 105903Sbill register s; 106903Sbill 107903Sbill s = spl6(); 108903Sbill if (rw & FREAD) { 109903Sbill while (getc(&tp->t_canq) >= 0) 110903Sbill ; 111903Sbill wakeup((caddr_t)&tp->t_rawq); 112903Sbill } 113903Sbill if (rw & FWRITE) { 114903Sbill wakeup((caddr_t)&tp->t_outq); 1155408Swnj tp->t_state &= ~TS_TTSTOP; 1165426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 117903Sbill while (getc(&tp->t_outq) >= 0) 118903Sbill ; 119903Sbill } 120903Sbill if (rw & FREAD) { 121903Sbill while (getc(&tp->t_rawq) >= 0) 122903Sbill ; 123903Sbill tp->t_delct = 0; 124903Sbill tp->t_rocount = 0; /* local */ 125903Sbill tp->t_rocol = 0; 126903Sbill tp->t_lstate = 0; 127903Sbill } 128903Sbill splx(s); 12939Sbill } 13039Sbill 131903Sbill /* 132903Sbill * Send stop character on input overflow. 133903Sbill */ 134903Sbill ttyblock(tp) 135903Sbill register struct tty *tp; 13639Sbill { 137903Sbill register x; 138903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 139903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 140903Sbill flushtty(tp, FREAD|FWRITE); 1415408Swnj tp->t_state &= ~TS_TBLOCK; 142903Sbill } 143903Sbill if (x >= TTYHOG/2) { 144903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 1455408Swnj tp->t_state |= TS_TBLOCK; 146903Sbill tp->t_char++; 147903Sbill ttstart(tp); 148903Sbill } 149903Sbill } 15039Sbill } 15139Sbill 15239Sbill /* 153903Sbill * Restart typewriter output following a delay 154903Sbill * timeout. 155903Sbill * The name of the routine is passed to the timeout 156903Sbill * subroutine and it is called during a clock interrupt. 157121Sbill */ 158903Sbill ttrstrt(tp) 159121Sbill register struct tty *tp; 160121Sbill { 161121Sbill 1623351Swnj if (tp == 0) { 1633351Swnj printf("ttrstrt: arg was 0!\n"); 1643351Swnj return; 1653351Swnj } 1665408Swnj tp->t_state &= ~TS_TIMEOUT; 167903Sbill ttstart(tp); 168121Sbill } 169121Sbill 170121Sbill /* 171903Sbill * Start output on the typewriter. It is used from the top half 172903Sbill * after some characters have been put on the output queue, 173903Sbill * from the interrupt routine to transmit the next 174903Sbill * character, and after a timeout has finished. 17539Sbill */ 176903Sbill ttstart(tp) 177903Sbill register struct tty *tp; 17839Sbill { 179903Sbill register s; 18039Sbill 181903Sbill s = spl5(); 182*5622Swnj if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 183*5622Swnj tp->t_oproc) /* kludge for pty */ 184903Sbill (*tp->t_oproc)(tp); 185903Sbill splx(s); 18639Sbill } 18739Sbill 18839Sbill /* 189903Sbill * Common code for tty ioctls. 19039Sbill */ 1911780Sbill /*ARGSUSED*/ 1921904Swnj ttioctl(tp, com, addr, flag) 19339Sbill register struct tty *tp; 19439Sbill caddr_t addr; 19539Sbill { 1961904Swnj int dev; 19739Sbill unsigned t; 198174Sbill struct sgttyb iocb; 199191Sbill struct clist tq; 20039Sbill extern int nldisp; 201887Sbill register c; 202728Sbill int temp; 20339Sbill 204903Sbill /* 205915Sbill * This is especially so that isatty() will 206915Sbill * fail when carrier is gone. 207915Sbill */ 2085408Swnj if ((tp->t_state&TS_CARR_ON) == 0) { 209915Sbill u.u_error = EBADF; 210915Sbill return (1); 211915Sbill } 212915Sbill 2131904Swnj dev = tp->t_dev; 214915Sbill /* 215903Sbill * If the ioctl involves modification, 216903Sbill * insist on being able to write the device, 217903Sbill * and hang if in the background. 218903Sbill */ 21939Sbill switch(com) { 22039Sbill 221915Sbill case TIOCSETD: 222915Sbill case TIOCSETP: 223915Sbill case TIOCSETN: 224903Sbill case TIOCFLUSH: 225903Sbill case TIOCSETC: 226903Sbill case TIOCSLTC: 227903Sbill case TIOCSPGRP: 228903Sbill case TIOCLBIS: 229903Sbill case TIOCLBIC: 230903Sbill case TIOCLSET: 231903Sbill case TIOCSTI: 232915Sbill /* this is reasonable, but impractical... 233903Sbill if ((flag & FWRITE) == 0) { 234903Sbill u.u_error = EBADF; 235903Sbill return (1); 236903Sbill } 237915Sbill */ 238903Sbill while (tp->t_line == NTTYDISC && 239903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 240903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 241903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 242903Sbill u.u_signal[SIGTTOU] != SIG_HOLD && 243903Sbill (u.u_procp->p_flag&SDETACH)==0) { 244903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 245903Sbill sleep((caddr_t)&lbolt, TTOPRI); 246903Sbill } 247903Sbill break; 248903Sbill } 249903Sbill 25039Sbill /* 251903Sbill * Process the ioctl. 25239Sbill */ 253903Sbill switch(com) { 254903Sbill 255903Sbill /* 256903Sbill * Get discipline number 257903Sbill */ 25839Sbill case TIOCGETD: 25939Sbill t = tp->t_line; 26039Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 26139Sbill u.u_error = EFAULT; 26239Sbill break; 26339Sbill 26439Sbill /* 265903Sbill * Set line discipline 26639Sbill */ 26739Sbill case TIOCSETD: 26839Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 26939Sbill u.u_error = EFAULT; 27039Sbill break; 27139Sbill } 27239Sbill if (t >= nldisp) { 27339Sbill u.u_error = ENXIO; 27439Sbill break; 27539Sbill } 276174Sbill (void) spl5(); 27739Sbill if (tp->t_line) 27839Sbill (*linesw[tp->t_line].l_close)(tp); 27939Sbill if (t) 28039Sbill (*linesw[t].l_open)(dev, tp, addr); 28139Sbill if (u.u_error==0) 28239Sbill tp->t_line = t; 283174Sbill (void) spl0(); 28439Sbill break; 28539Sbill 28639Sbill /* 2875614Swnj * Prevent more opens on channel 2885614Swnj */ 2895614Swnj case TIOCEXCL: 2905614Swnj tp->t_state |= TS_XCLUDE; 2915614Swnj break; 2925614Swnj 2935614Swnj case TIOCNXCL: 2945614Swnj tp->t_state &= ~TS_XCLUDE; 2955614Swnj break; 2965614Swnj 2975614Swnj /* 29839Sbill * Set new parameters 29939Sbill */ 30039Sbill case TIOCSETP: 301191Sbill case TIOCSETN: 30239Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 30339Sbill u.u_error = EFAULT; 30439Sbill return(1); 30539Sbill } 306121Sbill (void) spl5(); 3074484Swnj if (tp->t_flags&RAW || iocb.sg_flags&RAW || 3084484Swnj com == TIOCSETP) 3094484Swnj wflushtty(tp); 3104484Swnj else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 3114484Swnj if (iocb.sg_flags & CBREAK) { 3124484Swnj catq(&tp->t_rawq, &tp->t_canq); 3134484Swnj tq = tp->t_rawq; 3144484Swnj tp->t_rawq = tp->t_canq; 3154484Swnj tp->t_canq = tq; 3164484Swnj } else { 3174484Swnj tp->t_local |= LPENDIN; 3184484Swnj ttwakeup(tp); 319174Sbill } 320174Sbill } 3214484Swnj tp->t_ispeed = iocb.sg_ispeed; 3224484Swnj tp->t_ospeed = iocb.sg_ospeed; 323174Sbill tp->t_erase = iocb.sg_erase; 324174Sbill tp->t_kill = iocb.sg_kill; 325174Sbill tp->t_flags = iocb.sg_flags; 3263941Sbugs if (tp->t_flags & RAW) { 3275408Swnj tp->t_state &= ~TS_TTSTOP; 3283941Sbugs ttstart(tp); 3293941Sbugs } 330121Sbill (void) spl0(); 33139Sbill break; 33239Sbill 33339Sbill /* 334903Sbill * Send current parameters to user 33539Sbill */ 33639Sbill case TIOCGETP: 337174Sbill iocb.sg_ispeed = tp->t_ispeed; 338174Sbill iocb.sg_ospeed = tp->t_ospeed; 339174Sbill iocb.sg_erase = tp->t_erase; 340174Sbill iocb.sg_kill = tp->t_kill; 341174Sbill iocb.sg_flags = tp->t_flags; 34239Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 34339Sbill u.u_error = EFAULT; 34439Sbill break; 34539Sbill 34639Sbill /* 34739Sbill * Hang up line on last close 34839Sbill */ 34939Sbill case TIOCHPCL: 3505408Swnj tp->t_state |= TS_HUPCLS; 35139Sbill break; 35239Sbill 3533942Sbugs case TIOCFLUSH: { 3543942Sbugs int flags; 3553942Sbugs if (addr == 0) 3563942Sbugs flags = FREAD|FWRITE; 3573942Sbugs else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 3583942Sbugs u.u_error = EFAULT; 3593983Sroot return(1); 3603942Sbugs } 3613942Sbugs flushtty(tp, flags); 36239Sbill break; 3633944Sbugs } 36439Sbill 3655408Swnj case FIONBIO: { 3665408Swnj int nbio; 3675408Swnj if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 3685408Swnj u.u_error = EFAULT; 3695408Swnj return(1); 3705408Swnj } 3715408Swnj if (nbio) 3725408Swnj tp->t_state |= TS_NBIO; 3735408Swnj else 3745408Swnj tp->t_state &= ~TS_NBIO; 3755408Swnj break; 3765408Swnj } 3775408Swnj 37839Sbill /* 379903Sbill * Set and fetch special characters 38039Sbill */ 38139Sbill case TIOCSETC: 382174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 38339Sbill u.u_error = EFAULT; 38439Sbill break; 38539Sbill 38639Sbill case TIOCGETC: 387174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 38839Sbill u.u_error = EFAULT; 38939Sbill break; 39039Sbill 391174Sbill /* local ioctls */ 392903Sbill /* 393903Sbill * Set/get local special characters. 394903Sbill */ 395174Sbill case TIOCSLTC: 396174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 397174Sbill u.u_error = EFAULT; 398174Sbill break; 399174Sbill 400174Sbill case TIOCGLTC: 401174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 402174Sbill u.u_error = EFAULT; 403174Sbill break; 404174Sbill 405903Sbill /* 406903Sbill * Return number of characters immediately available. 407903Sbill */ 408174Sbill case FIONREAD: { 4094484Swnj off_t nread = ttnread(tp); 410174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 411174Sbill u.u_error = EFAULT; 412174Sbill break; 413174Sbill } 414174Sbill 415174Sbill /* 416174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 417174Sbill */ 418174Sbill case TIOCSPGRP: 419728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 420728Sbill u.u_error = EFAULT; 421174Sbill break; 422174Sbill 423174Sbill case TIOCGPGRP: 424174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 425174Sbill u.u_error = EFAULT; 426174Sbill break; 427174Sbill 428174Sbill /* 429174Sbill * Modify local mode word. 430174Sbill */ 431174Sbill case TIOCLBIS: 432728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 433728Sbill u.u_error = EFAULT; 434728Sbill else 435728Sbill tp->t_local |= temp; 436174Sbill break; 437174Sbill 438174Sbill case TIOCLBIC: 439728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 440728Sbill u.u_error = EFAULT; 441728Sbill else 442728Sbill tp->t_local &= ~temp; 443174Sbill break; 444174Sbill 445174Sbill case TIOCLSET: 446728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 447728Sbill u.u_error = EFAULT; 448728Sbill else 449728Sbill tp->t_local = temp; 450174Sbill break; 451174Sbill 452174Sbill case TIOCLGET: 453174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 454174Sbill u.u_error = EFAULT; 455174Sbill break; 456174Sbill 457903Sbill /* 458903Sbill * Return number of characters in 459903Sbill * the output. 460903Sbill */ 461213Sbill case TIOCOUTQ: 462213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 463213Sbill u.u_error = EFAULT; 464213Sbill break; 465213Sbill 466903Sbill /* 467903Sbill * Simulate typing of a character at the terminal. 468903Sbill */ 469887Sbill case TIOCSTI: 470887Sbill c = fubyte(addr); 471887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 472887Sbill u.u_error = EFAULT; 473887Sbill else 474887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 475887Sbill break; 4765573Swnj 4775573Swnj case TIOCSTOP: 4785573Swnj c = spl5(); 4795573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4805573Swnj tp->t_state |= TS_TTSTOP; 4815573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4825573Swnj } 4835573Swnj splx(c); 4845573Swnj break; 4855573Swnj 4865573Swnj case TIOCSTART: 4875573Swnj c = spl5(); 4885573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4895573Swnj tp->t_state &= ~TS_TTSTOP; 4905573Swnj tp->t_local &= ~LFLUSHO; 4915573Swnj ttstart(tp); 4925573Swnj } 4935573Swnj splx(c); 4945573Swnj break; 4955573Swnj 496174Sbill /* end of locals */ 497887Sbill 49839Sbill default: 49939Sbill return(0); 50039Sbill } 50139Sbill return(1); 50239Sbill } 5034484Swnj 5044484Swnj ttnread(tp) 5054484Swnj struct tty *tp; 5064484Swnj { 5074484Swnj int nread = 0; 5084484Swnj 5094484Swnj if (tp->t_local & LPENDIN) 5104484Swnj ttypend(tp); 5114484Swnj nread = tp->t_canq.c_cc; 5124484Swnj if (tp->t_flags & (RAW|CBREAK)) 5134484Swnj nread += tp->t_rawq.c_cc; 5144484Swnj return (nread); 5154484Swnj } 5164484Swnj 5175408Swnj ttselect(dev, rw) 5184484Swnj dev_t dev; 5195408Swnj int rw; 5204484Swnj { 5214484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5224484Swnj int nread; 5235408Swnj int s = spl5(); 5244484Swnj 5255408Swnj switch (rw) { 5264484Swnj 5274484Swnj case FREAD: 5284484Swnj nread = ttnread(tp); 5294484Swnj if (nread > 0) 5305408Swnj goto win; 5314938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5325408Swnj tp->t_state |= TS_RCOLL; 5334484Swnj else 5344484Swnj tp->t_rsel = u.u_procp; 5355408Swnj break; 5364484Swnj 5375408Swnj case FWRITE: 5385408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5395408Swnj goto win; 5405408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5415408Swnj tp->t_state |= TS_WCOLL; 5425408Swnj else 5435408Swnj tp->t_wsel = u.u_procp; 5445408Swnj break; 5454484Swnj } 5465408Swnj splx(s); 5475408Swnj return (0); 5485408Swnj win: 5495408Swnj splx(s); 5505408Swnj return (1); 5514484Swnj } 552