1*3941Sbugs /* tty.c 4.7 81/07/05 */ 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 /* 2339Sbill * Input mapping table-- if an entry is non-zero, when the 2439Sbill * corresponding character is typed preceded by "\" the escape 2539Sbill * sequence is replaced by the table value. Mostly used for 2639Sbill * upper-case only terminals. 2739Sbill */ 2839Sbill 2939Sbill char maptab[] ={ 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,000,000, 3439Sbill 000,'|',000,000,000,000,000,'`', 3539Sbill '{','}',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,000, 4139Sbill 000,000,000,000,000,000,'~',000, 4239Sbill 000,'A','B','C','D','E','F','G', 4339Sbill 'H','I','J','K','L','M','N','O', 4439Sbill 'P','Q','R','S','T','U','V','W', 4539Sbill 'X','Y','Z',000,000,000,000,000, 4639Sbill }; 4739Sbill 48925Sbill short tthiwat[16] = 49925Sbill { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 }; 50925Sbill short ttlowat[16] = 51925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 52925Sbill 5339Sbill #define OBUFSIZ 100 5439Sbill 5539Sbill /* 5639Sbill * set default control characters. 5739Sbill */ 5839Sbill ttychars(tp) 5939Sbill register struct tty *tp; 6039Sbill { 61174Sbill 6239Sbill tun.t_intrc = CINTR; 6339Sbill tun.t_quitc = CQUIT; 6439Sbill tun.t_startc = CSTART; 6539Sbill tun.t_stopc = CSTOP; 6639Sbill tun.t_eofc = CEOT; 6739Sbill tun.t_brkc = CBRK; 6839Sbill tp->t_erase = CERASE; 6939Sbill tp->t_kill = CKILL; 70174Sbill /* begin local */ 71208Sbill tlun.t_suspc = CTRL(z); 72208Sbill tlun.t_dsuspc = CTRL(y); 73174Sbill tlun.t_rprntc = CTRL(r); 74174Sbill tlun.t_flushc = CTRL(o); 75174Sbill tlun.t_werasc = CTRL(w); 76174Sbill tlun.t_lnextc = CTRL(v); 77174Sbill tp->t_local = 0; 78174Sbill tp->t_lstate = 0; 79174Sbill /* end local */ 8039Sbill } 8139Sbill 8239Sbill /* 83903Sbill * Wait for output to drain, then flush input waiting. 8439Sbill */ 85903Sbill wflushtty(tp) 8639Sbill register struct tty *tp; 8739Sbill { 8839Sbill 89903Sbill (void) spl5(); 90903Sbill while (tp->t_outq.c_cc && tp->t_state&CARR_ON) { 91903Sbill (*tp->t_oproc)(tp); 92903Sbill tp->t_state |= ASLEEP; 93903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 94903Sbill } 95903Sbill flushtty(tp, FREAD|FWRITE); 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 if (tp->t_line == NETLDISC) 108903Sbill return; 109903Sbill s = spl6(); 110903Sbill if (rw & FREAD) { 111903Sbill while (getc(&tp->t_canq) >= 0) 112903Sbill ; 113903Sbill wakeup((caddr_t)&tp->t_rawq); 114903Sbill } 115903Sbill if (rw & FWRITE) { 116903Sbill wakeup((caddr_t)&tp->t_outq); 117903Sbill tp->t_state &= ~TTSTOP; 118903Sbill (*cdevsw[major(tp->t_dev)].d_stop)(tp); 119903Sbill while (getc(&tp->t_outq) >= 0) 120903Sbill ; 121903Sbill } 122903Sbill if (rw & FREAD) { 123903Sbill while (getc(&tp->t_rawq) >= 0) 124903Sbill ; 125903Sbill tp->t_delct = 0; 126903Sbill tp->t_rocount = 0; /* local */ 127903Sbill tp->t_rocol = 0; 128903Sbill tp->t_lstate = 0; 129903Sbill } 130903Sbill splx(s); 13139Sbill } 13239Sbill 133903Sbill /* 134903Sbill * Send stop character on input overflow. 135903Sbill */ 136903Sbill ttyblock(tp) 137903Sbill register struct tty *tp; 13839Sbill { 139903Sbill register x; 140903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 141903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 142903Sbill flushtty(tp, FREAD|FWRITE); 143903Sbill tp->t_state &= ~TBLOCK; 144903Sbill } 145903Sbill if (x >= TTYHOG/2) { 146903Sbill if (putc(tun.t_stopc, &tp->t_outq)==0) { 147903Sbill tp->t_state |= TBLOCK; 148903Sbill tp->t_char++; 149903Sbill ttstart(tp); 150903Sbill } 151903Sbill } 15239Sbill } 15339Sbill 15439Sbill /* 155903Sbill * Restart typewriter output following a delay 156903Sbill * timeout. 157903Sbill * The name of the routine is passed to the timeout 158903Sbill * subroutine and it is called during a clock interrupt. 159121Sbill */ 160903Sbill ttrstrt(tp) 161121Sbill register struct tty *tp; 162121Sbill { 163121Sbill 1643351Swnj if (tp == 0) { 1653351Swnj printf("ttrstrt: arg was 0!\n"); 1663351Swnj return; 1673351Swnj } 168903Sbill tp->t_state &= ~TIMEOUT; 169903Sbill ttstart(tp); 170121Sbill } 171121Sbill 172121Sbill /* 173903Sbill * Start output on the typewriter. It is used from the top half 174903Sbill * after some characters have been put on the output queue, 175903Sbill * from the interrupt routine to transmit the next 176903Sbill * character, and after a timeout has finished. 17739Sbill */ 178903Sbill ttstart(tp) 179903Sbill register struct tty *tp; 18039Sbill { 181903Sbill register s; 18239Sbill 183903Sbill s = spl5(); 184903Sbill if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0) 185903Sbill (*tp->t_oproc)(tp); 186903Sbill splx(s); 18739Sbill } 18839Sbill 18939Sbill /* 190903Sbill * Common code for tty ioctls. 19139Sbill */ 1921780Sbill /*ARGSUSED*/ 1931904Swnj ttioctl(tp, com, addr, flag) 19439Sbill register struct tty *tp; 19539Sbill caddr_t addr; 19639Sbill { 1971904Swnj int dev; 19839Sbill unsigned t; 199174Sbill struct sgttyb iocb; 200191Sbill struct clist tq; 20139Sbill extern int nldisp; 202887Sbill register c; 203728Sbill int temp; 20439Sbill 205903Sbill /* 206915Sbill * This is especially so that isatty() will 207915Sbill * fail when carrier is gone. 208915Sbill */ 209915Sbill if ((tp->t_state&CARR_ON) == 0) { 210915Sbill u.u_error = EBADF; 211915Sbill return (1); 212915Sbill } 213915Sbill 2141904Swnj dev = tp->t_dev; 215915Sbill /* 216903Sbill * If the ioctl involves modification, 217903Sbill * insist on being able to write the device, 218903Sbill * and hang if in the background. 219903Sbill */ 22039Sbill switch(com) { 22139Sbill 222915Sbill case TIOCSETD: 223915Sbill case TIOCSETP: 224915Sbill case TIOCSETN: 225903Sbill case TIOCFLUSH: 226903Sbill case TIOCSETC: 227903Sbill case TIOCSLTC: 228903Sbill case TIOCSPGRP: 229903Sbill case TIOCLBIS: 230903Sbill case TIOCLBIC: 231903Sbill case TIOCLSET: 232903Sbill case TIOCSTI: 233915Sbill /* this is reasonable, but impractical... 234903Sbill if ((flag & FWRITE) == 0) { 235903Sbill u.u_error = EBADF; 236903Sbill return (1); 237903Sbill } 238915Sbill */ 239903Sbill while (tp->t_line == NTTYDISC && 240903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 241903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 242903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 243903Sbill u.u_signal[SIGTTOU] != SIG_HOLD && 244903Sbill (u.u_procp->p_flag&SDETACH)==0) { 245903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 246903Sbill sleep((caddr_t)&lbolt, TTOPRI); 247903Sbill } 248903Sbill break; 249903Sbill } 250903Sbill 25139Sbill /* 252903Sbill * Process the ioctl. 25339Sbill */ 254903Sbill switch(com) { 255903Sbill 256903Sbill /* 257903Sbill * Get discipline number 258903Sbill */ 25939Sbill case TIOCGETD: 26039Sbill t = tp->t_line; 26139Sbill if (copyout((caddr_t)&t, addr, sizeof(t))) 26239Sbill u.u_error = EFAULT; 26339Sbill break; 26439Sbill 26539Sbill /* 266903Sbill * Set line discipline 26739Sbill */ 26839Sbill case TIOCSETD: 26939Sbill if (copyin(addr, (caddr_t)&t, sizeof(t))) { 27039Sbill u.u_error = EFAULT; 27139Sbill break; 27239Sbill } 27339Sbill if (t >= nldisp) { 27439Sbill u.u_error = ENXIO; 27539Sbill break; 27639Sbill } 277174Sbill (void) spl5(); 27839Sbill if (tp->t_line) 27939Sbill (*linesw[tp->t_line].l_close)(tp); 28039Sbill if (t) 28139Sbill (*linesw[t].l_open)(dev, tp, addr); 28239Sbill if (u.u_error==0) 28339Sbill tp->t_line = t; 284174Sbill (void) spl0(); 28539Sbill break; 28639Sbill 28739Sbill /* 288903Sbill * Prevent more opens on channel 28939Sbill */ 29039Sbill case TIOCEXCL: 29139Sbill tp->t_state |= XCLUDE; 29239Sbill break; 29339Sbill 29439Sbill case TIOCNXCL: 29539Sbill tp->t_state &= ~XCLUDE; 29639Sbill break; 29739Sbill 29839Sbill /* 29939Sbill * Set new parameters 30039Sbill */ 30139Sbill case TIOCSETP: 302191Sbill case TIOCSETN: 30339Sbill if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) { 30439Sbill u.u_error = EFAULT; 30539Sbill return(1); 30639Sbill } 307121Sbill (void) spl5(); 308174Sbill if (tp->t_line == 0) { 309174Sbill if (com == TIOCSETP) 310174Sbill wflushtty(tp); 311174Sbill while (canon(tp)>=0) 312174Sbill ; 313933Sbill #ifdef notdef 314933Sbill wakeup((caddr_t)&tp->t_rawq); 315933Sbill #endif 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"); 330933Sbill #ifdef notdef 331174Sbill if (tp->t_chan) 332174Sbill (void) sdata(tp->t_chan); 333174Sbill else 334933Sbill #endif 335174Sbill wakeup((caddr_t)&tp->t_rawq); 336174Sbill } 337174Sbill } 338174Sbill } 33939Sbill if ((tp->t_state&SPEEDS)==0) { 340174Sbill tp->t_ispeed = iocb.sg_ispeed; 341174Sbill tp->t_ospeed = iocb.sg_ospeed; 34239Sbill } 343174Sbill tp->t_erase = iocb.sg_erase; 344174Sbill tp->t_kill = iocb.sg_kill; 345174Sbill tp->t_flags = iocb.sg_flags; 346*3941Sbugs if (tp->t_flags & RAW) { 347*3941Sbugs tp->t_state &= ~TTSTOP; 348*3941Sbugs ttstart(tp); 349*3941Sbugs } 350121Sbill (void) spl0(); 35139Sbill break; 35239Sbill 35339Sbill /* 354903Sbill * Send current parameters to user 35539Sbill */ 35639Sbill case TIOCGETP: 357174Sbill iocb.sg_ispeed = tp->t_ispeed; 358174Sbill iocb.sg_ospeed = tp->t_ospeed; 359174Sbill iocb.sg_erase = tp->t_erase; 360174Sbill iocb.sg_kill = tp->t_kill; 361174Sbill iocb.sg_flags = tp->t_flags; 36239Sbill if (copyout((caddr_t)&iocb, addr, sizeof(iocb))) 36339Sbill u.u_error = EFAULT; 36439Sbill break; 36539Sbill 36639Sbill /* 36739Sbill * Hang up line on last close 36839Sbill */ 36939Sbill case TIOCHPCL: 37039Sbill tp->t_state |= HUPCLS; 37139Sbill break; 37239Sbill 37339Sbill case TIOCFLUSH: 374872Sbill flushtty(tp, FREAD|FWRITE); 37539Sbill break; 37639Sbill 37739Sbill /* 378903Sbill * Set and fetch special characters 37939Sbill */ 38039Sbill case TIOCSETC: 381174Sbill if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars))) 38239Sbill u.u_error = EFAULT; 38339Sbill break; 38439Sbill 38539Sbill case TIOCGETC: 386174Sbill if (copyout((caddr_t)&tun, addr, sizeof(struct tchars))) 38739Sbill u.u_error = EFAULT; 38839Sbill break; 38939Sbill 390174Sbill /* local ioctls */ 391903Sbill /* 392903Sbill * Set/get local special characters. 393903Sbill */ 394174Sbill case TIOCSLTC: 395174Sbill if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars))) 396174Sbill u.u_error = EFAULT; 397174Sbill break; 398174Sbill 399174Sbill case TIOCGLTC: 400174Sbill if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars))) 401174Sbill u.u_error = EFAULT; 402174Sbill break; 403174Sbill 404903Sbill /* 405903Sbill * Return number of characters immediately available. 406903Sbill */ 407174Sbill case FIONREAD: { 408340Sbill off_t nread; 409174Sbill 410340Sbill switch (tp->t_line) { 411340Sbill 412340Sbill case NETLDISC: 413340Sbill nread = tp->t_rec ? tp->t_inbuf : 0; 414340Sbill break; 415340Sbill 416894Sbill case 0: 417894Sbill (void) spl5(); 418894Sbill while (canon(tp)>=0) 419894Sbill ; 420894Sbill (void) spl0(); 421894Sbill /* fall into ... */ 422894Sbill 423340Sbill case NTTYDISC: 424340Sbill nread = tp->t_canq.c_cc; 425340Sbill if (tp->t_flags & (RAW|CBREAK)) 426340Sbill nread += tp->t_rawq.c_cc; 427340Sbill break; 428340Sbill 429340Sbill } 430174Sbill if (copyout((caddr_t)&nread, addr, sizeof (off_t))) 431174Sbill u.u_error = EFAULT; 432174Sbill break; 433174Sbill } 434174Sbill 435174Sbill /* 436174Sbill * Should allow SPGRP and GPGRP only if tty open for reading. 437174Sbill */ 438174Sbill case TIOCSPGRP: 439728Sbill if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp))) 440728Sbill u.u_error = EFAULT; 441174Sbill break; 442174Sbill 443174Sbill case TIOCGPGRP: 444174Sbill if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp))) 445174Sbill u.u_error = EFAULT; 446174Sbill break; 447174Sbill 448174Sbill /* 449174Sbill * Modify local mode word. 450174Sbill */ 451174Sbill case TIOCLBIS: 452728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 453728Sbill u.u_error = EFAULT; 454728Sbill else 455728Sbill tp->t_local |= temp; 456174Sbill break; 457174Sbill 458174Sbill case TIOCLBIC: 459728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 460728Sbill u.u_error = EFAULT; 461728Sbill else 462728Sbill tp->t_local &= ~temp; 463174Sbill break; 464174Sbill 465174Sbill case TIOCLSET: 466728Sbill if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local))) 467728Sbill u.u_error = EFAULT; 468728Sbill else 469728Sbill tp->t_local = temp; 470174Sbill break; 471174Sbill 472174Sbill case TIOCLGET: 473174Sbill if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local))) 474174Sbill u.u_error = EFAULT; 475174Sbill break; 476174Sbill 477903Sbill /* 478903Sbill * Return number of characters in 479903Sbill * the output. 480903Sbill */ 481213Sbill case TIOCOUTQ: 482213Sbill if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc))) 483213Sbill u.u_error = EFAULT; 484213Sbill break; 485213Sbill 486903Sbill /* 487903Sbill * Simulate typing of a character at the terminal. 488903Sbill */ 489887Sbill case TIOCSTI: 490887Sbill c = fubyte(addr); 491887Sbill if (u.u_uid && u.u_ttyp != tp || c < 0) 492887Sbill u.u_error = EFAULT; 493887Sbill else 494887Sbill (*linesw[tp->t_line].l_rint)(c, tp); 495887Sbill break; 496174Sbill /* end of locals */ 497887Sbill 49839Sbill default: 49939Sbill return(0); 50039Sbill } 50139Sbill return(1); 50239Sbill } 503