1*6216Swnj /* tty.c 4.22 82/03/15 */ 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 && 2425626Swnj u.u_signal[SIGTTOU] != SIG_HOLD 2435626Swnj /* 2445626Swnj && 245903Sbill (u.u_procp->p_flag&SDETACH)==0) { 2465626Swnj */ 2475626Swnj ) { 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 382*6216Swnj case FIOASYNC: { 383*6216Swnj int async; 384*6216Swnj if (copyin(addr, (caddr_t)&async, sizeof (async))) { 385*6216Swnj u.u_error = EFAULT; 386*6216Swnj return(1); 387*6216Swnj } 388*6216Swnj if (async) 389*6216Swnj tp->t_state |= TS_ASYNC; 390*6216Swnj else 391*6216Swnj tp->t_state &= ~TS_ASYNC; 392*6216Swnj break; 393*6216Swnj } 394*6216Swnj 39539Sbill /* 396903Sbill * Set and fetch special characters 39739Sbill */ 39839Sbill case TIOCSETC: 399174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 40039Sbill u.u_error = EFAULT; 40139Sbill break; 40239Sbill 40339Sbill case TIOCGETC: 404174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 40539Sbill u.u_error = EFAULT; 40639Sbill break; 40739Sbill 408174Sbill /* local ioctls */ 409903Sbill /* 410903Sbill * Set/get local special characters. 411903Sbill */ 412174Sbill case TIOCSLTC: 413174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 414174Sbill u.u_error = EFAULT; 415174Sbill break; 416174Sbill 417174Sbill case TIOCGLTC: 418174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 419174Sbill u.u_error = EFAULT; 420174Sbill break; 421174Sbill 422903Sbill /* 423903Sbill * Return number of characters immediately available. 424903Sbill */ 425174Sbill case FIONREAD: { 4264484Swnj off_t nread = ttnread(tp); 427174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 428174Sbill u.u_error = EFAULT; 429174Sbill break; 430174Sbill } 431174Sbill 432174Sbill /* 433174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 434174Sbill */ 435174Sbill case TIOCSPGRP: 436728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 437728Sbill u.u_error = EFAULT; 438174Sbill break; 439174Sbill 440174Sbill case TIOCGPGRP: 441174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 442174Sbill u.u_error = EFAULT; 443174Sbill break; 444174Sbill 445174Sbill /* 446174Sbill * Modify local mode word. 447174Sbill */ 448174Sbill case TIOCLBIS: 449728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 450728Sbill u.u_error = EFAULT; 451728Sbill else 452728Sbill tp->t_local |= temp; 453174Sbill break; 454174Sbill 455174Sbill case TIOCLBIC: 456728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 457728Sbill u.u_error = EFAULT; 458728Sbill else 459728Sbill tp->t_local &= ~temp; 460174Sbill break; 461174Sbill 462174Sbill case TIOCLSET: 463728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 464728Sbill u.u_error = EFAULT; 465728Sbill else 466728Sbill tp->t_local = temp; 467174Sbill break; 468174Sbill 469174Sbill case TIOCLGET: 470174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 471174Sbill u.u_error = EFAULT; 472174Sbill break; 473174Sbill 474903Sbill /* 475903Sbill * Return number of characters in 476903Sbill * the output. 477903Sbill */ 478213Sbill case TIOCOUTQ: 479213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 480213Sbill u.u_error = EFAULT; 481213Sbill break; 482213Sbill 483903Sbill /* 484903Sbill * Simulate typing of a character at the terminal. 485903Sbill */ 486887Sbill case TIOCSTI: 487887Sbill c = fubyte(addr); 488887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 489887Sbill u.u_error = EFAULT; 490887Sbill else 491887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 492887Sbill break; 4935573Swnj 4945573Swnj case TIOCSTOP: 4955573Swnj c = spl5(); 4965573Swnj if ((tp->t_state & TS_TTSTOP) == 0) { 4975573Swnj tp->t_state |= TS_TTSTOP; 4985573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 4995573Swnj } 5005573Swnj splx(c); 5015573Swnj break; 5025573Swnj 5035573Swnj case TIOCSTART: 5045573Swnj c = spl5(); 5055573Swnj if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) { 5065573Swnj tp->t_state &= ~TS_TTSTOP; 5075573Swnj tp->t_local &= ~LFLUSHO; 5085573Swnj ttstart(tp); 5095573Swnj } 5105573Swnj splx(c); 5115573Swnj break; 5125573Swnj 513174Sbill /* end of locals */ 514887Sbill 51539Sbill default: 51639Sbill return(0); 51739Sbill } 51839Sbill return(1); 51939Sbill } 5204484Swnj 5214484Swnj ttnread(tp) 5224484Swnj struct tty *tp; 5234484Swnj { 5244484Swnj int nread = 0; 5254484Swnj 5264484Swnj if (tp->t_local & LPENDIN) 5274484Swnj ttypend(tp); 5284484Swnj nread = tp->t_canq.c_cc; 5294484Swnj if (tp->t_flags & (RAW|CBREAK)) 5304484Swnj nread += tp->t_rawq.c_cc; 5314484Swnj return (nread); 5324484Swnj } 5334484Swnj 5345408Swnj ttselect(dev, rw) 5354484Swnj dev_t dev; 5365408Swnj int rw; 5374484Swnj { 5384484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5394484Swnj int nread; 5405408Swnj int s = spl5(); 5414484Swnj 5425408Swnj switch (rw) { 5434484Swnj 5444484Swnj case FREAD: 5454484Swnj nread = ttnread(tp); 5464484Swnj if (nread > 0) 5475408Swnj goto win; 5484938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5495408Swnj tp->t_state |= TS_RCOLL; 5504484Swnj else 5514484Swnj tp->t_rsel = u.u_procp; 5525408Swnj break; 5534484Swnj 5545408Swnj case FWRITE: 5555408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5565408Swnj goto win; 5575408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5585408Swnj tp->t_state |= TS_WCOLL; 5595408Swnj else 5605408Swnj tp->t_wsel = u.u_procp; 5615408Swnj break; 5624484Swnj } 5635408Swnj splx(s); 5645408Swnj return (0); 5655408Swnj win: 5665408Swnj splx(s); 5675408Swnj return (1); 5684484Swnj } 569