1*17545Skarels /* tty.c 6.12 84/12/20 */ 239Sbill 39760Ssam #include "../machine/reg.h" 49760Ssam 517095Sbloom #include "param.h" 617095Sbloom #include "systm.h" 717095Sbloom #include "dir.h" 817095Sbloom #include "user.h" 917095Sbloom #include "ioctl.h" 1017095Sbloom #include "tty.h" 1117095Sbloom #include "proc.h" 1217095Sbloom #include "inode.h" 1317095Sbloom #include "file.h" 1417095Sbloom #include "conf.h" 1517095Sbloom #include "buf.h" 1617095Sbloom #include "dk.h" 1717095Sbloom #include "uio.h" 1817095Sbloom #include "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 */ 11512752Ssam ttywflush(tp) 1165408Swnj register struct tty *tp; 11739Sbill { 11839Sbill 11912752Ssam ttywait(tp); 12012752Ssam ttyflush(tp, FREAD); 12112752Ssam } 12212752Ssam 12312752Ssam ttywait(tp) 12412752Ssam register struct tty *tp; 12512752Ssam { 126*17545Skarels register int s = spltty(); 12712752Ssam 12813809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 12913809Ssam tp->t_state&TS_CARR_ON && 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 */ 14012752Ssam ttyflush(tp, rw) 1417625Ssam register struct tty *tp; 14239Sbill { 143903Sbill register s; 144903Sbill 145*17545Skarels s = spltty(); 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 ; 1619578Ssam tp->t_rocount = 0; 162903Sbill tp->t_rocol = 0; 1639578Ssam tp->t_state &= ~TS_LOCAL; 164903Sbill } 165903Sbill splx(s); 16639Sbill } 16739Sbill 168903Sbill /* 169903Sbill * Send stop character on input overflow. 170903Sbill */ 171903Sbill ttyblock(tp) 1727625Ssam register struct tty *tp; 17339Sbill { 174903Sbill register x; 1759578Ssam 176903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 177903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 17812752Ssam ttyflush(tp, FREAD|FWRITE); 1795408Swnj tp->t_state &= ~TS_TBLOCK; 180903Sbill } 18115118Skarels /* 18215118Skarels * Block further input iff: 18315118Skarels * Current input > threshold AND input is available to user program 18415118Skarels */ 18516055Skarels if (x >= TTYHOG/2 && 18616055Skarels ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) { 18715118Skarels if (putc(tp->t_stopc, &tp->t_outq)==0) { 18815118Skarels tp->t_state |= TS_TBLOCK; 18915118Skarels ttstart(tp); 19015118Skarels } 191903Sbill } 19239Sbill } 19339Sbill 19439Sbill /* 195903Sbill * Restart typewriter output following a delay 196903Sbill * timeout. 197903Sbill * The name of the routine is passed to the timeout 198903Sbill * subroutine and it is called during a clock interrupt. 199121Sbill */ 200903Sbill ttrstrt(tp) 2017625Ssam register struct tty *tp; 202121Sbill { 203121Sbill 2049578Ssam if (tp == 0) 2059578Ssam panic("ttrstrt"); 2065408Swnj tp->t_state &= ~TS_TIMEOUT; 207903Sbill ttstart(tp); 208121Sbill } 209121Sbill 210121Sbill /* 211903Sbill * Start output on the typewriter. It is used from the top half 212903Sbill * after some characters have been put on the output queue, 213903Sbill * from the interrupt routine to transmit the next 214903Sbill * character, and after a timeout has finished. 21539Sbill */ 216903Sbill ttstart(tp) 2177625Ssam register struct tty *tp; 21839Sbill { 219903Sbill register s; 22039Sbill 221*17545Skarels s = spltty(); 2229578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2235622Swnj tp->t_oproc) /* kludge for pty */ 224903Sbill (*tp->t_oproc)(tp); 225903Sbill splx(s); 22639Sbill } 22739Sbill 22839Sbill /* 229903Sbill * Common code for tty ioctls. 23039Sbill */ 2311780Sbill /*ARGSUSED*/ 2327625Ssam ttioctl(tp, com, data, flag) 2337625Ssam register struct tty *tp; 2347625Ssam caddr_t data; 23539Sbill { 2368520Sroot int dev = tp->t_dev; 23739Sbill extern int nldisp; 2388556Sroot int s; 23912752Ssam register int newflags; 24039Sbill 241903Sbill /* 242903Sbill * If the ioctl involves modification, 243*17545Skarels * hang if in the background. 244903Sbill */ 2457625Ssam switch (com) { 24639Sbill 247915Sbill case TIOCSETD: 248915Sbill case TIOCSETP: 249915Sbill case TIOCSETN: 250903Sbill case TIOCFLUSH: 251903Sbill case TIOCSETC: 252903Sbill case TIOCSLTC: 253903Sbill case TIOCSPGRP: 254903Sbill case TIOCLBIS: 255903Sbill case TIOCLBIC: 256903Sbill case TIOCLSET: 2579325Ssam case TIOCSTI: 25815078Skarels #define bit(a) (1<<(a-1)) 259903Sbill while (tp->t_line == NTTYDISC && 260903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 261903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 26215078Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 26315078Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU))) { 264903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 265903Sbill sleep((caddr_t)&lbolt, TTOPRI); 266903Sbill } 267903Sbill break; 268903Sbill } 26915078Skarels #undef bit 270903Sbill 2719578Ssam /* 2729578Ssam * Process the ioctl. 2739578Ssam */ 2747625Ssam switch (com) { 275903Sbill 2768556Sroot /* get discipline number */ 27739Sbill case TIOCGETD: 2787625Ssam *(int *)data = tp->t_line; 27939Sbill break; 28039Sbill 2818556Sroot /* set line discipline */ 2827625Ssam case TIOCSETD: { 2837625Ssam register int t = *(int *)data; 2849578Ssam int error = 0; 2857625Ssam 28615078Skarels if ((unsigned) t >= nldisp) 28710851Ssam return (ENXIO); 288*17545Skarels s = spltty(); 28939Sbill if (tp->t_line) 29039Sbill (*linesw[tp->t_line].l_close)(tp); 29139Sbill if (t) 2928556Sroot error = (*linesw[t].l_open)(dev, tp); 2938556Sroot splx(s); 29410851Ssam if (error) { 295*17545Skarels s = spltty(); 29610851Ssam if (tp->t_line) 29710851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29810851Ssam splx(s); 2998556Sroot return (error); 30010851Ssam } 3018556Sroot tp->t_line = t; 30239Sbill break; 3037625Ssam } 30439Sbill 3058556Sroot /* prevent more opens on channel */ 3065614Swnj case TIOCEXCL: 3075614Swnj tp->t_state |= TS_XCLUDE; 3085614Swnj break; 3095614Swnj 3105614Swnj case TIOCNXCL: 3115614Swnj tp->t_state &= ~TS_XCLUDE; 3125614Swnj break; 3135614Swnj 3148556Sroot /* hang up line on last close */ 31539Sbill case TIOCHPCL: 3165408Swnj tp->t_state |= TS_HUPCLS; 31739Sbill break; 31839Sbill 3193942Sbugs case TIOCFLUSH: { 3207625Ssam register int flags = *(int *)data; 3217625Ssam 3227625Ssam if (flags == 0) 3233942Sbugs flags = FREAD|FWRITE; 3247625Ssam else 3257625Ssam flags &= FREAD|FWRITE; 32612752Ssam ttyflush(tp, flags); 32739Sbill break; 3283944Sbugs } 32939Sbill 3308556Sroot /* return number of characters immediately available */ 3317625Ssam case FIONREAD: 3327625Ssam *(off_t *)data = ttnread(tp); 333174Sbill break; 334174Sbill 33513077Ssam case TIOCOUTQ: 33613077Ssam *(int *)data = tp->t_outq.c_cc; 33713077Ssam break; 33813077Ssam 3398589Sroot case TIOCSTOP: 340*17545Skarels s = spltty(); 3419578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3425573Swnj tp->t_state |= TS_TTSTOP; 3435573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3445573Swnj } 3457625Ssam splx(s); 3465573Swnj break; 3475573Swnj 3488589Sroot case TIOCSTART: 349*17545Skarels s = spltty(); 3509578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3515573Swnj tp->t_state &= ~TS_TTSTOP; 3529578Ssam tp->t_flags &= ~FLUSHO; 3535573Swnj ttstart(tp); 3545573Swnj } 3557625Ssam splx(s); 3565573Swnj break; 3575573Swnj 3589325Ssam /* 3599325Ssam * Simulate typing of a character at the terminal. 3609325Ssam */ 3619325Ssam case TIOCSTI: 36217183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36317183Smckusick return (EPERM); 3649325Ssam if (u.u_uid && u.u_ttyp != tp) 3659325Ssam return (EACCES); 3669578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3679325Ssam break; 3689325Ssam 36912752Ssam case TIOCSETP: 37012752Ssam case TIOCSETN: { 37112752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37212752Ssam 37312752Ssam tp->t_erase = sg->sg_erase; 37412752Ssam tp->t_kill = sg->sg_kill; 37512752Ssam tp->t_ispeed = sg->sg_ispeed; 37612752Ssam tp->t_ospeed = sg->sg_ospeed; 37712752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 378*17545Skarels s = spltty(); 37912752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38012752Ssam ttywait(tp); 38112752Ssam ttyflush(tp, FREAD); 38212752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38312752Ssam if (newflags&CBREAK) { 38412752Ssam struct clist tq; 38512752Ssam 38612752Ssam catq(&tp->t_rawq, &tp->t_canq); 38712752Ssam tq = tp->t_rawq; 38812752Ssam tp->t_rawq = tp->t_canq; 38912752Ssam tp->t_canq = tq; 39012752Ssam } else { 39112752Ssam tp->t_flags |= PENDIN; 39213801Ssam newflags |= PENDIN; 39312752Ssam ttwakeup(tp); 39412752Ssam } 39512752Ssam } 39612752Ssam tp->t_flags = newflags; 39712752Ssam if (tp->t_flags&RAW) { 39812752Ssam tp->t_state &= ~TS_TTSTOP; 39912752Ssam ttstart(tp); 40012752Ssam } 40112752Ssam splx(s); 40212752Ssam break; 40312752Ssam } 40412752Ssam 40512752Ssam /* send current parameters to user */ 40612752Ssam case TIOCGETP: { 40712752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40812752Ssam 40912752Ssam sg->sg_ispeed = tp->t_ispeed; 41012752Ssam sg->sg_ospeed = tp->t_ospeed; 41112752Ssam sg->sg_erase = tp->t_erase; 41212752Ssam sg->sg_kill = tp->t_kill; 41312752Ssam sg->sg_flags = tp->t_flags; 41412752Ssam break; 41512752Ssam } 41612752Ssam 41712752Ssam case FIONBIO: 41812752Ssam if (*(int *)data) 41912752Ssam tp->t_state |= TS_NBIO; 42012752Ssam else 42112752Ssam tp->t_state &= ~TS_NBIO; 42212752Ssam break; 42312752Ssam 42412752Ssam case FIOASYNC: 42512752Ssam if (*(int *)data) 42612752Ssam tp->t_state |= TS_ASYNC; 42712752Ssam else 42812752Ssam tp->t_state &= ~TS_ASYNC; 42912752Ssam break; 43012752Ssam 43113077Ssam case TIOCGETC: 43213077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43313077Ssam break; 43413077Ssam 43513077Ssam case TIOCSETC: 43613077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43713077Ssam break; 43813077Ssam 43912752Ssam /* set/get local special characters */ 44012752Ssam case TIOCSLTC: 44112752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44212752Ssam break; 44312752Ssam 44412752Ssam case TIOCGLTC: 44512752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44612752Ssam break; 44712752Ssam 44812752Ssam /* 44912752Ssam * Modify local mode word. 45012752Ssam */ 45112752Ssam case TIOCLBIS: 45212752Ssam tp->t_flags |= *(int *)data << 16; 45312752Ssam break; 45412752Ssam 45512752Ssam case TIOCLBIC: 45612752Ssam tp->t_flags &= ~(*(int *)data << 16); 45712752Ssam break; 45812752Ssam 45912752Ssam case TIOCLSET: 46012752Ssam tp->t_flags &= 0xffff; 46112752Ssam tp->t_flags |= *(int *)data << 16; 46212752Ssam break; 46312752Ssam 46412752Ssam case TIOCLGET: 46515720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46612752Ssam break; 46712752Ssam 468*17545Skarels /* 469*17545Skarels * Allow SPGRP only if tty is ours and is open for reading. 470*17545Skarels */ 47112752Ssam case TIOCSPGRP: 472*17545Skarels { 473*17545Skarels struct proc *p; 474*17545Skarels int pgrp = *(int *)data; 475*17545Skarels 476*17545Skarels if (u.u_uid && (flag & FREAD) == 0) 477*17545Skarels return (EPERM); 478*17545Skarels if (u.u_uid && u.u_ttyp != tp) 479*17545Skarels return (EACCES); 480*17545Skarels tp->t_pgrp = pgrp; 48112752Ssam break; 482*17545Skarels } 48312752Ssam 48412752Ssam case TIOCGPGRP: 48512752Ssam *(int *)data = tp->t_pgrp; 48612752Ssam break; 48712752Ssam 48839Sbill default: 4898556Sroot return (-1); 49039Sbill } 4918556Sroot return (0); 49239Sbill } 4934484Swnj 4944484Swnj ttnread(tp) 4954484Swnj struct tty *tp; 4964484Swnj { 4974484Swnj int nread = 0; 4984484Swnj 4999578Ssam if (tp->t_flags & PENDIN) 5004484Swnj ttypend(tp); 5014484Swnj nread = tp->t_canq.c_cc; 5024484Swnj if (tp->t_flags & (RAW|CBREAK)) 5034484Swnj nread += tp->t_rawq.c_cc; 5044484Swnj return (nread); 5054484Swnj } 5064484Swnj 5075408Swnj ttselect(dev, rw) 5084484Swnj dev_t dev; 5095408Swnj int rw; 5104484Swnj { 5114484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5124484Swnj int nread; 513*17545Skarels int s = spltty(); 5144484Swnj 5155408Swnj switch (rw) { 5164484Swnj 5174484Swnj case FREAD: 5184484Swnj nread = ttnread(tp); 5194484Swnj if (nread > 0) 5205408Swnj goto win; 5214938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5225408Swnj tp->t_state |= TS_RCOLL; 5234484Swnj else 5244484Swnj tp->t_rsel = u.u_procp; 5255408Swnj break; 5264484Swnj 5275408Swnj case FWRITE: 5285408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5295408Swnj goto win; 5305408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5315408Swnj tp->t_state |= TS_WCOLL; 5325408Swnj else 5335408Swnj tp->t_wsel = u.u_procp; 5345408Swnj break; 5354484Swnj } 5365408Swnj splx(s); 5375408Swnj return (0); 5385408Swnj win: 5395408Swnj splx(s); 5405408Swnj return (1); 5414484Swnj } 5427436Skre 5437502Sroot /* 5449578Ssam * Establish a process group for distribution of 5457502Sroot * quits and interrupts from the tty. 5467502Sroot */ 5477502Sroot ttyopen(dev, tp) 5487625Ssam dev_t dev; 5497625Ssam register struct tty *tp; 5507502Sroot { 5517502Sroot register struct proc *pp; 5527502Sroot 5537502Sroot pp = u.u_procp; 5547502Sroot tp->t_dev = dev; 5557625Ssam if (pp->p_pgrp == 0) { 5567502Sroot u.u_ttyp = tp; 5577502Sroot u.u_ttyd = dev; 5587502Sroot if (tp->t_pgrp == 0) 5597502Sroot tp->t_pgrp = pp->p_pid; 5607502Sroot pp->p_pgrp = tp->t_pgrp; 5617502Sroot } 5627502Sroot tp->t_state &= ~TS_WOPEN; 563*17545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 564*17545Skarels tp->t_state |= TS_ISOPEN; 565*17545Skarels if (tp->t_line != NTTYDISC) 566*17545Skarels ttywflush(tp); 567*17545Skarels } 5688556Sroot return (0); 5697502Sroot } 5707502Sroot 5717502Sroot /* 5727502Sroot * clean tp on last close 5737502Sroot */ 5747502Sroot ttyclose(tp) 5757625Ssam register struct tty *tp; 5767502Sroot { 5777502Sroot 5787502Sroot if (tp->t_line) { 57912752Ssam ttywflush(tp); 5807502Sroot tp->t_line = 0; 5817502Sroot return; 5827502Sroot } 5837502Sroot tp->t_pgrp = 0; 58412752Ssam ttywflush(tp); 5857502Sroot tp->t_state = 0; 5867502Sroot } 5877502Sroot 5887502Sroot /* 5897502Sroot * reinput pending characters after state switch 590*17545Skarels * call at spltty(). 5917502Sroot */ 5927502Sroot ttypend(tp) 5937625Ssam register struct tty *tp; 5947502Sroot { 5957502Sroot struct clist tq; 5967502Sroot register c; 5977502Sroot 5989578Ssam tp->t_flags &= ~PENDIN; 5999578Ssam tp->t_state |= TS_TYPEN; 6007502Sroot tq = tp->t_rawq; 6017502Sroot tp->t_rawq.c_cc = 0; 6027502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6037502Sroot while ((c = getc(&tq)) >= 0) 6047502Sroot ttyinput(c, tp); 6059578Ssam tp->t_state &= ~TS_TYPEN; 6067502Sroot } 6077502Sroot 6087502Sroot /* 6099578Ssam * Place a character on raw TTY input queue, 6109578Ssam * putting in delimiters and waking up top 6119578Ssam * half as needed. Also echo if required. 6129578Ssam * The arguments are the character and the 6139578Ssam * appropriate tty structure. 6147502Sroot */ 6157502Sroot ttyinput(c, tp) 6167625Ssam register c; 6177625Ssam register struct tty *tp; 6187502Sroot { 6199578Ssam register int t_flags = tp->t_flags; 6207502Sroot int i; 6217502Sroot 6229578Ssam /* 6239578Ssam * If input is pending take it first. 6249578Ssam */ 6259578Ssam if (t_flags&PENDIN) 6267502Sroot ttypend(tp); 6277502Sroot tk_nin++; 6287502Sroot c &= 0377; 6299578Ssam 6309578Ssam /* 6319578Ssam * In tandem mode, check high water mark. 6329578Ssam */ 6337502Sroot if (t_flags&TANDEM) 6347502Sroot ttyblock(tp); 6359578Ssam 6369578Ssam if (t_flags&RAW) { 6379578Ssam /* 6389578Ssam * Raw mode, just put character 6399578Ssam * in input q w/o interpretation. 6409578Ssam */ 6419578Ssam if (tp->t_rawq.c_cc > TTYHOG) 64212752Ssam ttyflush(tp, FREAD|FWRITE); 6439578Ssam else { 6449578Ssam if (putc(c, &tp->t_rawq) >= 0) 6459578Ssam ttwakeup(tp); 6469578Ssam ttyecho(c, tp); 6477502Sroot } 6489578Ssam goto endcase; 6499578Ssam } 6509578Ssam 6519578Ssam /* 6529578Ssam * Ignore any high bit added during 6539578Ssam * previous ttyinput processing. 6549578Ssam */ 6559578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6569578Ssam c &= 0177; 6579578Ssam /* 6589578Ssam * Check for literal nexting very first 6599578Ssam */ 6609578Ssam if (tp->t_state&TS_LNCH) { 6619578Ssam c |= 0200; 6629578Ssam tp->t_state &= ~TS_LNCH; 6639578Ssam } 6649578Ssam 6659578Ssam /* 6669578Ssam * Scan for special characters. This code 6679578Ssam * is really just a big case statement with 6689578Ssam * non-constant cases. The bottom of the 6699578Ssam * case statement is labeled ``endcase'', so goto 6709578Ssam * it after a case match, or similar. 6719578Ssam */ 6729578Ssam if (tp->t_line == NTTYDISC) { 6739578Ssam if (c == tp->t_lnextc) { 6747502Sroot if (tp->t_flags&ECHO) 6757502Sroot ttyout("^\b", tp); 6769578Ssam tp->t_state |= TS_LNCH; 6779578Ssam goto endcase; 6789578Ssam } 6799578Ssam if (c == tp->t_flushc) { 6809578Ssam if (tp->t_flags&FLUSHO) 6819578Ssam tp->t_flags &= ~FLUSHO; 6827502Sroot else { 68312752Ssam ttyflush(tp, FWRITE); 6847502Sroot ttyecho(c, tp); 6859578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6867502Sroot ttyretype(tp); 6879578Ssam tp->t_flags |= FLUSHO; 6887502Sroot } 6899578Ssam goto startoutput; 6909578Ssam } 6919578Ssam if (c == tp->t_suspc) { 6929578Ssam if ((tp->t_flags&NOFLSH) == 0) 69312752Ssam ttyflush(tp, FREAD); 6949578Ssam ttyecho(c, tp); 6959578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6969578Ssam goto endcase; 6979578Ssam } 6989578Ssam } 6999578Ssam 7009578Ssam /* 7019578Ssam * Handle start/stop characters. 7029578Ssam */ 7039578Ssam if (c == tp->t_stopc) { 7049578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7059578Ssam tp->t_state |= TS_TTSTOP; 7069578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7077502Sroot return; 7089578Ssam } 7099578Ssam if (c != tp->t_startc) 7109578Ssam return; 7119578Ssam goto endcase; 7129578Ssam } 7139578Ssam if (c == tp->t_startc) 7149578Ssam goto restartoutput; 7159578Ssam 7169578Ssam /* 7179578Ssam * Look for interrupt/quit chars. 7189578Ssam */ 7199578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7209578Ssam if ((tp->t_flags&NOFLSH) == 0) 72112752Ssam ttyflush(tp, FREAD|FWRITE); 7229578Ssam ttyecho(c, tp); 7239578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7249578Ssam goto endcase; 7259578Ssam } 7269578Ssam 7279578Ssam /* 7289578Ssam * Cbreak mode, don't process line editing 7299578Ssam * characters; check high water mark for wakeup. 7309578Ssam */ 7319578Ssam if (t_flags&CBREAK) { 7329578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7337502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7347502Sroot tp->t_line == NTTYDISC) 7357502Sroot (void) ttyoutput(CTRL(g), tp); 7367502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7377502Sroot ttwakeup(tp); 7387502Sroot ttyecho(c, tp); 7397502Sroot } 7409578Ssam goto endcase; 7419578Ssam } 7429578Ssam 7439578Ssam /* 7449578Ssam * From here on down cooked mode character 7459578Ssam * processing takes place. 7469578Ssam */ 7479578Ssam if ((tp->t_state&TS_QUOT) && 7489578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7499578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7509578Ssam c |= 0200; 7519578Ssam } 7529578Ssam if (c == tp->t_erase) { 7539578Ssam if (tp->t_rawq.c_cc) 7549578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7559578Ssam goto endcase; 7569578Ssam } 7579578Ssam if (c == tp->t_kill) { 7589578Ssam if (tp->t_flags&CRTKIL && 7599578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7609578Ssam while (tp->t_rawq.c_cc) 7619578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7629578Ssam } else { 7639578Ssam ttyecho(c, tp); 7649578Ssam ttyecho('\n', tp); 7659578Ssam while (getc(&tp->t_rawq) > 0) 7669578Ssam ; 7679578Ssam tp->t_rocount = 0; 7689578Ssam } 7699578Ssam tp->t_state &= ~TS_LOCAL; 7709578Ssam goto endcase; 7719578Ssam } 7729578Ssam 7739578Ssam /* 7749578Ssam * New line discipline, 7759578Ssam * check word erase/reprint line. 7769578Ssam */ 7779578Ssam if (tp->t_line == NTTYDISC) { 7789578Ssam if (c == tp->t_werasc) { 7799578Ssam if (tp->t_rawq.c_cc == 0) 7809578Ssam goto endcase; 7819578Ssam do { 7829578Ssam c = unputc(&tp->t_rawq); 7839578Ssam if (c != ' ' && c != '\t') 7849578Ssam goto erasenb; 7859578Ssam ttyrub(c, tp); 7869578Ssam } while (tp->t_rawq.c_cc); 7879578Ssam goto endcase; 7889578Ssam erasenb: 7899578Ssam do { 7909578Ssam ttyrub(c, tp); 7919578Ssam if (tp->t_rawq.c_cc == 0) 7929578Ssam goto endcase; 7939578Ssam c = unputc(&tp->t_rawq); 7949578Ssam } while (c != ' ' && c != '\t'); 7959578Ssam (void) putc(c, &tp->t_rawq); 7969578Ssam goto endcase; 7979578Ssam } 7989578Ssam if (c == tp->t_rprntc) { 7999578Ssam ttyretype(tp); 8009578Ssam goto endcase; 8019578Ssam } 8029578Ssam } 8039578Ssam 8049578Ssam /* 8059578Ssam * Check for input buffer overflow 8069578Ssam */ 80710391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 80810391Ssam if (tp->t_line == NTTYDISC) 80910391Ssam (void) ttyoutput(CTRL(g), tp); 8109578Ssam goto endcase; 81110391Ssam } 8129578Ssam 8139578Ssam /* 8149578Ssam * Put data char in q for user and 8159578Ssam * wakeup on seeing a line delimiter. 8169578Ssam */ 8179578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8189578Ssam if (ttbreakc(c, tp)) { 8199578Ssam tp->t_rocount = 0; 8209578Ssam catq(&tp->t_rawq, &tp->t_canq); 8217502Sroot ttwakeup(tp); 8229578Ssam } else if (tp->t_rocount++ == 0) 8239578Ssam tp->t_rocol = tp->t_col; 8249578Ssam tp->t_state &= ~TS_QUOT; 8259578Ssam if (c == '\\') 8269578Ssam tp->t_state |= TS_QUOT; 8279578Ssam if (tp->t_state&TS_ERASE) { 8289578Ssam tp->t_state &= ~TS_ERASE; 8299578Ssam (void) ttyoutput('/', tp); 8309578Ssam } 8319578Ssam i = tp->t_col; 8327502Sroot ttyecho(c, tp); 8339578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8349578Ssam i = MIN(2, tp->t_col - i); 8359578Ssam while (i > 0) { 8369578Ssam (void) ttyoutput('\b', tp); 8379578Ssam i--; 8389578Ssam } 8399578Ssam } 8407502Sroot } 8419578Ssam 8429578Ssam endcase: 8439578Ssam /* 8449578Ssam * If DEC-style start/stop is enabled don't restart 8459578Ssam * output until seeing the start character. 8469578Ssam */ 8479578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8489578Ssam tp->t_startc != tp->t_stopc) 8497502Sroot return; 8509578Ssam 8519578Ssam restartoutput: 8527502Sroot tp->t_state &= ~TS_TTSTOP; 8539578Ssam tp->t_flags &= ~FLUSHO; 8549578Ssam 8559578Ssam startoutput: 8567502Sroot ttstart(tp); 8577502Sroot } 8587502Sroot 8597502Sroot /* 8609578Ssam * Put character on TTY output queue, adding delays, 8617502Sroot * expanding tabs, and handling the CR/NL bit. 8629578Ssam * This is called both from the top half for output, 8639578Ssam * and from interrupt level for echoing. 8647502Sroot * The arguments are the character and the tty structure. 8657502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8667502Sroot * Must be recursive. 8677502Sroot */ 8687502Sroot ttyoutput(c, tp) 8697502Sroot register c; 8707502Sroot register struct tty *tp; 8717502Sroot { 8727502Sroot register char *colp; 8737502Sroot register ctype; 8747502Sroot 8759578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8769578Ssam if (tp->t_flags&FLUSHO) 8777502Sroot return (-1); 8787502Sroot if (putc(c, &tp->t_outq)) 8797625Ssam return (c); 8807502Sroot tk_nout++; 8817502Sroot return (-1); 8827502Sroot } 8839578Ssam 8847502Sroot /* 8859578Ssam * Ignore EOT in normal mode to avoid 8869578Ssam * hanging up certain terminals. 8877502Sroot */ 8887502Sroot c &= 0177; 8899578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8907502Sroot return (-1); 8917502Sroot /* 8927502Sroot * Turn tabs to spaces as required 8937502Sroot */ 8949578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8957502Sroot register int s; 8967502Sroot 8977502Sroot c = 8 - (tp->t_col&7); 8989578Ssam if ((tp->t_flags&FLUSHO) == 0) { 899*17545Skarels s = spltty(); /* don't interrupt tabs */ 9007502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9017502Sroot tk_nout += c; 9027502Sroot splx(s); 9037502Sroot } 9047502Sroot tp->t_col += c; 9057502Sroot return (c ? -1 : '\t'); 9067502Sroot } 9077502Sroot tk_nout++; 9087502Sroot /* 9097502Sroot * for upper-case-only terminals, 9107502Sroot * generate escapes. 9117502Sroot */ 9127502Sroot if (tp->t_flags&LCASE) { 9137502Sroot colp = "({)}!|^~'`"; 9147625Ssam while (*colp++) 9157625Ssam if (c == *colp++) { 9167502Sroot if (ttyoutput('\\', tp) >= 0) 9177502Sroot return (c); 9187502Sroot c = colp[-2]; 9197502Sroot break; 9207502Sroot } 9219578Ssam if ('A' <= c && c <= 'Z') { 9227502Sroot if (ttyoutput('\\', tp) >= 0) 9237502Sroot return (c); 9249578Ssam } else if ('a' <= c && c <= 'z') 9257502Sroot c += 'A' - 'a'; 9267502Sroot } 9279578Ssam 9287502Sroot /* 9297502Sroot * turn <nl> to <cr><lf> if desired. 9307502Sroot */ 9319578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9327502Sroot if (ttyoutput('\r', tp) >= 0) 9337502Sroot return (c); 9349578Ssam if (c == '~' && tp->t_flags&TILDE) 9357502Sroot c = '`'; 9369578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9377502Sroot return (c); 9387502Sroot /* 9397502Sroot * Calculate delays. 9407502Sroot * The numbers here represent clock ticks 9417502Sroot * and are not necessarily optimal for all terminals. 9427502Sroot * The delays are indicated by characters above 0200. 9437502Sroot * In raw mode there are no delays and the 9447502Sroot * transmission path is 8 bits wide. 9459578Ssam * 9469578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9477502Sroot */ 9487502Sroot colp = &tp->t_col; 9497502Sroot ctype = partab[c]; 9507502Sroot c = 0; 9517502Sroot switch (ctype&077) { 9527502Sroot 9537502Sroot case ORDINARY: 9547502Sroot (*colp)++; 9557502Sroot 9567502Sroot case CONTROL: 9577502Sroot break; 9587502Sroot 9597502Sroot case BACKSPACE: 9607502Sroot if (*colp) 9617502Sroot (*colp)--; 9627502Sroot break; 9637502Sroot 96413821Ssam /* 96513821Ssam * This macro is close enough to the correct thing; 96613821Ssam * it should be replaced by real user settable delays 96713821Ssam * in any event... 96813821Ssam */ 96913821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9707502Sroot case NEWLINE: 9717502Sroot ctype = (tp->t_flags >> 8) & 03; 9727625Ssam if (ctype == 1) { /* tty 37 */ 97312752Ssam if (*colp > 0) 97413863Ssam c = max((((unsigned)*colp) >> 4) + 3, 97513863Ssam (unsigned)6); 9769578Ssam } else if (ctype == 2) /* vt05 */ 97713821Ssam c = mstohz(100); 9787502Sroot *colp = 0; 9797502Sroot break; 9807502Sroot 9817502Sroot case TAB: 9827502Sroot ctype = (tp->t_flags >> 10) & 03; 9837625Ssam if (ctype == 1) { /* tty 37 */ 9847502Sroot c = 1 - (*colp | ~07); 9857625Ssam if (c < 5) 9867502Sroot c = 0; 9877502Sroot } 9887502Sroot *colp |= 07; 9897502Sroot (*colp)++; 9907502Sroot break; 9917502Sroot 9927502Sroot case VTAB: 9939578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9947502Sroot c = 0177; 9957502Sroot break; 9967502Sroot 9977502Sroot case RETURN: 9987502Sroot ctype = (tp->t_flags >> 12) & 03; 9999578Ssam if (ctype == 1) /* tn 300 */ 100013821Ssam c = mstohz(83); 10019578Ssam else if (ctype == 2) /* ti 700 */ 100213821Ssam c = mstohz(166); 10039578Ssam else if (ctype == 3) { /* concept 100 */ 10047502Sroot int i; 10059578Ssam 10067502Sroot if ((i = *colp) >= 0) 10079578Ssam for (; i < 9; i++) 10087502Sroot (void) putc(0177, &tp->t_outq); 10097502Sroot } 10107502Sroot *colp = 0; 10117502Sroot } 10129578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10137502Sroot (void) putc(c|0200, &tp->t_outq); 10147502Sroot return (-1); 10157502Sroot } 101613821Ssam #undef mstohz 10177502Sroot 10187502Sroot /* 10197502Sroot * Called from device's read routine after it has 10207502Sroot * calculated the tty-structure given as argument. 10217502Sroot */ 10227722Swnj ttread(tp, uio) 10237625Ssam register struct tty *tp; 10247722Swnj struct uio *uio; 10257502Sroot { 10267502Sroot register struct clist *qp; 10279578Ssam register c, t_flags; 10289859Ssam int s, first, error = 0; 10297502Sroot 10307502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10318520Sroot return (EIO); 10327502Sroot loop: 10339578Ssam /* 10349578Ssam * Take any pending input first. 10359578Ssam */ 1036*17545Skarels s = spltty(); 10379578Ssam if (tp->t_flags&PENDIN) 10387502Sroot ttypend(tp); 10399859Ssam splx(s); 10409578Ssam 10419578Ssam /* 10429578Ssam * Hang process if it's in the background. 10439578Ssam */ 104415141Skarels #define bit(a) (1<<(a-1)) 10457502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 104615141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 104715141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10487502Sroot /* 10497502Sroot (u.u_procp->p_flag&SDETACH) || 10507502Sroot */ 10517502Sroot u.u_procp->p_flag&SVFORK) 10528520Sroot return (EIO); 10537502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10547502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10557502Sroot } 10569578Ssam t_flags = tp->t_flags; 105715141Skarels #undef bit 10589578Ssam 10599578Ssam /* 10609578Ssam * In raw mode take characters directly from the 10619578Ssam * raw queue w/o processing. Interlock against 10629578Ssam * device interrupts when interrogating rawq. 10639578Ssam */ 10649578Ssam if (t_flags&RAW) { 1065*17545Skarels s = spltty(); 10667502Sroot if (tp->t_rawq.c_cc <= 0) { 10679578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10687502Sroot (tp->t_state&TS_NBIO)) { 10699859Ssam splx(s); 107015094Skarels return (EWOULDBLOCK); 10717502Sroot } 10727502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10739859Ssam splx(s); 10747502Sroot goto loop; 10757502Sroot } 10769859Ssam splx(s); 107714938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 107814938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10799859Ssam goto checktandem; 10809578Ssam } 10819578Ssam 10829578Ssam /* 10839578Ssam * In cbreak mode use the rawq, otherwise 10849578Ssam * take characters from the canonicalized q. 10859578Ssam */ 10869578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10879578Ssam 10889578Ssam /* 10899578Ssam * No input, sleep on rawq awaiting hardware 10909578Ssam * receipt and notification. 10919578Ssam */ 1092*17545Skarels s = spltty(); 10939578Ssam if (qp->c_cc <= 0) { 10949578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10959578Ssam (tp->t_state&TS_NBIO)) { 10969859Ssam splx(s); 10979578Ssam return (EWOULDBLOCK); 10987502Sroot } 10999578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11009859Ssam splx(s); 11019578Ssam goto loop; 11029578Ssam } 11039859Ssam splx(s); 11049578Ssam 11059578Ssam /* 11069578Ssam * Input present, perform input mapping 11079578Ssam * and processing (we're not in raw mode). 11089578Ssam */ 11099578Ssam first = 1; 11109578Ssam while ((c = getc(qp)) >= 0) { 11119578Ssam if (t_flags&CRMOD && c == '\r') 11129578Ssam c = '\n'; 11139578Ssam /* 11149578Ssam * Hack lower case simulation on 11159578Ssam * upper case only terminals. 11169578Ssam */ 11179578Ssam if (t_flags&LCASE && c <= 0177) 11189578Ssam if (tp->t_state&TS_BKSL) { 11199578Ssam if (maptab[c]) 11209578Ssam c = maptab[c]; 11219578Ssam tp->t_state &= ~TS_BKSL; 11229578Ssam } else if (c >= 'A' && c <= 'Z') 11239578Ssam c += 'a' - 'A'; 11249578Ssam else if (c == '\\') { 11259578Ssam tp->t_state |= TS_BKSL; 11269578Ssam continue; 11277502Sroot } 11289578Ssam /* 11299578Ssam * Check for delayed suspend character. 11309578Ssam */ 11319578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11329578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11339578Ssam if (first) { 11349578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11359578Ssam goto loop; 11369578Ssam } 11379578Ssam break; 11387502Sroot } 11399578Ssam /* 11409578Ssam * Interpret EOF only in cooked mode. 11419578Ssam */ 11429578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11439578Ssam break; 11449578Ssam /* 11459578Ssam * Give user character. 11469578Ssam */ 114714938Smckusick error = ureadc(c & 0177, uio); 11489578Ssam if (error) 11499578Ssam break; 115014938Smckusick if (uio->uio_resid == 0) 11519578Ssam break; 11529578Ssam /* 11539578Ssam * In cooked mode check for a "break character" 11549578Ssam * marking the end of a "line of input". 11559578Ssam */ 11569578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11579578Ssam break; 11589578Ssam first = 0; 11597502Sroot } 11609578Ssam tp->t_state &= ~TS_BKSL; 11619578Ssam 11629859Ssam checktandem: 11639578Ssam /* 11649578Ssam * Look to unblock output now that (presumably) 11659578Ssam * the input queue has gone down. 11669578Ssam */ 11679859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11689578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11697502Sroot tp->t_state &= ~TS_TBLOCK; 11707502Sroot ttstart(tp); 11717502Sroot } 11728520Sroot return (error); 11737502Sroot } 11747502Sroot 11757502Sroot /* 11767502Sroot * Called from the device's write routine after it has 11777502Sroot * calculated the tty-structure given as argument. 11787502Sroot */ 11797822Sroot ttwrite(tp, uio) 11807625Ssam register struct tty *tp; 11819578Ssam register struct uio *uio; 11827502Sroot { 11837502Sroot register char *cp; 11849578Ssam register int cc, ce, c; 11859578Ssam int i, hiwat, cnt, error, s; 11867502Sroot char obuf[OBUFSIZ]; 11877502Sroot 11889578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11898520Sroot return (EIO); 11909578Ssam hiwat = TTHIWAT(tp); 11919578Ssam cnt = uio->uio_resid; 11929578Ssam error = 0; 11937502Sroot loop: 11949578Ssam /* 11959578Ssam * Hang the process if it's in the background. 11969578Ssam */ 119715141Skarels #define bit(a) (1<<(a-1)) 11987502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11999578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 120015141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 120115141Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU)) 12027502Sroot /* 12037502Sroot && 12047502Sroot (u.u_procp->p_flag&SDETACH)==0) { 12057502Sroot */ 12067502Sroot ) { 12077502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12087502Sroot sleep((caddr_t)&lbolt, TTIPRI); 12097502Sroot } 121015141Skarels #undef bit 12119578Ssam 12129578Ssam /* 12139578Ssam * Process the user's data in at most OBUFSIZ 12149578Ssam * chunks. Perform lower case simulation and 12159578Ssam * similar hacks. Keep track of high water 12169578Ssam * mark, sleep on overflow awaiting device aid 12179578Ssam * in acquiring new space. 12189578Ssam */ 12197822Sroot while (uio->uio_resid > 0) { 12209578Ssam /* 12219578Ssam * Grab a hunk of data from the user. 12229578Ssam */ 12237822Sroot cc = uio->uio_iov->iov_len; 12247822Sroot if (cc == 0) { 12257822Sroot uio->uio_iovcnt--; 12267822Sroot uio->uio_iov++; 12277822Sroot if (uio->uio_iovcnt < 0) 12287822Sroot panic("ttwrite"); 12297822Sroot continue; 12307822Sroot } 12317822Sroot if (cc > OBUFSIZ) 12327822Sroot cc = OBUFSIZ; 12337502Sroot cp = obuf; 123412752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12358520Sroot if (error) 12367502Sroot break; 12377502Sroot if (tp->t_outq.c_cc > hiwat) 12387502Sroot goto ovhiwat; 12399578Ssam if (tp->t_flags&FLUSHO) 12407502Sroot continue; 12419578Ssam /* 12429578Ssam * If we're mapping lower case or kludging tildes, 12439578Ssam * then we've got to look at each character, so 12449578Ssam * just feed the stuff to ttyoutput... 12459578Ssam */ 12469578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12479578Ssam while (cc > 0) { 12487502Sroot c = *cp++; 12497502Sroot tp->t_rocount = 0; 12507625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12517502Sroot /* out of clists, wait a bit */ 12527502Sroot ttstart(tp); 12537502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12547502Sroot tp->t_rocount = 0; 12557502Sroot } 12567502Sroot --cc; 12577502Sroot if (tp->t_outq.c_cc > hiwat) 12587502Sroot goto ovhiwat; 12597502Sroot } 12607502Sroot continue; 12617502Sroot } 12629578Ssam /* 12639578Ssam * If nothing fancy need be done, grab those characters we 12649578Ssam * can handle without any of ttyoutput's processing and 12659578Ssam * just transfer them to the output q. For those chars 12669578Ssam * which require special processing (as indicated by the 12679578Ssam * bits in partab), call ttyoutput. After processing 12689578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12699578Ssam * immediately. 12709578Ssam */ 12719578Ssam while (cc > 0) { 12729578Ssam if (tp->t_flags & (RAW|LITOUT)) 12737502Sroot ce = cc; 12747502Sroot else { 127512752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 127612752Ssam (caddr_t)partab, 077); 12779578Ssam /* 12789578Ssam * If ce is zero, then we're processing 12799578Ssam * a special character through ttyoutput. 12809578Ssam */ 12819578Ssam if (ce == 0) { 12827502Sroot tp->t_rocount = 0; 12837502Sroot if (ttyoutput(*cp, tp) >= 0) { 12849578Ssam /* no c-lists, wait a bit */ 12857502Sroot ttstart(tp); 12867502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12877502Sroot continue; 12887502Sroot } 12899578Ssam cp++, cc--; 12909578Ssam if (tp->t_flags&FLUSHO || 12919578Ssam tp->t_outq.c_cc > hiwat) 12927502Sroot goto ovhiwat; 12939578Ssam continue; 12947502Sroot } 12957502Sroot } 12969578Ssam /* 12979578Ssam * A bunch of normal characters have been found, 12989578Ssam * transfer them en masse to the output queue and 12999578Ssam * continue processing at the top of the loop. 13009578Ssam * If there are any further characters in this 13019578Ssam * <= OBUFSIZ chunk, the first should be a character 13029578Ssam * requiring special handling by ttyoutput. 13039578Ssam */ 13047502Sroot tp->t_rocount = 0; 13059578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13069578Ssam ce -= i; 13079578Ssam tp->t_col += ce; 13089578Ssam cp += ce, cc -= ce, tk_nout += ce; 13099578Ssam if (i > 0) { 13109578Ssam /* out of c-lists, wait a bit */ 13117502Sroot ttstart(tp); 13127502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13137502Sroot } 13149578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13157502Sroot goto ovhiwat; 13167502Sroot } 13177502Sroot } 13187502Sroot ttstart(tp); 13198520Sroot return (error); 13207502Sroot 13217502Sroot ovhiwat: 1322*17545Skarels s = spltty(); 13239578Ssam if (cc != 0) { 13249578Ssam uio->uio_iov->iov_base -= cc; 13259578Ssam uio->uio_iov->iov_len += cc; 13269578Ssam uio->uio_resid += cc; 13279578Ssam uio->uio_offset -= cc; 13289578Ssam } 13299578Ssam /* 13309578Ssam * This can only occur if FLUSHO 13319578Ssam * is also set in t_flags. 13329578Ssam */ 13337502Sroot if (tp->t_outq.c_cc <= hiwat) { 13349578Ssam splx(s); 13357502Sroot goto loop; 13367502Sroot } 13377502Sroot ttstart(tp); 13389578Ssam if (tp->t_state&TS_NBIO) { 1339*17545Skarels splx(s); 13407822Sroot if (uio->uio_resid == cnt) 13418520Sroot return (EWOULDBLOCK); 13428520Sroot return (0); 13437502Sroot } 13447502Sroot tp->t_state |= TS_ASLEEP; 13457502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13469578Ssam splx(s); 13477502Sroot goto loop; 13487502Sroot } 13497502Sroot 13507502Sroot /* 13517502Sroot * Rubout one character from the rawq of tp 13527502Sroot * as cleanly as possible. 13537502Sroot */ 13547502Sroot ttyrub(c, tp) 13557625Ssam register c; 13567625Ssam register struct tty *tp; 13577502Sroot { 13587502Sroot register char *cp; 13597502Sroot register int savecol; 13607502Sroot int s; 13617502Sroot char *nextc(); 13627502Sroot 13639578Ssam if ((tp->t_flags&ECHO) == 0) 13647502Sroot return; 13659578Ssam tp->t_flags &= ~FLUSHO; 13667502Sroot c &= 0377; 13679578Ssam if (tp->t_flags&CRTBS) { 13687502Sroot if (tp->t_rocount == 0) { 13697502Sroot /* 13707502Sroot * Screwed by ttwrite; retype 13717502Sroot */ 13727502Sroot ttyretype(tp); 13737502Sroot return; 13747502Sroot } 13759578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13767502Sroot ttyrubo(tp, 2); 13779578Ssam else switch (partab[c&=0177]&0177) { 13787502Sroot 13797502Sroot case ORDINARY: 13807502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13817502Sroot ttyrubo(tp, 2); 13827502Sroot else 13837502Sroot ttyrubo(tp, 1); 13847502Sroot break; 13857502Sroot 13867502Sroot case VTAB: 13877502Sroot case BACKSPACE: 13887502Sroot case CONTROL: 13897502Sroot case RETURN: 13909578Ssam if (tp->t_flags&CTLECH) 13917502Sroot ttyrubo(tp, 2); 13927502Sroot break; 13937502Sroot 13947502Sroot case TAB: 13957502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13967502Sroot ttyretype(tp); 13977502Sroot return; 13987502Sroot } 1399*17545Skarels s = spltty(); 14007502Sroot savecol = tp->t_col; 14019578Ssam tp->t_state |= TS_CNTTB; 14029578Ssam tp->t_flags |= FLUSHO; 14037502Sroot tp->t_col = tp->t_rocol; 14049578Ssam cp = tp->t_rawq.c_cf; 14059578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14067502Sroot ttyecho(*cp, tp); 14079578Ssam tp->t_flags &= ~FLUSHO; 14089578Ssam tp->t_state &= ~TS_CNTTB; 14097502Sroot splx(s); 14107502Sroot /* 14117502Sroot * savecol will now be length of the tab 14127502Sroot */ 14137502Sroot savecol -= tp->t_col; 14147502Sroot tp->t_col += savecol; 14157502Sroot if (savecol > 8) 14167502Sroot savecol = 8; /* overflow screw */ 14177502Sroot while (--savecol >= 0) 14187502Sroot (void) ttyoutput('\b', tp); 14197502Sroot break; 14207502Sroot 14217502Sroot default: 14227502Sroot panic("ttyrub"); 14237502Sroot } 14249578Ssam } else if (tp->t_flags&PRTERA) { 14259578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14267502Sroot (void) ttyoutput('\\', tp); 14279578Ssam tp->t_state |= TS_ERASE; 14287502Sroot } 14297502Sroot ttyecho(c, tp); 14307502Sroot } else 14317502Sroot ttyecho(tp->t_erase, tp); 14327502Sroot tp->t_rocount--; 14337502Sroot } 14347502Sroot 14357502Sroot /* 14367502Sroot * Crt back over cnt chars perhaps 14377502Sroot * erasing them. 14387502Sroot */ 14397502Sroot ttyrubo(tp, cnt) 14407625Ssam register struct tty *tp; 14417625Ssam int cnt; 14427502Sroot { 14439578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14447502Sroot 14457502Sroot while (--cnt >= 0) 14469578Ssam ttyout(rubostring, tp); 14477502Sroot } 14487502Sroot 14497502Sroot /* 14507502Sroot * Reprint the rawq line. 14517502Sroot * We assume c_cc has already been checked. 14527502Sroot */ 14537502Sroot ttyretype(tp) 14547625Ssam register struct tty *tp; 14557502Sroot { 14567502Sroot register char *cp; 14577502Sroot char *nextc(); 14587502Sroot int s; 14597502Sroot 14609578Ssam if (tp->t_rprntc != 0377) 14619578Ssam ttyecho(tp->t_rprntc, tp); 14627502Sroot (void) ttyoutput('\n', tp); 1463*17545Skarels s = spltty(); 14647502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14657502Sroot ttyecho(*cp, tp); 14667502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14677502Sroot ttyecho(*cp, tp); 14689578Ssam tp->t_state &= ~TS_ERASE; 14697502Sroot splx(s); 14707502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14717502Sroot tp->t_rocol = 0; 14727502Sroot } 14737502Sroot 14747502Sroot /* 14757502Sroot * Echo a typed character to the terminal 14767502Sroot */ 14777502Sroot ttyecho(c, tp) 14787625Ssam register c; 14797625Ssam register struct tty *tp; 14807502Sroot { 14817502Sroot 14829578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14839578Ssam tp->t_flags &= ~FLUSHO; 14847502Sroot if ((tp->t_flags&ECHO) == 0) 14857502Sroot return; 14867502Sroot c &= 0377; 14877502Sroot if (tp->t_flags&RAW) { 14887502Sroot (void) ttyoutput(c, tp); 14897502Sroot return; 14907502Sroot } 14917502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14927502Sroot c = '\n'; 14939578Ssam if (tp->t_flags&CTLECH) { 14947502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14957502Sroot (void) ttyoutput('^', tp); 14967502Sroot c &= 0177; 14977502Sroot if (c == 0177) 14987502Sroot c = '?'; 14997502Sroot else if (tp->t_flags&LCASE) 15007502Sroot c += 'a' - 1; 15017502Sroot else 15027502Sroot c += 'A' - 1; 15037502Sroot } 15047502Sroot } 15057502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 15067502Sroot c += 'a' - 'A'; 15079578Ssam (void) ttyoutput(c&0177, tp); 15087502Sroot } 15097502Sroot 15107502Sroot /* 15117502Sroot * Is c a break char for tp? 15127502Sroot */ 15137502Sroot ttbreakc(c, tp) 15147625Ssam register c; 15157625Ssam register struct tty *tp; 15167502Sroot { 15179578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15187502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15197502Sroot } 15207502Sroot 15217502Sroot /* 15227502Sroot * send string cp to tp 15237502Sroot */ 15247502Sroot ttyout(cp, tp) 15257625Ssam register char *cp; 15267625Ssam register struct tty *tp; 15277502Sroot { 15287502Sroot register char c; 15297502Sroot 15307502Sroot while (c = *cp++) 15317502Sroot (void) ttyoutput(c, tp); 15327502Sroot } 15337502Sroot 15347502Sroot ttwakeup(tp) 15357502Sroot struct tty *tp; 15367502Sroot { 15377502Sroot 15387502Sroot if (tp->t_rsel) { 15397502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15407502Sroot tp->t_state &= ~TS_RCOLL; 15417502Sroot tp->t_rsel = 0; 15427502Sroot } 154312752Ssam if (tp->t_state & TS_ASYNC) 154412752Ssam gsignal(tp->t_pgrp, SIGIO); 15457502Sroot wakeup((caddr_t)&tp->t_rawq); 15467502Sroot } 15477502Sroot 154813533Ssam #if !defined(vax) 15499578Ssam scanc(size, cp, table, mask) 15509578Ssam register int size; 15519578Ssam register char *cp, table[]; 15529578Ssam register int mask; 15537502Sroot { 15549578Ssam register int i = 0; 15557502Sroot 15569578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15579578Ssam i++; 155815100Skarels return (size - i); 15597502Sroot } 15609578Ssam #endif 1561