1*5626Swnj /* tty.c 4.21 82/01/30 */ 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(); 895622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 905622Swnj && 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(); 1825622Swnj if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 1835622Swnj 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 && 242*5626Swnj u.u_signal[SIGTTOU] != SIG_HOLD 243*5626Swnj /* 244*5626Swnj && 245903Sbill (u.u_procp->p_flag&SDETACH)==0) { 246*5626Swnj */ 247*5626Swnj ) { 248903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 249903Sbill sleep((caddr_t)&lbolt, TTOPRI); 250903Sbill } 251903Sbill break; 252903Sbill } 253903Sbill 25439Sbill /* 255903Sbill * Process the ioctl. 25639Sbill */ 257903Sbill switch(com) { 258903Sbill 259903Sbill /* 260903Sbill * Get discipline number 261903Sbill */ 26239Sbill case TIOCGETD: 26339Sbill t = tp->t_line; 26439Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 26539Sbill u.u_error = EFAULT; 26639Sbill break; 26739Sbill 26839Sbill /* 269903Sbill * Set line discipline 27039Sbill */ 27139Sbill case TIOCSETD: 27239Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 27339Sbill u.u_error = EFAULT; 27439Sbill break; 27539Sbill } 27639Sbill if (t >= nldisp) { 27739Sbill u.u_error = ENXIO; 27839Sbill break; 27939Sbill } 280174Sbill (void) spl5(); 28139Sbill if (tp->t_line) 28239Sbill (*linesw[tp->t_line].l_close)(tp); 28339Sbill if (t) 28439Sbill (*linesw[t].l_open)(dev, tp, addr); 28539Sbill if (u.u_error==0) 28639Sbill tp->t_line = t; 287174Sbill (void) spl0(); 28839Sbill break; 28939Sbill 29039Sbill /* 2915614Swnj * Prevent more opens on channel 2925614Swnj */ 2935614Swnj case TIOCEXCL: 2945614Swnj tp->t_state |= TS_XCLUDE; 2955614Swnj break; 2965614Swnj 2975614Swnj case TIOCNXCL: 2985614Swnj tp->t_state &= ~TS_XCLUDE; 2995614Swnj break; 3005614Swnj 3015614Swnj /* 30239Sbill * Set new parameters 30339Sbill */ 30439Sbill case TIOCSETP: 305191Sbill case TIOCSETN: 30639Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 30739Sbill u.u_error = EFAULT; 30839Sbill return(1); 30939Sbill } 310121Sbill (void) spl5(); 3114484Swnj if (tp->t_flags&RAW || iocb.sg_flags&RAW || 3124484Swnj com == TIOCSETP) 3134484Swnj wflushtty(tp); 3144484Swnj else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 3154484Swnj if (iocb.sg_flags & CBREAK) { 3164484Swnj catq(&tp->t_rawq, &tp->t_canq); 3174484Swnj tq = tp->t_rawq; 3184484Swnj tp->t_rawq = tp->t_canq; 3194484Swnj tp->t_canq = tq; 3204484Swnj } else { 3214484Swnj tp->t_local |= LPENDIN; 3224484Swnj ttwakeup(tp); 323174Sbill } 324174Sbill } 3254484Swnj tp->t_ispeed = iocb.sg_ispeed; 3264484Swnj tp->t_ospeed = iocb.sg_ospeed; 327174Sbill tp->t_erase = iocb.sg_erase; 328174Sbill tp->t_kill = iocb.sg_kill; 329174Sbill tp->t_flags = iocb.sg_flags; 3303941Sbugs if (tp->t_flags & RAW) { 3315408Swnj tp->t_state &= ~TS_TTSTOP; 3323941Sbugs ttstart(tp); 3333941Sbugs } 334121Sbill (void) spl0(); 33539Sbill break; 33639Sbill 33739Sbill /* 338903Sbill * Send current parameters to user 33939Sbill */ 34039Sbill case TIOCGETP: 341174Sbill iocb.sg_ispeed = tp->t_ispeed; 342174Sbill iocb.sg_ospeed = tp->t_ospeed; 343174Sbill iocb.sg_erase = tp->t_erase; 344174Sbill iocb.sg_kill = tp->t_kill; 345174Sbill iocb.sg_flags = tp->t_flags; 34639Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 34739Sbill u.u_error = EFAULT; 34839Sbill break; 34939Sbill 35039Sbill /* 35139Sbill * Hang up line on last close 35239Sbill */ 35339Sbill case TIOCHPCL: 3545408Swnj tp->t_state |= TS_HUPCLS; 35539Sbill break; 35639Sbill 3573942Sbugs case TIOCFLUSH: { 3583942Sbugs int flags; 3593942Sbugs if (addr == 0) 3603942Sbugs flags = FREAD|FWRITE; 3613942Sbugs else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) { 3623942Sbugs u.u_error = EFAULT; 3633983Sroot return(1); 3643942Sbugs } 3653942Sbugs flushtty(tp, flags); 36639Sbill break; 3673944Sbugs } 36839Sbill 3695408Swnj case FIONBIO: { 3705408Swnj int nbio; 3715408Swnj if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) { 3725408Swnj u.u_error = EFAULT; 3735408Swnj return(1); 3745408Swnj } 3755408Swnj if (nbio) 3765408Swnj tp->t_state |= TS_NBIO; 3775408Swnj else 3785408Swnj tp->t_state &= ~TS_NBIO; 3795408Swnj break; 3805408Swnj } 3815408Swnj 38239Sbill /* 383903Sbill * Set and fetch special characters 38439Sbill */ 38539Sbill case TIOCSETC: 386174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 38739Sbill u.u_error = EFAULT; 38839Sbill break; 38939Sbill 39039Sbill case TIOCGETC: 391174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 39239Sbill u.u_error = EFAULT; 39339Sbill break; 39439Sbill 395174Sbill /* local ioctls */ 396903Sbill /* 397903Sbill * Set/get local special characters. 398903Sbill */ 399174Sbill case TIOCSLTC: 400174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 401174Sbill u.u_error = EFAULT; 402174Sbill break; 403174Sbill 404174Sbill case TIOCGLTC: 405174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 406174Sbill u.u_error = EFAULT; 407174Sbill break; 408174Sbill 409903Sbill /* 410903Sbill * Return number of characters immediately available. 411903Sbill */ 412174Sbill case FIONREAD: { 4134484Swnj off_t nread = ttnread(tp); 414174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 415174Sbill u.u_error = EFAULT; 416174Sbill break; 417174Sbill } 418174Sbill 419174Sbill /* 420174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 421174Sbill */ 422174Sbill case TIOCSPGRP: 423728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 424728Sbill u.u_error = EFAULT; 425174Sbill break; 426174Sbill 427174Sbill case TIOCGPGRP: 428174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 429174Sbill u.u_error = EFAULT; 430174Sbill break; 431174Sbill 432174Sbill /* 433174Sbill * Modify local mode word. 434174Sbill */ 435174Sbill case TIOCLBIS: 436728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 437728Sbill u.u_error = EFAULT; 438728Sbill else 439728Sbill tp->t_local |= temp; 440174Sbill break; 441174Sbill 442174Sbill case TIOCLBIC: 443728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 444728Sbill u.u_error = EFAULT; 445728Sbill else 446728Sbill tp->t_local &= ~temp; 447174Sbill break; 448174Sbill 449174Sbill case TIOCLSET: 450728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 451728Sbill u.u_error = EFAULT; 452728Sbill else 453728Sbill tp->t_local = temp; 454174Sbill break; 455174Sbill 456174Sbill case TIOCLGET: 457174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 458174Sbill u.u_error = EFAULT; 459174Sbill break; 460174Sbill 461903Sbill /* 462903Sbill * Return number of characters in 463903Sbill * the output. 464903Sbill */ 465213Sbill case TIOCOUTQ: 466213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 467213Sbill u.u_error = EFAULT; 468213Sbill break; 469213Sbill 470903Sbill /* 471903Sbill * Simulate typing of a character at the terminal. 472903Sbill */ 473887Sbill case TIOCSTI: 474887Sbill c = fubyte(addr); 475887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 476887Sbill u.u_error = EFAULT; 477887Sbill else 478887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 479887Sbill break; 4805573Swnj 4815573Swnj case TIOCSTOP: 4825573Swnj c = spl5(); 4835573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4845573Swnj tp->t_state |= TS_TTSTOP; 4855573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4865573Swnj } 4875573Swnj splx(c); 4885573Swnj break; 4895573Swnj 4905573Swnj case TIOCSTART: 4915573Swnj c = spl5(); 4925573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 4935573Swnj tp->t_state &= ~TS_TTSTOP; 4945573Swnj tp->t_local &= ~LFLUSHO; 4955573Swnj ttstart(tp); 4965573Swnj } 4975573Swnj splx(c); 4985573Swnj break; 4995573Swnj 500174Sbill /* end of locals */ 501887Sbill 50239Sbill default: 50339Sbill return(0); 50439Sbill } 50539Sbill return(1); 50639Sbill } 5074484Swnj 5084484Swnj ttnread(tp) 5094484Swnj struct tty *tp; 5104484Swnj { 5114484Swnj int nread = 0; 5124484Swnj 5134484Swnj if (tp->t_local & LPENDIN) 5144484Swnj ttypend(tp); 5154484Swnj nread = tp->t_canq.c_cc; 5164484Swnj if (tp->t_flags & (RAW|CBREAK)) 5174484Swnj nread += tp->t_rawq.c_cc; 5184484Swnj return (nread); 5194484Swnj } 5204484Swnj 5215408Swnj ttselect(dev, rw) 5224484Swnj dev_t dev; 5235408Swnj int rw; 5244484Swnj { 5254484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5264484Swnj int nread; 5275408Swnj int s = spl5(); 5284484Swnj 5295408Swnj switch (rw) { 5304484Swnj 5314484Swnj case FREAD: 5324484Swnj nread = ttnread(tp); 5334484Swnj if (nread > 0) 5345408Swnj goto win; 5354938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5365408Swnj tp->t_state |= TS_RCOLL; 5374484Swnj else 5384484Swnj tp->t_rsel = u.u_procp; 5395408Swnj break; 5404484Swnj 5415408Swnj case FWRITE: 5425408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5435408Swnj goto win; 5445408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5455408Swnj tp->t_state |= TS_WCOLL; 5465408Swnj else 5475408Swnj tp->t_wsel = u.u_procp; 5485408Swnj break; 5494484Swnj } 5505408Swnj splx(s); 5515408Swnj return (0); 5525408Swnj win: 5535408Swnj splx(s); 5545408Swnj return (1); 5554484Swnj } 556