1*1780Sbill /* tty.c 4.2 11/09/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 60925Sbill short tthiwat[16] = 61925Sbill { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 62925Sbill short ttlowat[16] = 63925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 64925Sbill 6539Sbill #define OBUFSIZ 100 6639Sbill 6739Sbill /* 6839Sbill * set default control characters. 6939Sbill */ 7039Sbill ttychars(tp) 7139Sbill register struct tty *tp; 7239Sbill { 73174Sbill 7439Sbill tun.t_intrc = CINTR; 7539Sbill tun.t_quitc = CQUIT; 7639Sbill tun.t_startc = CSTART; 7739Sbill tun.t_stopc = CSTOP; 7839Sbill tun.t_eofc = CEOT; 7939Sbill tun.t_brkc = CBRK; 8039Sbill tp->t_erase = CERASE; 8139Sbill tp->t_kill = CKILL; 82174Sbill /* begin local */ 83208Sbill tlun.t_suspc = CTRL(z); 84208Sbill tlun.t_dsuspc = CTRL(y); 85174Sbill tlun.t_rprntc = CTRL(r); 86174Sbill tlun.t_flushc = CTRL(o); 87174Sbill tlun.t_werasc = CTRL(w); 88174Sbill tlun.t_lnextc = CTRL(v); 89174Sbill tp->t_local = 0; 90174Sbill tp->t_lstate = 0; 91174Sbill /* end local */ 9239Sbill } 9339Sbill 9439Sbill /* 95903Sbill * Wait for output to drain, then flush input waiting. 9639Sbill */ 97903Sbill wflushtty(tp) 9839Sbill register struct tty *tp; 9939Sbill { 10039Sbill 101903Sbill (void) spl5(); 102903Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 103903Sbill (*tp->t_oproc)(tp); 104903Sbill tp->t_state |= ASLEEP; 105903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 106903Sbill } 107903Sbill flushtty(tp, FREAD|FWRITE); 108903Sbill (void) spl0(); 10939Sbill } 11039Sbill 11139Sbill /* 112903Sbill * flush all TTY queues 11339Sbill */ 114903Sbill flushtty(tp, rw) 115903Sbill register struct tty *tp; 11639Sbill { 117903Sbill register s; 118903Sbill 119903Sbill if (tp->t_line == NETLDISC) 120903Sbill return; 121903Sbill s = spl6(); 122903Sbill if (rw & FREAD) { 123903Sbill while (getc(&tp->t_canq) >= 0) 124903Sbill ; 125903Sbill wakeup((caddr_t)&tp->t_rawq); 126903Sbill } 127903Sbill if (rw & FWRITE) { 128903Sbill wakeup((caddr_t)&tp->t_outq); 129903Sbill tp->t_state &= ~TTSTOP; 130903Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 131903Sbill while (getc(&tp->t_outq) >= 0) 132903Sbill ; 133903Sbill } 134903Sbill if (rw & FREAD) { 135903Sbill while (getc(&tp->t_rawq) >= 0) 136903Sbill ; 137903Sbill tp->t_delct = 0; 138903Sbill tp->t_rocount = 0; /* local */ 139903Sbill tp->t_rocol = 0; 140903Sbill tp->t_lstate = 0; 141903Sbill } 142903Sbill splx(s); 14339Sbill } 14439Sbill 145903Sbill /* 146903Sbill * Send stop character on input overflow. 147903Sbill */ 148903Sbill ttyblock(tp) 149903Sbill register struct tty *tp; 15039Sbill { 151903Sbill register x; 152903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 153903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 154903Sbill flushtty(tp, FREAD|FWRITE); 155903Sbill tp->t_state &= ~TBLOCK; 156903Sbill } 157903Sbill if (x >= TTYHOG/2) { 158903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 159903Sbill tp->t_state |= TBLOCK; 160903Sbill tp->t_char++; 161903Sbill ttstart(tp); 162903Sbill } 163903Sbill } 16439Sbill } 16539Sbill 16639Sbill /* 167903Sbill * Restart typewriter output following a delay 168903Sbill * timeout. 169903Sbill * The name of the routine is passed to the timeout 170903Sbill * subroutine and it is called during a clock interrupt. 171121Sbill */ 172903Sbill ttrstrt(tp) 173121Sbill register struct tty *tp; 174121Sbill { 175121Sbill 176903Sbill tp->t_state &= ~TIMEOUT; 177903Sbill ttstart(tp); 178121Sbill } 179121Sbill 180121Sbill /* 181903Sbill * Start output on the typewriter. It is used from the top half 182903Sbill * after some characters have been put on the output queue, 183903Sbill * from the interrupt routine to transmit the next 184903Sbill * character, and after a timeout has finished. 18539Sbill */ 186903Sbill ttstart(tp) 187903Sbill register struct tty *tp; 18839Sbill { 189903Sbill register s; 19039Sbill 191903Sbill s = spl5(); 192903Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 193903Sbill (*tp->t_oproc)(tp); 194903Sbill splx(s); 19539Sbill } 19639Sbill 19739Sbill /* 198903Sbill * Common code for tty ioctls. 19939Sbill */ 200*1780Sbill /*ARGSUSED*/ 201903Sbill ttioctl(com, tp, addr, dev, flag) 20239Sbill register struct tty *tp; 20339Sbill caddr_t addr; 20439Sbill { 20539Sbill unsigned t; 206174Sbill struct sgttyb iocb; 207191Sbill struct clist tq; 20839Sbill extern int nldisp; 209887Sbill register c; 210728Sbill int temp; 21139Sbill 212903Sbill /* 213915Sbill * This is especially so that isatty() will 214915Sbill * fail when carrier is gone. 215915Sbill */ 216915Sbill if ((tp->t_state&CARR_ON) == 0) { 217915Sbill u.u_error = EBADF; 218915Sbill return (1); 219915Sbill } 220915Sbill 221915Sbill /* 222903Sbill * If the ioctl involves modification, 223903Sbill * insist on being able to write the device, 224903Sbill * and hang if in the background. 225903Sbill */ 22639Sbill switch(com) { 22739Sbill 228915Sbill case TIOCSETD: 229915Sbill case TIOCSETP: 230915Sbill case TIOCSETN: 231903Sbill case TIOCFLUSH: 232903Sbill case TIOCSETC: 233903Sbill case TIOCSLTC: 234903Sbill case TIOCSPGRP: 235903Sbill case TIOCLBIS: 236903Sbill case TIOCLBIC: 237903Sbill case TIOCLSET: 238903Sbill case TIOCSTI: 239915Sbill /* this is reasonable, but impractical... 240903Sbill if ((flag & FWRITE) == 0) { 241903Sbill u.u_error = EBADF; 242903Sbill return (1); 243903Sbill } 244915Sbill */ 245903Sbill while (tp->t_line == NTTYDISC && 246903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 247903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 248903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 249903Sbill u.u_signal[SIGTTOU] != SIG_HOLD && 250903Sbill (u.u_procp->p_flag&SDETACH)==0) { 251903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 252903Sbill sleep((caddr_t)&lbolt, TTOPRI); 253903Sbill } 254903Sbill break; 255903Sbill } 256903Sbill 25739Sbill /* 258903Sbill * Process the ioctl. 25939Sbill */ 260903Sbill switch(com) { 261903Sbill 262903Sbill /* 263903Sbill * Get discipline number 264903Sbill */ 26539Sbill case TIOCGETD: 26639Sbill t = tp->t_line; 26739Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 26839Sbill u.u_error = EFAULT; 26939Sbill break; 27039Sbill 27139Sbill /* 272903Sbill * Set line discipline 27339Sbill */ 27439Sbill case TIOCSETD: 27539Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 27639Sbill u.u_error = EFAULT; 27739Sbill break; 27839Sbill } 27939Sbill if (t >= nldisp) { 28039Sbill u.u_error = ENXIO; 28139Sbill break; 28239Sbill } 283174Sbill (void) spl5(); 28439Sbill if (tp->t_line) 28539Sbill (*linesw[tp->t_line].l_close)(tp); 28639Sbill if (t) 28739Sbill (*linesw[t].l_open)(dev, tp, addr); 28839Sbill if (u.u_error==0) 28939Sbill tp->t_line = t; 290174Sbill (void) spl0(); 29139Sbill break; 29239Sbill 29339Sbill /* 294903Sbill * Prevent more opens on channel 29539Sbill */ 29639Sbill case TIOCEXCL: 29739Sbill tp->t_state |= XCLUDE; 29839Sbill break; 29939Sbill 30039Sbill case TIOCNXCL: 30139Sbill tp->t_state &= ~XCLUDE; 30239Sbill break; 30339Sbill 30439Sbill /* 30539Sbill * Set new parameters 30639Sbill */ 30739Sbill case TIOCSETP: 308191Sbill case TIOCSETN: 30939Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 31039Sbill u.u_error = EFAULT; 31139Sbill return(1); 31239Sbill } 313121Sbill (void) spl5(); 314174Sbill if (tp->t_line == 0) { 315174Sbill if (com == TIOCSETP) 316174Sbill wflushtty(tp); 317174Sbill while (canon(tp)>=0) 318174Sbill ; 319933Sbill #ifdef notdef 320933Sbill wakeup((caddr_t)&tp->t_rawq); 321933Sbill #endif 322174Sbill } else if (tp->t_line == NTTYDISC) { 323174Sbill if (tp->t_flags&RAW || iocb.sg_flags&RAW || 324174Sbill com == TIOCSETP) 325174Sbill wflushtty(tp); 326174Sbill else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) { 327174Sbill if (iocb.sg_flags & CBREAK) { 328174Sbill catq(&tp->t_rawq, &tp->t_canq); 329174Sbill tq = tp->t_rawq; 330174Sbill tp->t_rawq = tp->t_canq; 331174Sbill tp->t_canq = tq; 332174Sbill } else { 333174Sbill tp->t_local |= LPENDIN; 334174Sbill if (tp->t_canq.c_cc) 335174Sbill panic("ioccom canq"); 336933Sbill #ifdef notdef 337174Sbill if (tp->t_chan) 338174Sbill (void) sdata(tp->t_chan); 339174Sbill else 340933Sbill #endif 341174Sbill wakeup((caddr_t)&tp->t_rawq); 342174Sbill } 343174Sbill } 344174Sbill } 34539Sbill if ((tp->t_state&SPEEDS)==0) { 346174Sbill tp->t_ispeed = iocb.sg_ispeed; 347174Sbill tp->t_ospeed = iocb.sg_ospeed; 34839Sbill } 349174Sbill tp->t_erase = iocb.sg_erase; 350174Sbill tp->t_kill = iocb.sg_kill; 351174Sbill tp->t_flags = iocb.sg_flags; 352121Sbill (void) spl0(); 35339Sbill break; 35439Sbill 35539Sbill /* 356903Sbill * Send current parameters to user 35739Sbill */ 35839Sbill case TIOCGETP: 359174Sbill iocb.sg_ispeed = tp->t_ispeed; 360174Sbill iocb.sg_ospeed = tp->t_ospeed; 361174Sbill iocb.sg_erase = tp->t_erase; 362174Sbill iocb.sg_kill = tp->t_kill; 363174Sbill iocb.sg_flags = tp->t_flags; 36439Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 36539Sbill u.u_error = EFAULT; 36639Sbill break; 36739Sbill 36839Sbill /* 36939Sbill * Hang up line on last close 37039Sbill */ 37139Sbill case TIOCHPCL: 37239Sbill tp->t_state |= HUPCLS; 37339Sbill break; 37439Sbill 37539Sbill case TIOCFLUSH: 376872Sbill flushtty(tp, FREAD|FWRITE); 37739Sbill break; 37839Sbill 37939Sbill /* 380903Sbill * Ioctl entries to line discipline 38139Sbill */ 38239Sbill case DIOCSETP: 38339Sbill case DIOCGETP: 384121Sbill if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr)) 385121Sbill u.u_error = ENOTTY; 38639Sbill break; 38739Sbill 38839Sbill /* 389903Sbill * Set and fetch special characters 39039Sbill */ 39139Sbill case TIOCSETC: 392174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 39339Sbill u.u_error = EFAULT; 39439Sbill break; 39539Sbill 39639Sbill case TIOCGETC: 397174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 39839Sbill u.u_error = EFAULT; 39939Sbill break; 40039Sbill 401174Sbill /* local ioctls */ 402903Sbill /* 403903Sbill * Set/get local special characters. 404903Sbill */ 405174Sbill case TIOCSLTC: 406174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 407174Sbill u.u_error = EFAULT; 408174Sbill break; 409174Sbill 410174Sbill case TIOCGLTC: 411174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 412174Sbill u.u_error = EFAULT; 413174Sbill break; 414174Sbill 415903Sbill /* 416903Sbill * Return number of characters immediately available. 417903Sbill */ 418174Sbill case FIONREAD: { 419340Sbill off_t nread; 420174Sbill 421340Sbill switch (tp->t_line) { 422340Sbill 423340Sbill case NETLDISC: 424340Sbill nread = tp->t_rec ? tp->t_inbuf : 0; 425340Sbill break; 426340Sbill 427894Sbill case 0: 428894Sbill (void) spl5(); 429894Sbill while (canon(tp)>=0) 430894Sbill ; 431894Sbill (void) spl0(); 432894Sbill /* fall into ... */ 433894Sbill 434340Sbill case NTTYDISC: 435340Sbill nread = tp->t_canq.c_cc; 436340Sbill if (tp->t_flags & (RAW|CBREAK)) 437340Sbill nread += tp->t_rawq.c_cc; 438340Sbill break; 439340Sbill 440340Sbill } 441174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 442174Sbill u.u_error = EFAULT; 443174Sbill break; 444174Sbill } 445174Sbill 446174Sbill /* 447174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 448174Sbill */ 449174Sbill case TIOCSPGRP: 450728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 451728Sbill u.u_error = EFAULT; 452174Sbill break; 453174Sbill 454174Sbill case TIOCGPGRP: 455174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 456174Sbill u.u_error = EFAULT; 457174Sbill break; 458174Sbill 459174Sbill /* 460174Sbill * Modify local mode word. 461174Sbill */ 462174Sbill case TIOCLBIS: 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 TIOCLBIC: 470728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 471728Sbill u.u_error = EFAULT; 472728Sbill else 473728Sbill tp->t_local &= ~temp; 474174Sbill break; 475174Sbill 476174Sbill case TIOCLSET: 477728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 478728Sbill u.u_error = EFAULT; 479728Sbill else 480728Sbill tp->t_local = temp; 481174Sbill break; 482174Sbill 483174Sbill case TIOCLGET: 484174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 485174Sbill u.u_error = EFAULT; 486174Sbill break; 487174Sbill 488903Sbill /* 489903Sbill * Return number of characters in 490903Sbill * the output. 491903Sbill */ 492213Sbill case TIOCOUTQ: 493213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 494213Sbill u.u_error = EFAULT; 495213Sbill break; 496213Sbill 497903Sbill /* 498903Sbill * Simulate typing of a character at the terminal. 499903Sbill */ 500887Sbill case TIOCSTI: 501887Sbill c = fubyte(addr); 502887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 503887Sbill u.u_error = EFAULT; 504887Sbill else 505887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 506887Sbill break; 507174Sbill /* end of locals */ 508887Sbill 50939Sbill default: 51039Sbill return(0); 51139Sbill } 51239Sbill return(1); 51339Sbill } 514