1*915Sbill /* tty.c 3.18 09/25/80 */ 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/mx.h" 1339Sbill #include "../h/inode.h" 1439Sbill #include "../h/file.h" 1539Sbill #include "../h/reg.h" 1639Sbill #include "../h/conf.h" 1739Sbill #include "../h/buf.h" 18340Sbill #include "../h/dk.h" 1939Sbill 2039Sbill char partab[]; 2139Sbill 22146Sbill /* 23146Sbill * When running dz's using only SAE (silo alarm) on input 24146Sbill * it is necessary to call dzrint() at clock interrupt time. 25146Sbill * This is unsafe unless spl5()s in tty code are changed to 26146Sbill * spl6()s to block clock interrupts. Note that the dh driver 27146Sbill * currently in use works the same way as the dz, even though 28146Sbill * we could try to more intelligently manage its silo. 29146Sbill * Thus don't take this out if you have no dz's unless you 30146Sbill * change clock.c and dhtimer(). 31146Sbill */ 32146Sbill #define spl5 spl6 3339Sbill 3439Sbill /* 3539Sbill * Input mapping table-- if an entry is non-zero, when the 3639Sbill * corresponding character is typed preceded by "\" the escape 3739Sbill * sequence is replaced by the table value. Mostly used for 3839Sbill * upper-case only terminals. 3939Sbill */ 4039Sbill 4139Sbill char maptab[] ={ 4239Sbill 000,000,000,000,000,000,000,000, 4339Sbill 000,000,000,000,000,000,000,000, 4439Sbill 000,000,000,000,000,000,000,000, 4539Sbill 000,000,000,000,000,000,000,000, 4639Sbill 000,'|',000,000,000,000,000,'`', 4739Sbill '{','}',000,000,000,000,000,000, 4839Sbill 000,000,000,000,000,000,000,000, 4939Sbill 000,000,000,000,000,000,000,000, 5039Sbill 000,000,000,000,000,000,000,000, 5139Sbill 000,000,000,000,000,000,000,000, 5239Sbill 000,000,000,000,000,000,000,000, 5339Sbill 000,000,000,000,000,000,'~',000, 5439Sbill 000,'A','B','C','D','E','F','G', 5539Sbill 'H','I','J','K','L','M','N','O', 5639Sbill 'P','Q','R','S','T','U','V','W', 5739Sbill 'X','Y','Z',000,000,000,000,000, 5839Sbill }; 5939Sbill 6039Sbill #define OBUFSIZ 100 6139Sbill 6239Sbill /* 6339Sbill * set default control characters. 6439Sbill */ 6539Sbill ttychars(tp) 6639Sbill register struct tty *tp; 6739Sbill { 68174Sbill 6939Sbill tun.t_intrc = CINTR; 7039Sbill tun.t_quitc = CQUIT; 7139Sbill tun.t_startc = CSTART; 7239Sbill tun.t_stopc = CSTOP; 7339Sbill tun.t_eofc = CEOT; 7439Sbill tun.t_brkc = CBRK; 7539Sbill tp->t_erase = CERASE; 7639Sbill tp->t_kill = CKILL; 77174Sbill /* begin local */ 78208Sbill tlun.t_suspc = CTRL(z); 79208Sbill tlun.t_dsuspc = CTRL(y); 80174Sbill tlun.t_rprntc = CTRL(r); 81174Sbill tlun.t_flushc = CTRL(o); 82174Sbill tlun.t_werasc = CTRL(w); 83174Sbill tlun.t_lnextc = CTRL(v); 84174Sbill tlun.t_lintr = CTRL(c); 85174Sbill tlun.t_lerase = CTRL(h); 86174Sbill tlun.t_lkill = CTRL(u); 87174Sbill tp->t_local = 0; 88174Sbill tp->t_lstate = 0; 89174Sbill /* end local */ 9039Sbill } 9139Sbill 9239Sbill /* 93903Sbill * Wait for output to drain, then flush input waiting. 9439Sbill */ 95903Sbill wflushtty(tp) 9639Sbill register struct tty *tp; 9739Sbill { 9839Sbill 99903Sbill (void) spl5(); 100903Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 101903Sbill (*tp->t_oproc)(tp); 102903Sbill tp->t_state |= ASLEEP; 103903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 104903Sbill } 105903Sbill flushtty(tp, FREAD|FWRITE); 106903Sbill (void) spl0(); 10739Sbill } 10839Sbill 10939Sbill /* 110903Sbill * flush all TTY queues 11139Sbill */ 112903Sbill flushtty(tp, rw) 113903Sbill register struct tty *tp; 11439Sbill { 115903Sbill register s; 116903Sbill 117903Sbill if (tp->t_line == NETLDISC) 118903Sbill return; 119903Sbill s = spl6(); 120903Sbill if (rw & FREAD) { 121903Sbill while (getc(&tp->t_canq) >= 0) 122903Sbill ; 123903Sbill wakeup((caddr_t)&tp->t_rawq); 124903Sbill } 125903Sbill if (rw & FWRITE) { 126903Sbill wakeup((caddr_t)&tp->t_outq); 127903Sbill tp->t_state &= ~TTSTOP; 128903Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 129903Sbill while (getc(&tp->t_outq) >= 0) 130903Sbill ; 131903Sbill } 132903Sbill if (rw & FREAD) { 133903Sbill while (getc(&tp->t_rawq) >= 0) 134903Sbill ; 135903Sbill tp->t_delct = 0; 136903Sbill tp->t_rocount = 0; /* local */ 137903Sbill tp->t_rocol = 0; 138903Sbill tp->t_lstate = 0; 139903Sbill } 140903Sbill splx(s); 14139Sbill } 14239Sbill 143903Sbill /* 144903Sbill * Send stop character on input overflow. 145903Sbill */ 146903Sbill ttyblock(tp) 147903Sbill register struct tty *tp; 14839Sbill { 149903Sbill register x; 150903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 151903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 152903Sbill flushtty(tp, FREAD|FWRITE); 153903Sbill tp->t_state &= ~TBLOCK; 154903Sbill } 155903Sbill if (x >= TTYHOG/2) { 156903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 157903Sbill tp->t_state |= TBLOCK; 158903Sbill tp->t_char++; 159903Sbill ttstart(tp); 160903Sbill } 161903Sbill } 16239Sbill } 16339Sbill 16439Sbill /* 165903Sbill * Restart typewriter output following a delay 166903Sbill * timeout. 167903Sbill * The name of the routine is passed to the timeout 168903Sbill * subroutine and it is called during a clock interrupt. 169121Sbill */ 170903Sbill ttrstrt(tp) 171121Sbill register struct tty *tp; 172121Sbill { 173121Sbill 174903Sbill tp->t_state &= ~TIMEOUT; 175903Sbill ttstart(tp); 176121Sbill } 177121Sbill 178121Sbill /* 179903Sbill * Start output on the typewriter. It is used from the top half 180903Sbill * after some characters have been put on the output queue, 181903Sbill * from the interrupt routine to transmit the next 182903Sbill * character, and after a timeout has finished. 18339Sbill */ 184903Sbill ttstart(tp) 185903Sbill register struct tty *tp; 18639Sbill { 187903Sbill register s; 18839Sbill 189903Sbill s = spl5(); 190903Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 191903Sbill (*tp->t_oproc)(tp); 192903Sbill splx(s); 19339Sbill } 19439Sbill 19539Sbill /* 196903Sbill * Common code for tty ioctls. 19739Sbill */ 198903Sbill ttioctl(com, tp, addr, dev, flag) 19939Sbill register struct tty *tp; 20039Sbill caddr_t addr; 20139Sbill { 20239Sbill unsigned t; 203174Sbill struct sgttyb iocb; 204191Sbill struct clist tq; 20539Sbill extern int nldisp; 206887Sbill register c; 207728Sbill int temp; 20839Sbill 209903Sbill /* 210*915Sbill * This is especially so that isatty() will 211*915Sbill * fail when carrier is gone. 212*915Sbill */ 213*915Sbill if ((tp->t_state&CARR_ON) == 0) { 214*915Sbill u.u_error = EBADF; 215*915Sbill return (1); 216*915Sbill } 217*915Sbill 218*915Sbill /* 219903Sbill * If the ioctl involves modification, 220903Sbill * insist on being able to write the device, 221903Sbill * and hang if in the background. 222903Sbill */ 22339Sbill switch(com) { 22439Sbill 225*915Sbill case TIOCSETD: 226*915Sbill case TIOCSETP: 227*915Sbill case TIOCSETN: 228903Sbill case TIOCFLUSH: 229903Sbill case TIOCSETC: 230903Sbill case TIOCSLTC: 231903Sbill case TIOCSPGRP: 232903Sbill case TIOCLBIS: 233903Sbill case TIOCLBIC: 234903Sbill case TIOCLSET: 235903Sbill case TIOCSTI: 236*915Sbill /* this is reasonable, but impractical... 237903Sbill if ((flag & FWRITE) == 0) { 238903Sbill u.u_error = EBADF; 239903Sbill return (1); 240903Sbill } 241*915Sbill */ 242903Sbill while (tp->t_line == NTTYDISC && 243903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 244903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 245903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 246903Sbill u.u_signal[SIGTTOU] != SIG_HOLD && 247903Sbill (u.u_procp->p_flag&SDETACH)==0) { 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 /* 291903Sbill * Prevent more opens on channel 29239Sbill */ 29339Sbill case TIOCEXCL: 29439Sbill tp->t_state |= XCLUDE; 29539Sbill break; 29639Sbill 29739Sbill case TIOCNXCL: 29839Sbill tp->t_state &= ~XCLUDE; 29939Sbill break; 30039Sbill 30139Sbill /* 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(); 311174Sbill if (tp->t_line == 0) { 312174Sbill if (com == TIOCSETP) 313174Sbill wflushtty(tp); 314174Sbill while (canon(tp)>=0) 315174Sbill ; 316174Sbill } else if (tp->t_line == NTTYDISC) { 317174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 318174Sbill com == TIOCSETP) 319174Sbill wflushtty(tp); 320174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 321174Sbill if (iocb.sg_flags & CBREAK) { 322174Sbill catq(&tp->t_rawq, &tp->t_canq); 323174Sbill tq = tp->t_rawq; 324174Sbill tp->t_rawq = tp->t_canq; 325174Sbill tp->t_canq = tq; 326174Sbill } else { 327174Sbill tp->t_local |= LPENDIN; 328174Sbill if (tp->t_canq.c_cc) 329174Sbill panic("ioccom canq"); 330174Sbill if (tp->t_chan) 331174Sbill (void) sdata(tp->t_chan); 332174Sbill else 333174Sbill wakeup((caddr_t)&tp->t_rawq); 334174Sbill } 335174Sbill } 336174Sbill } 33739Sbill if ((tp->t_state&SPEEDS)==0) { 338174Sbill tp->t_ispeed = iocb.sg_ispeed; 339174Sbill tp->t_ospeed = iocb.sg_ospeed; 34039Sbill } 341174Sbill tp->t_erase = iocb.sg_erase; 342174Sbill tp->t_kill = iocb.sg_kill; 343174Sbill tp->t_flags = iocb.sg_flags; 344121Sbill (void) spl0(); 34539Sbill break; 34639Sbill 34739Sbill /* 348903Sbill * Send current parameters to user 34939Sbill */ 35039Sbill case TIOCGETP: 351174Sbill iocb.sg_ispeed = tp->t_ispeed; 352174Sbill iocb.sg_ospeed = tp->t_ospeed; 353174Sbill iocb.sg_erase = tp->t_erase; 354174Sbill iocb.sg_kill = tp->t_kill; 355174Sbill iocb.sg_flags = tp->t_flags; 35639Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 35739Sbill u.u_error = EFAULT; 35839Sbill break; 35939Sbill 36039Sbill /* 36139Sbill * Hang up line on last close 36239Sbill */ 36339Sbill case TIOCHPCL: 36439Sbill tp->t_state |= HUPCLS; 36539Sbill break; 36639Sbill 36739Sbill case TIOCFLUSH: 368872Sbill flushtty(tp, FREAD|FWRITE); 36939Sbill break; 37039Sbill 37139Sbill /* 372903Sbill * Ioctl entries to line discipline 37339Sbill */ 37439Sbill case DIOCSETP: 37539Sbill case DIOCGETP: 376121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 377121Sbill u.u_error = ENOTTY; 37839Sbill break; 37939Sbill 38039Sbill /* 381903Sbill * Set and fetch special characters 38239Sbill */ 38339Sbill case TIOCSETC: 384174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 38539Sbill u.u_error = EFAULT; 38639Sbill break; 38739Sbill 38839Sbill case TIOCGETC: 389174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 39039Sbill u.u_error = EFAULT; 39139Sbill break; 39239Sbill 393174Sbill /* local ioctls */ 394903Sbill /* 395903Sbill * Set/get local special characters. 396903Sbill */ 397174Sbill case TIOCSLTC: 398174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 399174Sbill u.u_error = EFAULT; 400174Sbill break; 401174Sbill 402174Sbill case TIOCGLTC: 403174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 404174Sbill u.u_error = EFAULT; 405174Sbill break; 406174Sbill 407903Sbill /* 408903Sbill * Return number of characters immediately available. 409903Sbill */ 410174Sbill case FIONREAD: { 411340Sbill off_t nread; 412174Sbill 413340Sbill switch (tp->t_line) { 414340Sbill 415340Sbill case NETLDISC: 416340Sbill nread = tp->t_rec ? tp->t_inbuf : 0; 417340Sbill break; 418340Sbill 419894Sbill case 0: 420894Sbill (void) spl5(); 421894Sbill while (canon(tp)>=0) 422894Sbill ; 423894Sbill (void) spl0(); 424894Sbill /* fall into ... */ 425894Sbill 426340Sbill case NTTYDISC: 427340Sbill nread = tp->t_canq.c_cc; 428340Sbill if (tp->t_flags & (RAW|CBREAK)) 429340Sbill nread += tp->t_rawq.c_cc; 430340Sbill break; 431340Sbill 432340Sbill } 433174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 434174Sbill u.u_error = EFAULT; 435174Sbill break; 436174Sbill } 437174Sbill 438174Sbill /* 439174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 440174Sbill */ 441174Sbill case TIOCSPGRP: 442728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 443728Sbill u.u_error = EFAULT; 444174Sbill break; 445174Sbill 446174Sbill case TIOCGPGRP: 447174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 448174Sbill u.u_error = EFAULT; 449174Sbill break; 450174Sbill 451174Sbill /* 452174Sbill * Modify local mode word. 453174Sbill */ 454174Sbill case TIOCLBIS: 455728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 456728Sbill u.u_error = EFAULT; 457728Sbill else 458728Sbill tp->t_local |= temp; 459174Sbill break; 460174Sbill 461174Sbill case TIOCLBIC: 462728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 463728Sbill u.u_error = EFAULT; 464728Sbill else 465728Sbill tp->t_local &= ~temp; 466174Sbill break; 467174Sbill 468174Sbill case TIOCLSET: 469728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 470728Sbill u.u_error = EFAULT; 471728Sbill else 472728Sbill tp->t_local = temp; 473174Sbill break; 474174Sbill 475174Sbill case TIOCLGET: 476174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 477174Sbill u.u_error = EFAULT; 478174Sbill break; 479174Sbill 480903Sbill /* 481903Sbill * Return number of characters in 482903Sbill * the output. 483903Sbill */ 484213Sbill case TIOCOUTQ: 485213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 486213Sbill u.u_error = EFAULT; 487213Sbill break; 488213Sbill 489903Sbill /* 490903Sbill * Simulate typing of a character at the terminal. 491903Sbill */ 492887Sbill case TIOCSTI: 493887Sbill c = fubyte(addr); 494887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 495887Sbill u.u_error = EFAULT; 496887Sbill else 497887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 498887Sbill break; 499174Sbill /* end of locals */ 500887Sbill 50139Sbill default: 50239Sbill return(0); 50339Sbill } 50439Sbill return(1); 50539Sbill } 506