1*12752Ssam /* tty.c 4.41 83/05/27 */ 239Sbill 39760Ssam #include "../machine/reg.h" 49760Ssam 539Sbill #include "../h/param.h" 639Sbill #include "../h/systm.h" 739Sbill #include "../h/dir.h" 839Sbill #include "../h/user.h" 99578Ssam #include "../h/ioctl.h" 1039Sbill #include "../h/tty.h" 1139Sbill #include "../h/proc.h" 1239Sbill #include "../h/inode.h" 1339Sbill #include "../h/file.h" 1439Sbill #include "../h/conf.h" 1539Sbill #include "../h/buf.h" 16340Sbill #include "../h/dk.h" 177722Swnj #include "../h/uio.h" 188154Sroot #include "../h/kernel.h" 1939Sbill 207436Skre /* 217436Skre * Table giving parity for characters and indicating 227436Skre * character classes to tty driver. In particular, 237436Skre * if the low 6 bits are 0, then the character needs 247436Skre * no special processing on output. 257436Skre */ 2639Sbill 277436Skre char partab[] = { 287436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 297436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 307436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 317436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 327436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 407436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 447436Skre 457436Skre /* 467436Skre * 7 bit ascii ends with the last character above, 477436Skre * but we contine through all 256 codes for the sake 487436Skre * of the tty output routines which use special vax 497436Skre * instructions which need a 256 character trt table. 507436Skre */ 517436Skre 527436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 537436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 547436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 557436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 567436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 577436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007 687436Skre }; 697436Skre 70146Sbill /* 7139Sbill * Input mapping table-- if an entry is non-zero, when the 7239Sbill * corresponding character is typed preceded by "\" the escape 7339Sbill * sequence is replaced by the table value. Mostly used for 7439Sbill * upper-case only terminals. 7539Sbill */ 7639Sbill char maptab[] ={ 7739Sbill 000,000,000,000,000,000,000,000, 7839Sbill 000,000,000,000,000,000,000,000, 7939Sbill 000,000,000,000,000,000,000,000, 8039Sbill 000,000,000,000,000,000,000,000, 8139Sbill 000,'|',000,000,000,000,000,'`', 8239Sbill '{','}',000,000,000,000,000,000, 8339Sbill 000,000,000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,000,000,000,000,000,000,000, 8639Sbill 000,000,000,000,000,000,000,000, 8739Sbill 000,000,000,000,000,000,000,000, 8839Sbill 000,000,000,000,000,000,'~',000, 8939Sbill 000,'A','B','C','D','E','F','G', 9039Sbill 'H','I','J','K','L','M','N','O', 9139Sbill 'P','Q','R','S','T','U','V','W', 9239Sbill 'X','Y','Z',000,000,000,000,000, 9339Sbill }; 9439Sbill 95925Sbill short tthiwat[16] = 968954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 97925Sbill short ttlowat[16] = 98925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 99925Sbill 1009578Ssam struct ttychars ttydefaults = { 1019578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1029578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1039578Ssam }; 10439Sbill 10539Sbill ttychars(tp) 1069578Ssam struct tty *tp; 10739Sbill { 108174Sbill 1099578Ssam tp->t_chars = ttydefaults; 11039Sbill } 11139Sbill 11239Sbill /* 113903Sbill * Wait for output to drain, then flush input waiting. 11439Sbill */ 115*12752Ssam ttywflush(tp) 1165408Swnj register struct tty *tp; 11739Sbill { 11839Sbill 119*12752Ssam ttywait(tp); 120*12752Ssam ttyflush(tp, FREAD); 121*12752Ssam } 122*12752Ssam 123*12752Ssam ttywait(tp) 124*12752Ssam register struct tty *tp; 125*12752Ssam { 126*12752Ssam register int s = spl5(); 127*12752Ssam 1285622Swnj while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON 1295622Swnj && tp->t_oproc) { /* kludge for pty */ 130903Sbill (*tp->t_oproc)(tp); 1315408Swnj tp->t_state |= TS_ASLEEP; 132903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 133903Sbill } 1349859Ssam splx(s); 13539Sbill } 13639Sbill 13739Sbill /* 1389578Ssam * Flush all TTY queues 13939Sbill */ 140*12752Ssam ttyflush(tp, rw) 1417625Ssam register struct tty *tp; 14239Sbill { 143903Sbill register s; 144903Sbill 145903Sbill s = spl6(); 146903Sbill if (rw & FREAD) { 147903Sbill while (getc(&tp->t_canq) >= 0) 148903Sbill ; 149903Sbill wakeup((caddr_t)&tp->t_rawq); 150903Sbill } 151903Sbill if (rw & FWRITE) { 152903Sbill wakeup((caddr_t)&tp->t_outq); 1535408Swnj tp->t_state &= ~TS_TTSTOP; 1545426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 155903Sbill while (getc(&tp->t_outq) >= 0) 156903Sbill ; 157903Sbill } 158903Sbill if (rw & FREAD) { 159903Sbill while (getc(&tp->t_rawq) >= 0) 160903Sbill ; 161903Sbill tp->t_delct = 0; 1629578Ssam tp->t_rocount = 0; 163903Sbill tp->t_rocol = 0; 1649578Ssam tp->t_state &= ~TS_LOCAL; 165903Sbill } 166903Sbill splx(s); 16739Sbill } 16839Sbill 169903Sbill /* 170903Sbill * Send stop character on input overflow. 171903Sbill */ 172903Sbill ttyblock(tp) 1737625Ssam register struct tty *tp; 17439Sbill { 175903Sbill register x; 1769578Ssam 177903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 178903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 179*12752Ssam ttyflush(tp, FREAD|FWRITE); 1805408Swnj tp->t_state &= ~TS_TBLOCK; 181903Sbill } 1829578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 1839578Ssam tp->t_state |= TS_TBLOCK; 1849578Ssam ttstart(tp); 185903Sbill } 18639Sbill } 18739Sbill 18839Sbill /* 189903Sbill * Restart typewriter output following a delay 190903Sbill * timeout. 191903Sbill * The name of the routine is passed to the timeout 192903Sbill * subroutine and it is called during a clock interrupt. 193121Sbill */ 194903Sbill ttrstrt(tp) 1957625Ssam register struct tty *tp; 196121Sbill { 197121Sbill 1989578Ssam if (tp == 0) 1999578Ssam panic("ttrstrt"); 2005408Swnj tp->t_state &= ~TS_TIMEOUT; 201903Sbill ttstart(tp); 202121Sbill } 203121Sbill 204121Sbill /* 205903Sbill * Start output on the typewriter. It is used from the top half 206903Sbill * after some characters have been put on the output queue, 207903Sbill * from the interrupt routine to transmit the next 208903Sbill * character, and after a timeout has finished. 20939Sbill */ 210903Sbill ttstart(tp) 2117625Ssam register struct tty *tp; 21239Sbill { 213903Sbill register s; 21439Sbill 215903Sbill s = spl5(); 2169578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2175622Swnj tp->t_oproc) /* kludge for pty */ 218903Sbill (*tp->t_oproc)(tp); 219903Sbill splx(s); 22039Sbill } 22139Sbill 22239Sbill /* 223903Sbill * Common code for tty ioctls. 22439Sbill */ 2251780Sbill /*ARGSUSED*/ 2267625Ssam ttioctl(tp, com, data, flag) 2277625Ssam register struct tty *tp; 2287625Ssam caddr_t data; 22939Sbill { 2308520Sroot int dev = tp->t_dev; 23139Sbill extern int nldisp; 2328556Sroot int s; 233*12752Ssam register int newflags; 23439Sbill 235903Sbill /* 236903Sbill * If the ioctl involves modification, 237903Sbill * insist on being able to write the device, 238903Sbill * and hang if in the background. 239903Sbill */ 2407625Ssam switch (com) { 24139Sbill 242915Sbill case TIOCSETD: 243915Sbill case TIOCSETP: 244915Sbill case TIOCSETN: 245903Sbill case TIOCFLUSH: 246903Sbill case TIOCSETC: 247903Sbill case TIOCSLTC: 248903Sbill case TIOCSPGRP: 249903Sbill case TIOCLBIS: 250903Sbill case TIOCLBIC: 251903Sbill case TIOCLSET: 2529624Ssam case TIOCBIS: 2539624Ssam case TIOCBIC: 2549624Ssam case TIOCSET: 2559325Ssam case TIOCSTI: 256903Sbill while (tp->t_line == NTTYDISC && 257903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 258903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 259903Sbill u.u_signal[SIGTTOU] != SIG_IGN && 2608556Sroot u.u_signal[SIGTTOU] != SIG_HOLD) { 261903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 262903Sbill sleep((caddr_t)&lbolt, TTOPRI); 263903Sbill } 264903Sbill break; 265903Sbill } 266903Sbill 2679578Ssam /* 2689578Ssam * Process the ioctl. 2699578Ssam */ 2707625Ssam switch (com) { 271903Sbill 2728556Sroot /* get discipline number */ 27339Sbill case TIOCGETD: 2747625Ssam *(int *)data = tp->t_line; 27539Sbill break; 27639Sbill 2778556Sroot /* set line discipline */ 2787625Ssam case TIOCSETD: { 2797625Ssam register int t = *(int *)data; 2809578Ssam int error = 0; 2817625Ssam 28210851Ssam if (t >= nldisp) 28310851Ssam return (ENXIO); 2848556Sroot s = spl5(); 28539Sbill if (tp->t_line) 28639Sbill (*linesw[tp->t_line].l_close)(tp); 28739Sbill if (t) 2888556Sroot error = (*linesw[t].l_open)(dev, tp); 2898556Sroot splx(s); 29010851Ssam if (error) { 29110851Ssam s = spl5(); 29210851Ssam if (tp->t_line) 29310851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29410851Ssam splx(s); 2958556Sroot return (error); 29610851Ssam } 2978556Sroot tp->t_line = t; 29839Sbill break; 2997625Ssam } 30039Sbill 3018556Sroot /* prevent more opens on channel */ 3025614Swnj case TIOCEXCL: 3035614Swnj tp->t_state |= TS_XCLUDE; 3045614Swnj break; 3055614Swnj 3065614Swnj case TIOCNXCL: 3075614Swnj tp->t_state &= ~TS_XCLUDE; 3085614Swnj break; 3095614Swnj 3107625Ssam 3119624Ssam case TIOCGET: 312*12752Ssam *(int *)data = tp->t_flags; 3139624Ssam break; 3149624Ssam 3159624Ssam case TIOCCGET: 3169624Ssam bcopy((caddr_t)&tp->t_chars, data, sizeof (struct ttychars)); 3179624Ssam break; 3189624Ssam 3199624Ssam case TIOCCSET: 3209624Ssam bcopy(data, (caddr_t)&tp->t_chars, sizeof (struct ttychars)); 3219624Ssam break; 3229624Ssam 3238556Sroot /* hang up line on last close */ 32439Sbill case TIOCHPCL: 3255408Swnj tp->t_state |= TS_HUPCLS; 32639Sbill break; 32739Sbill 3283942Sbugs case TIOCFLUSH: { 3297625Ssam register int flags = *(int *)data; 3307625Ssam 3317625Ssam if (flags == 0) 3323942Sbugs flags = FREAD|FWRITE; 3337625Ssam else 3347625Ssam flags &= FREAD|FWRITE; 335*12752Ssam ttyflush(tp, flags); 33639Sbill break; 3373944Sbugs } 33839Sbill 3398556Sroot /* return number of characters immediately available */ 3407625Ssam case FIONREAD: 3417625Ssam *(off_t *)data = ttnread(tp); 342174Sbill break; 343174Sbill 3448589Sroot case TIOCSTOP: 3458589Sroot s = spl5(); 3469578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3475573Swnj tp->t_state |= TS_TTSTOP; 3485573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3495573Swnj } 3507625Ssam splx(s); 3515573Swnj break; 3525573Swnj 3538589Sroot case TIOCSTART: 3548589Sroot s = spl5(); 3559578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3565573Swnj tp->t_state &= ~TS_TTSTOP; 3579578Ssam tp->t_flags &= ~FLUSHO; 3585573Swnj ttstart(tp); 3595573Swnj } 3607625Ssam splx(s); 3615573Swnj break; 3625573Swnj 3639325Ssam /* 3649325Ssam * Simulate typing of a character at the terminal. 3659325Ssam */ 3669325Ssam case TIOCSTI: 3679325Ssam if (u.u_uid && u.u_ttyp != tp) 3689325Ssam return (EACCES); 3699578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3709325Ssam break; 3719325Ssam 372*12752Ssam case TIOCSET: 373*12752Ssam case TIOCBIS: 374*12752Ssam case TIOCBIC: 375*12752Ssam newflags = *(int *)data; 376*12752Ssam if (com == TIOCBIS) 377*12752Ssam newflags |= tp->t_flags; 378*12752Ssam else if (com == TIOCBIC) 379*12752Ssam newflags = tp->t_flags &~ newflags; 380*12752Ssam goto setin; 381*12752Ssam 382*12752Ssam case TIOCSETP: 383*12752Ssam case TIOCSETN: { 384*12752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 385*12752Ssam 386*12752Ssam tp->t_erase = sg->sg_erase; 387*12752Ssam tp->t_kill = sg->sg_kill; 388*12752Ssam tp->t_ispeed = sg->sg_ispeed; 389*12752Ssam tp->t_ospeed = sg->sg_ospeed; 390*12752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 391*12752Ssam setin: 392*12752Ssam s = spl5(); 393*12752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 394*12752Ssam ttywait(tp); 395*12752Ssam ttyflush(tp, FREAD); 396*12752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 397*12752Ssam if (newflags&CBREAK) { 398*12752Ssam struct clist tq; 399*12752Ssam 400*12752Ssam catq(&tp->t_rawq, &tp->t_canq); 401*12752Ssam tq = tp->t_rawq; 402*12752Ssam tp->t_rawq = tp->t_canq; 403*12752Ssam tp->t_canq = tq; 404*12752Ssam } else { 405*12752Ssam tp->t_flags |= PENDIN; 406*12752Ssam ttwakeup(tp); 407*12752Ssam } 408*12752Ssam } 409*12752Ssam tp->t_flags = newflags; 410*12752Ssam if (tp->t_flags&RAW) { 411*12752Ssam tp->t_state &= ~TS_TTSTOP; 412*12752Ssam ttstart(tp); 413*12752Ssam } 414*12752Ssam splx(s); 415*12752Ssam break; 416*12752Ssam } 417*12752Ssam 418*12752Ssam /* send current parameters to user */ 419*12752Ssam case TIOCGETP: { 420*12752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 421*12752Ssam 422*12752Ssam sg->sg_ispeed = tp->t_ispeed; 423*12752Ssam sg->sg_ospeed = tp->t_ospeed; 424*12752Ssam sg->sg_erase = tp->t_erase; 425*12752Ssam sg->sg_kill = tp->t_kill; 426*12752Ssam sg->sg_flags = tp->t_flags; 427*12752Ssam break; 428*12752Ssam } 429*12752Ssam 430*12752Ssam case FIONBIO: 431*12752Ssam if (*(int *)data) 432*12752Ssam tp->t_state |= TS_NBIO; 433*12752Ssam else 434*12752Ssam tp->t_state &= ~TS_NBIO; 435*12752Ssam break; 436*12752Ssam 437*12752Ssam case FIOASYNC: 438*12752Ssam if (*(int *)data) 439*12752Ssam tp->t_state |= TS_ASYNC; 440*12752Ssam else 441*12752Ssam tp->t_state &= ~TS_ASYNC; 442*12752Ssam break; 443*12752Ssam 444*12752Ssam /* set/get local special characters */ 445*12752Ssam case TIOCSLTC: 446*12752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 447*12752Ssam break; 448*12752Ssam 449*12752Ssam case TIOCGLTC: 450*12752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 451*12752Ssam break; 452*12752Ssam 453*12752Ssam /* 454*12752Ssam * Modify local mode word. 455*12752Ssam */ 456*12752Ssam case TIOCLBIS: 457*12752Ssam tp->t_flags |= *(int *)data << 16; 458*12752Ssam break; 459*12752Ssam 460*12752Ssam case TIOCLBIC: 461*12752Ssam tp->t_flags &= ~(*(int *)data << 16); 462*12752Ssam break; 463*12752Ssam 464*12752Ssam case TIOCLSET: 465*12752Ssam tp->t_flags &= 0xffff; 466*12752Ssam tp->t_flags |= *(int *)data << 16; 467*12752Ssam break; 468*12752Ssam 469*12752Ssam case TIOCLGET: 470*12752Ssam *(int *)data = tp->t_flags >> 16; 471*12752Ssam break; 472*12752Ssam 473*12752Ssam /* should allow SPGRP and GPGRP only if tty open for reading */ 474*12752Ssam case TIOCSPGRP: 475*12752Ssam tp->t_pgrp = *(int *)data; 476*12752Ssam break; 477*12752Ssam 478*12752Ssam case TIOCGPGRP: 479*12752Ssam *(int *)data = tp->t_pgrp; 480*12752Ssam break; 481*12752Ssam 48239Sbill default: 4838556Sroot return (-1); 48439Sbill } 4858556Sroot return (0); 48639Sbill } 4874484Swnj 4884484Swnj ttnread(tp) 4894484Swnj struct tty *tp; 4904484Swnj { 4914484Swnj int nread = 0; 4924484Swnj 4939578Ssam if (tp->t_flags & PENDIN) 4944484Swnj ttypend(tp); 4954484Swnj nread = tp->t_canq.c_cc; 4964484Swnj if (tp->t_flags & (RAW|CBREAK)) 4974484Swnj nread += tp->t_rawq.c_cc; 4984484Swnj return (nread); 4994484Swnj } 5004484Swnj 5015408Swnj ttselect(dev, rw) 5024484Swnj dev_t dev; 5035408Swnj int rw; 5044484Swnj { 5054484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5064484Swnj int nread; 5075408Swnj int s = spl5(); 5084484Swnj 5095408Swnj switch (rw) { 5104484Swnj 5114484Swnj case FREAD: 5124484Swnj nread = ttnread(tp); 5134484Swnj if (nread > 0) 5145408Swnj goto win; 5154938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5165408Swnj tp->t_state |= TS_RCOLL; 5174484Swnj else 5184484Swnj tp->t_rsel = u.u_procp; 5195408Swnj break; 5204484Swnj 5215408Swnj case FWRITE: 5225408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5235408Swnj goto win; 5245408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5255408Swnj tp->t_state |= TS_WCOLL; 5265408Swnj else 5275408Swnj tp->t_wsel = u.u_procp; 5285408Swnj break; 5294484Swnj } 5305408Swnj splx(s); 5315408Swnj return (0); 5325408Swnj win: 5335408Swnj splx(s); 5345408Swnj return (1); 5354484Swnj } 5367436Skre 5377502Sroot /* 5389578Ssam * Establish a process group for distribution of 5397502Sroot * quits and interrupts from the tty. 5407502Sroot */ 5417502Sroot ttyopen(dev, tp) 5427625Ssam dev_t dev; 5437625Ssam register struct tty *tp; 5447502Sroot { 5457502Sroot register struct proc *pp; 5467502Sroot 5477502Sroot pp = u.u_procp; 5487502Sroot tp->t_dev = dev; 5497625Ssam if (pp->p_pgrp == 0) { 5507502Sroot u.u_ttyp = tp; 5517502Sroot u.u_ttyd = dev; 5527502Sroot if (tp->t_pgrp == 0) 5537502Sroot tp->t_pgrp = pp->p_pid; 5547502Sroot pp->p_pgrp = tp->t_pgrp; 5557502Sroot } 5567502Sroot tp->t_state &= ~TS_WOPEN; 5577502Sroot tp->t_state |= TS_ISOPEN; 5587502Sroot if (tp->t_line != NTTYDISC) 559*12752Ssam ttywflush(tp); 5608556Sroot return (0); 5617502Sroot } 5627502Sroot 5637502Sroot /* 5647502Sroot * clean tp on last close 5657502Sroot */ 5667502Sroot ttyclose(tp) 5677625Ssam register struct tty *tp; 5687502Sroot { 5697502Sroot 5707502Sroot if (tp->t_line) { 571*12752Ssam ttywflush(tp); 5727502Sroot tp->t_line = 0; 5737502Sroot return; 5747502Sroot } 5757502Sroot tp->t_pgrp = 0; 576*12752Ssam ttywflush(tp); 5777502Sroot tp->t_state = 0; 5787502Sroot } 5797502Sroot 5807502Sroot /* 5817502Sroot * reinput pending characters after state switch 5827502Sroot * call at spl5(). 5837502Sroot */ 5847502Sroot ttypend(tp) 5857625Ssam register struct tty *tp; 5867502Sroot { 5877502Sroot struct clist tq; 5887502Sroot register c; 5897502Sroot 5909578Ssam tp->t_flags &= ~PENDIN; 5919578Ssam tp->t_state |= TS_TYPEN; 5927502Sroot tq = tp->t_rawq; 5937502Sroot tp->t_rawq.c_cc = 0; 5947502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5957502Sroot while ((c = getc(&tq)) >= 0) 5967502Sroot ttyinput(c, tp); 5979578Ssam tp->t_state &= ~TS_TYPEN; 5987502Sroot } 5997502Sroot 6007502Sroot /* 6019578Ssam * Place a character on raw TTY input queue, 6029578Ssam * putting in delimiters and waking up top 6039578Ssam * half as needed. Also echo if required. 6049578Ssam * The arguments are the character and the 6059578Ssam * appropriate tty structure. 6067502Sroot */ 6077502Sroot ttyinput(c, tp) 6087625Ssam register c; 6097625Ssam register struct tty *tp; 6107502Sroot { 6119578Ssam register int t_flags = tp->t_flags; 6127502Sroot int i; 6137502Sroot 6149578Ssam /* 6159578Ssam * If input is pending take it first. 6169578Ssam */ 6179578Ssam if (t_flags&PENDIN) 6187502Sroot ttypend(tp); 6197502Sroot tk_nin++; 6207502Sroot c &= 0377; 6219578Ssam 6229578Ssam /* 6239578Ssam * In tandem mode, check high water mark. 6249578Ssam */ 6257502Sroot if (t_flags&TANDEM) 6267502Sroot ttyblock(tp); 6279578Ssam 6289578Ssam if (t_flags&RAW) { 6299578Ssam /* 6309578Ssam * Raw mode, just put character 6319578Ssam * in input q w/o interpretation. 6329578Ssam */ 6339578Ssam if (tp->t_rawq.c_cc > TTYHOG) 634*12752Ssam ttyflush(tp, FREAD|FWRITE); 6359578Ssam else { 6369578Ssam if (putc(c, &tp->t_rawq) >= 0) 6379578Ssam ttwakeup(tp); 6389578Ssam ttyecho(c, tp); 6397502Sroot } 6409578Ssam goto endcase; 6419578Ssam } 6429578Ssam 6439578Ssam /* 6449578Ssam * Ignore any high bit added during 6459578Ssam * previous ttyinput processing. 6469578Ssam */ 6479578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6489578Ssam c &= 0177; 6499578Ssam /* 6509578Ssam * Check for literal nexting very first 6519578Ssam */ 6529578Ssam if (tp->t_state&TS_LNCH) { 6539578Ssam c |= 0200; 6549578Ssam tp->t_state &= ~TS_LNCH; 6559578Ssam } 6569578Ssam 6579578Ssam /* 6589578Ssam * Scan for special characters. This code 6599578Ssam * is really just a big case statement with 6609578Ssam * non-constant cases. The bottom of the 6619578Ssam * case statement is labeled ``endcase'', so goto 6629578Ssam * it after a case match, or similar. 6639578Ssam */ 6649578Ssam if (tp->t_line == NTTYDISC) { 6659578Ssam if (c == tp->t_lnextc) { 6667502Sroot if (tp->t_flags&ECHO) 6677502Sroot ttyout("^\b", tp); 6689578Ssam tp->t_state |= TS_LNCH; 6699578Ssam goto endcase; 6709578Ssam } 6719578Ssam if (c == tp->t_flushc) { 6729578Ssam if (tp->t_flags&FLUSHO) 6739578Ssam tp->t_flags &= ~FLUSHO; 6747502Sroot else { 675*12752Ssam ttyflush(tp, FWRITE); 6767502Sroot ttyecho(c, tp); 6779578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6787502Sroot ttyretype(tp); 6799578Ssam tp->t_flags |= FLUSHO; 6807502Sroot } 6819578Ssam goto startoutput; 6829578Ssam } 6839578Ssam if (c == tp->t_suspc) { 6849578Ssam if ((tp->t_flags&NOFLSH) == 0) 685*12752Ssam ttyflush(tp, FREAD); 6869578Ssam ttyecho(c, tp); 6879578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6889578Ssam goto endcase; 6899578Ssam } 6909578Ssam } 6919578Ssam 6929578Ssam /* 6939578Ssam * Handle start/stop characters. 6949578Ssam */ 6959578Ssam if (c == tp->t_stopc) { 6969578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6979578Ssam tp->t_state |= TS_TTSTOP; 6989578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6997502Sroot return; 7009578Ssam } 7019578Ssam if (c != tp->t_startc) 7029578Ssam return; 7039578Ssam goto endcase; 7049578Ssam } 7059578Ssam if (c == tp->t_startc) 7069578Ssam goto restartoutput; 7079578Ssam 7089578Ssam /* 7099578Ssam * Look for interrupt/quit chars. 7109578Ssam */ 7119578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7129578Ssam if ((tp->t_flags&NOFLSH) == 0) 713*12752Ssam ttyflush(tp, FREAD|FWRITE); 7149578Ssam ttyecho(c, tp); 7159578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7169578Ssam goto endcase; 7179578Ssam } 7189578Ssam 7199578Ssam /* 7209578Ssam * Cbreak mode, don't process line editing 7219578Ssam * characters; check high water mark for wakeup. 7229578Ssam */ 7239578Ssam if (t_flags&CBREAK) { 7249578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7257502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7267502Sroot tp->t_line == NTTYDISC) 7277502Sroot (void) ttyoutput(CTRL(g), tp); 7287502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7297502Sroot ttwakeup(tp); 7307502Sroot ttyecho(c, tp); 7317502Sroot } 7329578Ssam goto endcase; 7339578Ssam } 7349578Ssam 7359578Ssam /* 7369578Ssam * From here on down cooked mode character 7379578Ssam * processing takes place. 7389578Ssam */ 7399578Ssam if ((tp->t_state&TS_QUOT) && 7409578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7419578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7429578Ssam c |= 0200; 7439578Ssam } 7449578Ssam if (c == tp->t_erase) { 7459578Ssam if (tp->t_rawq.c_cc) 7469578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7479578Ssam goto endcase; 7489578Ssam } 7499578Ssam if (c == tp->t_kill) { 7509578Ssam if (tp->t_flags&CRTKIL && 7519578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7529578Ssam while (tp->t_rawq.c_cc) 7539578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7549578Ssam } else { 7559578Ssam ttyecho(c, tp); 7569578Ssam ttyecho('\n', tp); 7579578Ssam while (getc(&tp->t_rawq) > 0) 7589578Ssam ; 7599578Ssam tp->t_rocount = 0; 7609578Ssam } 7619578Ssam tp->t_state &= ~TS_LOCAL; 7629578Ssam goto endcase; 7639578Ssam } 7649578Ssam 7659578Ssam /* 7669578Ssam * New line discipline, 7679578Ssam * check word erase/reprint line. 7689578Ssam */ 7699578Ssam if (tp->t_line == NTTYDISC) { 7709578Ssam if (c == tp->t_werasc) { 7719578Ssam if (tp->t_rawq.c_cc == 0) 7729578Ssam goto endcase; 7739578Ssam do { 7749578Ssam c = unputc(&tp->t_rawq); 7759578Ssam if (c != ' ' && c != '\t') 7769578Ssam goto erasenb; 7779578Ssam ttyrub(c, tp); 7789578Ssam } while (tp->t_rawq.c_cc); 7799578Ssam goto endcase; 7809578Ssam erasenb: 7819578Ssam do { 7829578Ssam ttyrub(c, tp); 7839578Ssam if (tp->t_rawq.c_cc == 0) 7849578Ssam goto endcase; 7859578Ssam c = unputc(&tp->t_rawq); 7869578Ssam } while (c != ' ' && c != '\t'); 7879578Ssam (void) putc(c, &tp->t_rawq); 7889578Ssam goto endcase; 7899578Ssam } 7909578Ssam if (c == tp->t_rprntc) { 7919578Ssam ttyretype(tp); 7929578Ssam goto endcase; 7939578Ssam } 7949578Ssam } 7959578Ssam 7969578Ssam /* 7979578Ssam * Check for input buffer overflow 7989578Ssam */ 79910391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 80010391Ssam if (tp->t_line == NTTYDISC) 80110391Ssam (void) ttyoutput(CTRL(g), tp); 8029578Ssam goto endcase; 80310391Ssam } 8049578Ssam 8059578Ssam /* 8069578Ssam * Put data char in q for user and 8079578Ssam * wakeup on seeing a line delimiter. 8089578Ssam */ 8099578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8109578Ssam if (ttbreakc(c, tp)) { 8119578Ssam tp->t_rocount = 0; 8129578Ssam catq(&tp->t_rawq, &tp->t_canq); 8137502Sroot ttwakeup(tp); 8149578Ssam } else if (tp->t_rocount++ == 0) 8159578Ssam tp->t_rocol = tp->t_col; 8169578Ssam tp->t_state &= ~TS_QUOT; 8179578Ssam if (c == '\\') 8189578Ssam tp->t_state |= TS_QUOT; 8199578Ssam if (tp->t_state&TS_ERASE) { 8209578Ssam tp->t_state &= ~TS_ERASE; 8219578Ssam (void) ttyoutput('/', tp); 8229578Ssam } 8239578Ssam i = tp->t_col; 8247502Sroot ttyecho(c, tp); 8259578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8269578Ssam i = MIN(2, tp->t_col - i); 8279578Ssam while (i > 0) { 8289578Ssam (void) ttyoutput('\b', tp); 8299578Ssam i--; 8309578Ssam } 8319578Ssam } 8327502Sroot } 8339578Ssam 8349578Ssam endcase: 8359578Ssam /* 8369578Ssam * If DEC-style start/stop is enabled don't restart 8379578Ssam * output until seeing the start character. 8389578Ssam */ 8399578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8409578Ssam tp->t_startc != tp->t_stopc) 8417502Sroot return; 8429578Ssam 8439578Ssam restartoutput: 8447502Sroot tp->t_state &= ~TS_TTSTOP; 8459578Ssam tp->t_flags &= ~FLUSHO; 8469578Ssam 8479578Ssam startoutput: 8487502Sroot ttstart(tp); 8497502Sroot } 8507502Sroot 8517502Sroot /* 8529578Ssam * Put character on TTY output queue, adding delays, 8537502Sroot * expanding tabs, and handling the CR/NL bit. 8549578Ssam * This is called both from the top half for output, 8559578Ssam * and from interrupt level for echoing. 8567502Sroot * The arguments are the character and the tty structure. 8577502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8587502Sroot * Must be recursive. 8597502Sroot */ 8607502Sroot ttyoutput(c, tp) 8617502Sroot register c; 8627502Sroot register struct tty *tp; 8637502Sroot { 8647502Sroot register char *colp; 8657502Sroot register ctype; 8667502Sroot 8679578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8689578Ssam if (tp->t_flags&FLUSHO) 8697502Sroot return (-1); 8707502Sroot if (putc(c, &tp->t_outq)) 8717625Ssam return (c); 8727502Sroot tk_nout++; 8737502Sroot return (-1); 8747502Sroot } 8759578Ssam 8767502Sroot /* 8779578Ssam * Ignore EOT in normal mode to avoid 8789578Ssam * hanging up certain terminals. 8797502Sroot */ 8807502Sroot c &= 0177; 8819578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8827502Sroot return (-1); 8837502Sroot /* 8847502Sroot * Turn tabs to spaces as required 8857502Sroot */ 8869578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8877502Sroot register int s; 8887502Sroot 8897502Sroot c = 8 - (tp->t_col&7); 8909578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8917502Sroot s = spl5(); /* don't interrupt tabs */ 8927502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8937502Sroot tk_nout += c; 8947502Sroot splx(s); 8957502Sroot } 8967502Sroot tp->t_col += c; 8977502Sroot return (c ? -1 : '\t'); 8987502Sroot } 8997502Sroot tk_nout++; 9007502Sroot /* 9017502Sroot * for upper-case-only terminals, 9027502Sroot * generate escapes. 9037502Sroot */ 9047502Sroot if (tp->t_flags&LCASE) { 9057502Sroot colp = "({)}!|^~'`"; 9067625Ssam while (*colp++) 9077625Ssam if (c == *colp++) { 9087502Sroot if (ttyoutput('\\', tp) >= 0) 9097502Sroot return (c); 9107502Sroot c = colp[-2]; 9117502Sroot break; 9127502Sroot } 9139578Ssam if ('A' <= c && c <= 'Z') { 9147502Sroot if (ttyoutput('\\', tp) >= 0) 9157502Sroot return (c); 9169578Ssam } else if ('a' <= c && c <= 'z') 9177502Sroot c += 'A' - 'a'; 9187502Sroot } 9199578Ssam 9207502Sroot /* 9217502Sroot * turn <nl> to <cr><lf> if desired. 9227502Sroot */ 9239578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9247502Sroot if (ttyoutput('\r', tp) >= 0) 9257502Sroot return (c); 9269578Ssam if (c == '~' && tp->t_flags&TILDE) 9277502Sroot c = '`'; 9289578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9297502Sroot return (c); 9307502Sroot /* 9317502Sroot * Calculate delays. 9327502Sroot * The numbers here represent clock ticks 9337502Sroot * and are not necessarily optimal for all terminals. 9347502Sroot * The delays are indicated by characters above 0200. 9357502Sroot * In raw mode there are no delays and the 9367502Sroot * transmission path is 8 bits wide. 9379578Ssam * 9389578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9397502Sroot */ 9407502Sroot colp = &tp->t_col; 9417502Sroot ctype = partab[c]; 9427502Sroot c = 0; 9437502Sroot switch (ctype&077) { 9447502Sroot 9457502Sroot case ORDINARY: 9467502Sroot (*colp)++; 9477502Sroot 9487502Sroot case CONTROL: 9497502Sroot break; 9507502Sroot 9517502Sroot case BACKSPACE: 9527502Sroot if (*colp) 9537502Sroot (*colp)--; 9547502Sroot break; 9557502Sroot 9567502Sroot case NEWLINE: 9577502Sroot ctype = (tp->t_flags >> 8) & 03; 9587625Ssam if (ctype == 1) { /* tty 37 */ 959*12752Ssam if (*colp > 0) 9607502Sroot c = max(((unsigned)*colp>>4) + 3, (unsigned)6); 9619578Ssam } else if (ctype == 2) /* vt05 */ 9627502Sroot c = 6; 9637502Sroot *colp = 0; 9647502Sroot break; 9657502Sroot 9667502Sroot case TAB: 9677502Sroot ctype = (tp->t_flags >> 10) & 03; 9687625Ssam if (ctype == 1) { /* tty 37 */ 9697502Sroot c = 1 - (*colp | ~07); 9707625Ssam if (c < 5) 9717502Sroot c = 0; 9727502Sroot } 9737502Sroot *colp |= 07; 9747502Sroot (*colp)++; 9757502Sroot break; 9767502Sroot 9777502Sroot case VTAB: 9789578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9797502Sroot c = 0177; 9807502Sroot break; 9817502Sroot 9827502Sroot case RETURN: 9837502Sroot ctype = (tp->t_flags >> 12) & 03; 9849578Ssam if (ctype == 1) /* tn 300 */ 9857502Sroot c = 5; 9869578Ssam else if (ctype == 2) /* ti 700 */ 9877502Sroot c = 10; 9889578Ssam else if (ctype == 3) { /* concept 100 */ 9897502Sroot int i; 9909578Ssam 9917502Sroot if ((i = *colp) >= 0) 9929578Ssam for (; i < 9; i++) 9937502Sroot (void) putc(0177, &tp->t_outq); 9947502Sroot } 9957502Sroot *colp = 0; 9967502Sroot } 9979578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9987502Sroot (void) putc(c|0200, &tp->t_outq); 9997502Sroot return (-1); 10007502Sroot } 10017502Sroot 10027502Sroot /* 10037502Sroot * Called from device's read routine after it has 10047502Sroot * calculated the tty-structure given as argument. 10057502Sroot */ 10067722Swnj ttread(tp, uio) 10077625Ssam register struct tty *tp; 10087722Swnj struct uio *uio; 10097502Sroot { 10107502Sroot register struct clist *qp; 10119578Ssam register c, t_flags; 10129859Ssam int s, first, error = 0; 10137502Sroot 10147502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10158520Sroot return (EIO); 10167502Sroot loop: 10179578Ssam /* 10189578Ssam * Take any pending input first. 10199578Ssam */ 10209859Ssam s = spl5(); 10219578Ssam if (tp->t_flags&PENDIN) 10227502Sroot ttypend(tp); 10239859Ssam splx(s); 10249578Ssam 10259578Ssam /* 10269578Ssam * Hang process if it's in the background. 10279578Ssam */ 10287502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10297502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10307502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10317502Sroot /* 10327502Sroot (u.u_procp->p_flag&SDETACH) || 10337502Sroot */ 10347502Sroot u.u_procp->p_flag&SVFORK) 10358520Sroot return (EIO); 10367502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10377502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10387502Sroot } 10399578Ssam t_flags = tp->t_flags; 10409578Ssam 10419578Ssam /* 10429578Ssam * In raw mode take characters directly from the 10439578Ssam * raw queue w/o processing. Interlock against 10449578Ssam * device interrupts when interrogating rawq. 10459578Ssam */ 10469578Ssam if (t_flags&RAW) { 10479859Ssam s = spl5(); 10487502Sroot if (tp->t_rawq.c_cc <= 0) { 10499578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10507502Sroot (tp->t_state&TS_NBIO)) { 10519859Ssam splx(s); 10529578Ssam return (0); 10537502Sroot } 10547502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10559859Ssam splx(s); 10567502Sroot goto loop; 10577502Sroot } 10589859Ssam splx(s); 10599859Ssam while (!error && tp->t_rawq.c_cc && uio->uio_iovcnt) 10608520Sroot error = passuc(getc(&tp->t_rawq), uio); 10619859Ssam goto checktandem; 10629578Ssam } 10639578Ssam 10649578Ssam /* 10659578Ssam * In cbreak mode use the rawq, otherwise 10669578Ssam * take characters from the canonicalized q. 10679578Ssam */ 10689578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10699578Ssam 10709578Ssam /* 10719578Ssam * No input, sleep on rawq awaiting hardware 10729578Ssam * receipt and notification. 10739578Ssam */ 10749859Ssam s = spl5(); 10759578Ssam if (qp->c_cc <= 0) { 10769578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10779578Ssam (tp->t_state&TS_NBIO)) { 10789859Ssam splx(s); 10799578Ssam return (EWOULDBLOCK); 10807502Sroot } 10819578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10829859Ssam splx(s); 10839578Ssam goto loop; 10849578Ssam } 10859859Ssam splx(s); 10869578Ssam 10879578Ssam /* 10889578Ssam * Input present, perform input mapping 10899578Ssam * and processing (we're not in raw mode). 10909578Ssam */ 10919578Ssam first = 1; 10929578Ssam while ((c = getc(qp)) >= 0) { 10939578Ssam if (t_flags&CRMOD && c == '\r') 10949578Ssam c = '\n'; 10959578Ssam /* 10969578Ssam * Hack lower case simulation on 10979578Ssam * upper case only terminals. 10989578Ssam */ 10999578Ssam if (t_flags&LCASE && c <= 0177) 11009578Ssam if (tp->t_state&TS_BKSL) { 11019578Ssam if (maptab[c]) 11029578Ssam c = maptab[c]; 11039578Ssam tp->t_state &= ~TS_BKSL; 11049578Ssam } else if (c >= 'A' && c <= 'Z') 11059578Ssam c += 'a' - 'A'; 11069578Ssam else if (c == '\\') { 11079578Ssam tp->t_state |= TS_BKSL; 11089578Ssam continue; 11097502Sroot } 11109578Ssam /* 11119578Ssam * Check for delayed suspend character. 11129578Ssam */ 11139578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11149578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11159578Ssam if (first) { 11169578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11179578Ssam goto loop; 11189578Ssam } 11199578Ssam break; 11207502Sroot } 11219578Ssam /* 11229578Ssam * Interpret EOF only in cooked mode. 11239578Ssam */ 11249578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11259578Ssam break; 11269578Ssam /* 11279578Ssam * Give user character. 11289578Ssam */ 11299578Ssam error = passuc(c & 0177, uio); 11309578Ssam if (error) 11319578Ssam break; 11329578Ssam if (uio->uio_iovcnt == 0) 11339578Ssam break; 11349578Ssam /* 11359578Ssam * In cooked mode check for a "break character" 11369578Ssam * marking the end of a "line of input". 11379578Ssam */ 11389578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11399578Ssam break; 11409578Ssam first = 0; 11417502Sroot } 11429578Ssam tp->t_state &= ~TS_BKSL; 11439578Ssam 11449859Ssam checktandem: 11459578Ssam /* 11469578Ssam * Look to unblock output now that (presumably) 11479578Ssam * the input queue has gone down. 11489578Ssam */ 11499859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11509578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11517502Sroot tp->t_state &= ~TS_TBLOCK; 11527502Sroot ttstart(tp); 11537502Sroot } 11548520Sroot return (error); 11557502Sroot } 11567502Sroot 11577502Sroot /* 11587502Sroot * Called from the device's write routine after it has 11597502Sroot * calculated the tty-structure given as argument. 11607502Sroot */ 11617822Sroot ttwrite(tp, uio) 11627625Ssam register struct tty *tp; 11639578Ssam register struct uio *uio; 11647502Sroot { 11657502Sroot register char *cp; 11669578Ssam register int cc, ce, c; 11679578Ssam int i, hiwat, cnt, error, s; 11687502Sroot char obuf[OBUFSIZ]; 11697502Sroot 11709578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11718520Sroot return (EIO); 11729578Ssam hiwat = TTHIWAT(tp); 11739578Ssam cnt = uio->uio_resid; 11749578Ssam error = 0; 11757502Sroot loop: 11769578Ssam /* 11779578Ssam * Hang the process if it's in the background. 11789578Ssam */ 11797502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11809578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11817502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11827502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11837502Sroot /* 11847502Sroot && 11857502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11867502Sroot */ 11877502Sroot ) { 11887502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11897502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11907502Sroot } 11919578Ssam 11929578Ssam /* 11939578Ssam * Process the user's data in at most OBUFSIZ 11949578Ssam * chunks. Perform lower case simulation and 11959578Ssam * similar hacks. Keep track of high water 11969578Ssam * mark, sleep on overflow awaiting device aid 11979578Ssam * in acquiring new space. 11989578Ssam */ 11997822Sroot while (uio->uio_resid > 0) { 12009578Ssam /* 12019578Ssam * Grab a hunk of data from the user. 12029578Ssam */ 12037822Sroot cc = uio->uio_iov->iov_len; 12047822Sroot if (cc == 0) { 12057822Sroot uio->uio_iovcnt--; 12067822Sroot uio->uio_iov++; 12077822Sroot if (uio->uio_iovcnt < 0) 12087822Sroot panic("ttwrite"); 12097822Sroot continue; 12107822Sroot } 12117822Sroot if (cc > OBUFSIZ) 12127822Sroot cc = OBUFSIZ; 12137502Sroot cp = obuf; 1214*12752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12158520Sroot if (error) 12167502Sroot break; 12177502Sroot if (tp->t_outq.c_cc > hiwat) 12187502Sroot goto ovhiwat; 12199578Ssam if (tp->t_flags&FLUSHO) 12207502Sroot continue; 12219578Ssam /* 12229578Ssam * If we're mapping lower case or kludging tildes, 12239578Ssam * then we've got to look at each character, so 12249578Ssam * just feed the stuff to ttyoutput... 12259578Ssam */ 12269578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12279578Ssam while (cc > 0) { 12287502Sroot c = *cp++; 12297502Sroot tp->t_rocount = 0; 12307625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12317502Sroot /* out of clists, wait a bit */ 12327502Sroot ttstart(tp); 12337502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12347502Sroot tp->t_rocount = 0; 12357502Sroot } 12367502Sroot --cc; 12377502Sroot if (tp->t_outq.c_cc > hiwat) 12387502Sroot goto ovhiwat; 12397502Sroot } 12407502Sroot continue; 12417502Sroot } 12429578Ssam /* 12439578Ssam * If nothing fancy need be done, grab those characters we 12449578Ssam * can handle without any of ttyoutput's processing and 12459578Ssam * just transfer them to the output q. For those chars 12469578Ssam * which require special processing (as indicated by the 12479578Ssam * bits in partab), call ttyoutput. After processing 12489578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12499578Ssam * immediately. 12509578Ssam */ 12519578Ssam while (cc > 0) { 12529578Ssam if (tp->t_flags & (RAW|LITOUT)) 12537502Sroot ce = cc; 12547502Sroot else { 1255*12752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 1256*12752Ssam (caddr_t)partab, 077); 12579578Ssam /* 12589578Ssam * If ce is zero, then we're processing 12599578Ssam * a special character through ttyoutput. 12609578Ssam */ 12619578Ssam if (ce == 0) { 12627502Sroot tp->t_rocount = 0; 12637502Sroot if (ttyoutput(*cp, tp) >= 0) { 12649578Ssam /* no c-lists, wait a bit */ 12657502Sroot ttstart(tp); 12667502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12677502Sroot continue; 12687502Sroot } 12699578Ssam cp++, cc--; 12709578Ssam if (tp->t_flags&FLUSHO || 12719578Ssam tp->t_outq.c_cc > hiwat) 12727502Sroot goto ovhiwat; 12739578Ssam continue; 12747502Sroot } 12757502Sroot } 12769578Ssam /* 12779578Ssam * A bunch of normal characters have been found, 12789578Ssam * transfer them en masse to the output queue and 12799578Ssam * continue processing at the top of the loop. 12809578Ssam * If there are any further characters in this 12819578Ssam * <= OBUFSIZ chunk, the first should be a character 12829578Ssam * requiring special handling by ttyoutput. 12839578Ssam */ 12847502Sroot tp->t_rocount = 0; 12859578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12869578Ssam ce -= i; 12879578Ssam tp->t_col += ce; 12889578Ssam cp += ce, cc -= ce, tk_nout += ce; 12899578Ssam if (i > 0) { 12909578Ssam /* out of c-lists, wait a bit */ 12917502Sroot ttstart(tp); 12927502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12937502Sroot } 12949578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12957502Sroot goto ovhiwat; 12967502Sroot } 12977502Sroot } 12987502Sroot ttstart(tp); 12998520Sroot return (error); 13007502Sroot 13017502Sroot ovhiwat: 13029578Ssam s = spl5(); 13039578Ssam if (cc != 0) { 13049578Ssam uio->uio_iov->iov_base -= cc; 13059578Ssam uio->uio_iov->iov_len += cc; 13069578Ssam uio->uio_resid += cc; 13079578Ssam uio->uio_offset -= cc; 13089578Ssam } 13099578Ssam /* 13109578Ssam * This can only occur if FLUSHO 13119578Ssam * is also set in t_flags. 13129578Ssam */ 13137502Sroot if (tp->t_outq.c_cc <= hiwat) { 13149578Ssam splx(s); 13157502Sroot goto loop; 13167502Sroot } 13177502Sroot ttstart(tp); 13189578Ssam if (tp->t_state&TS_NBIO) { 13197822Sroot if (uio->uio_resid == cnt) 13208520Sroot return (EWOULDBLOCK); 13218520Sroot return (0); 13227502Sroot } 13237502Sroot tp->t_state |= TS_ASLEEP; 13247502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13259578Ssam splx(s); 13267502Sroot goto loop; 13277502Sroot } 13287502Sroot 13297502Sroot /* 13307502Sroot * Rubout one character from the rawq of tp 13317502Sroot * as cleanly as possible. 13327502Sroot */ 13337502Sroot ttyrub(c, tp) 13347625Ssam register c; 13357625Ssam register struct tty *tp; 13367502Sroot { 13377502Sroot register char *cp; 13387502Sroot register int savecol; 13397502Sroot int s; 13407502Sroot char *nextc(); 13417502Sroot 13429578Ssam if ((tp->t_flags&ECHO) == 0) 13437502Sroot return; 13449578Ssam tp->t_flags &= ~FLUSHO; 13457502Sroot c &= 0377; 13469578Ssam if (tp->t_flags&CRTBS) { 13477502Sroot if (tp->t_rocount == 0) { 13487502Sroot /* 13497502Sroot * Screwed by ttwrite; retype 13507502Sroot */ 13517502Sroot ttyretype(tp); 13527502Sroot return; 13537502Sroot } 13549578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13557502Sroot ttyrubo(tp, 2); 13569578Ssam else switch (partab[c&=0177]&0177) { 13577502Sroot 13587502Sroot case ORDINARY: 13597502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13607502Sroot ttyrubo(tp, 2); 13617502Sroot else 13627502Sroot ttyrubo(tp, 1); 13637502Sroot break; 13647502Sroot 13657502Sroot case VTAB: 13667502Sroot case BACKSPACE: 13677502Sroot case CONTROL: 13687502Sroot case RETURN: 13699578Ssam if (tp->t_flags&CTLECH) 13707502Sroot ttyrubo(tp, 2); 13717502Sroot break; 13727502Sroot 13737502Sroot case TAB: 13747502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13757502Sroot ttyretype(tp); 13767502Sroot return; 13777502Sroot } 13787502Sroot s = spl5(); 13797502Sroot savecol = tp->t_col; 13809578Ssam tp->t_state |= TS_CNTTB; 13819578Ssam tp->t_flags |= FLUSHO; 13827502Sroot tp->t_col = tp->t_rocol; 13839578Ssam cp = tp->t_rawq.c_cf; 13849578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13857502Sroot ttyecho(*cp, tp); 13869578Ssam tp->t_flags &= ~FLUSHO; 13879578Ssam tp->t_state &= ~TS_CNTTB; 13887502Sroot splx(s); 13897502Sroot /* 13907502Sroot * savecol will now be length of the tab 13917502Sroot */ 13927502Sroot savecol -= tp->t_col; 13937502Sroot tp->t_col += savecol; 13947502Sroot if (savecol > 8) 13957502Sroot savecol = 8; /* overflow screw */ 13967502Sroot while (--savecol >= 0) 13977502Sroot (void) ttyoutput('\b', tp); 13987502Sroot break; 13997502Sroot 14007502Sroot default: 14017502Sroot panic("ttyrub"); 14027502Sroot } 14039578Ssam } else if (tp->t_flags&PRTERA) { 14049578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14057502Sroot (void) ttyoutput('\\', tp); 14069578Ssam tp->t_state |= TS_ERASE; 14077502Sroot } 14087502Sroot ttyecho(c, tp); 14097502Sroot } else 14107502Sroot ttyecho(tp->t_erase, tp); 14117502Sroot tp->t_rocount--; 14127502Sroot } 14137502Sroot 14147502Sroot /* 14157502Sroot * Crt back over cnt chars perhaps 14167502Sroot * erasing them. 14177502Sroot */ 14187502Sroot ttyrubo(tp, cnt) 14197625Ssam register struct tty *tp; 14207625Ssam int cnt; 14217502Sroot { 14229578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14237502Sroot 14247502Sroot while (--cnt >= 0) 14259578Ssam ttyout(rubostring, tp); 14267502Sroot } 14277502Sroot 14287502Sroot /* 14297502Sroot * Reprint the rawq line. 14307502Sroot * We assume c_cc has already been checked. 14317502Sroot */ 14327502Sroot ttyretype(tp) 14337625Ssam register struct tty *tp; 14347502Sroot { 14357502Sroot register char *cp; 14367502Sroot char *nextc(); 14377502Sroot int s; 14387502Sroot 14399578Ssam if (tp->t_rprntc != 0377) 14409578Ssam ttyecho(tp->t_rprntc, tp); 14417502Sroot (void) ttyoutput('\n', tp); 14427502Sroot s = spl5(); 14437502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14447502Sroot ttyecho(*cp, tp); 14457502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14467502Sroot ttyecho(*cp, tp); 14479578Ssam tp->t_state &= ~TS_ERASE; 14487502Sroot splx(s); 14497502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14507502Sroot tp->t_rocol = 0; 14517502Sroot } 14527502Sroot 14537502Sroot /* 14547502Sroot * Echo a typed character to the terminal 14557502Sroot */ 14567502Sroot ttyecho(c, tp) 14577625Ssam register c; 14587625Ssam register struct tty *tp; 14597502Sroot { 14607502Sroot 14619578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14629578Ssam tp->t_flags &= ~FLUSHO; 14637502Sroot if ((tp->t_flags&ECHO) == 0) 14647502Sroot return; 14657502Sroot c &= 0377; 14667502Sroot if (tp->t_flags&RAW) { 14677502Sroot (void) ttyoutput(c, tp); 14687502Sroot return; 14697502Sroot } 14707502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14717502Sroot c = '\n'; 14729578Ssam if (tp->t_flags&CTLECH) { 14737502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14747502Sroot (void) ttyoutput('^', tp); 14757502Sroot c &= 0177; 14767502Sroot if (c == 0177) 14777502Sroot c = '?'; 14787502Sroot else if (tp->t_flags&LCASE) 14797502Sroot c += 'a' - 1; 14807502Sroot else 14817502Sroot c += 'A' - 1; 14827502Sroot } 14837502Sroot } 14847502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14857502Sroot c += 'a' - 'A'; 14869578Ssam (void) ttyoutput(c&0177, tp); 14877502Sroot } 14887502Sroot 14897502Sroot /* 14907502Sroot * Is c a break char for tp? 14917502Sroot */ 14927502Sroot ttbreakc(c, tp) 14937625Ssam register c; 14947625Ssam register struct tty *tp; 14957502Sroot { 14969578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14977502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14987502Sroot } 14997502Sroot 15007502Sroot /* 15017502Sroot * send string cp to tp 15027502Sroot */ 15037502Sroot ttyout(cp, tp) 15047625Ssam register char *cp; 15057625Ssam register struct tty *tp; 15067502Sroot { 15077502Sroot register char c; 15087502Sroot 15097502Sroot while (c = *cp++) 15107502Sroot (void) ttyoutput(c, tp); 15117502Sroot } 15127502Sroot 15137502Sroot ttwakeup(tp) 15147502Sroot struct tty *tp; 15157502Sroot { 15167502Sroot 15177502Sroot if (tp->t_rsel) { 15187502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15197502Sroot tp->t_state &= ~TS_RCOLL; 15207502Sroot tp->t_rsel = 0; 15217502Sroot } 1522*12752Ssam if (tp->t_state & TS_ASYNC) 1523*12752Ssam gsignal(tp->t_pgrp, SIGIO); 15247502Sroot wakeup((caddr_t)&tp->t_rawq); 15257502Sroot } 15267502Sroot 152710391Ssam #if !defined(vax) && !defined(sun) 15289578Ssam scanc(size, cp, table, mask) 15299578Ssam register int size; 15309578Ssam register char *cp, table[]; 15319578Ssam register int mask; 15327502Sroot { 15339578Ssam register int i = 0; 15347502Sroot 15359578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15369578Ssam i++; 15379578Ssam return (i); 15387502Sroot } 15399578Ssam #endif 1540