1*17183Smckusick /* tty.c 6.11 84/09/10 */ 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 { 12612752Ssam register int s = spl5(); 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 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 ; 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 221903Sbill s = spl5(); 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, 243903Sbill * insist on being able to write the device, 244903Sbill * and hang if in the background. 245903Sbill */ 2467625Ssam switch (com) { 24739Sbill 248915Sbill case TIOCSETD: 249915Sbill case TIOCSETP: 250915Sbill case TIOCSETN: 251903Sbill case TIOCFLUSH: 252903Sbill case TIOCSETC: 253903Sbill case TIOCSLTC: 254903Sbill case TIOCSPGRP: 255903Sbill case TIOCLBIS: 256903Sbill case TIOCLBIC: 257903Sbill case TIOCLSET: 2589325Ssam case TIOCSTI: 25915078Skarels #define bit(a) (1<<(a-1)) 260903Sbill while (tp->t_line == NTTYDISC && 261903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 262903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 26315078Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 26415078Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU))) { 265903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 266903Sbill sleep((caddr_t)&lbolt, TTOPRI); 267903Sbill } 268903Sbill break; 269903Sbill } 27015078Skarels #undef bit 271903Sbill 2729578Ssam /* 2739578Ssam * Process the ioctl. 2749578Ssam */ 2757625Ssam switch (com) { 276903Sbill 2778556Sroot /* get discipline number */ 27839Sbill case TIOCGETD: 2797625Ssam *(int *)data = tp->t_line; 28039Sbill break; 28139Sbill 2828556Sroot /* set line discipline */ 2837625Ssam case TIOCSETD: { 2847625Ssam register int t = *(int *)data; 2859578Ssam int error = 0; 2867625Ssam 28715078Skarels if ((unsigned) t >= nldisp) 28810851Ssam return (ENXIO); 2898556Sroot s = spl5(); 29039Sbill if (tp->t_line) 29139Sbill (*linesw[tp->t_line].l_close)(tp); 29239Sbill if (t) 2938556Sroot error = (*linesw[t].l_open)(dev, tp); 2948556Sroot splx(s); 29510851Ssam if (error) { 29610851Ssam s = spl5(); 29710851Ssam if (tp->t_line) 29810851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29910851Ssam splx(s); 3008556Sroot return (error); 30110851Ssam } 3028556Sroot tp->t_line = t; 30339Sbill break; 3047625Ssam } 30539Sbill 3068556Sroot /* prevent more opens on channel */ 3075614Swnj case TIOCEXCL: 3085614Swnj tp->t_state |= TS_XCLUDE; 3095614Swnj break; 3105614Swnj 3115614Swnj case TIOCNXCL: 3125614Swnj tp->t_state &= ~TS_XCLUDE; 3135614Swnj break; 3145614Swnj 3158556Sroot /* hang up line on last close */ 31639Sbill case TIOCHPCL: 3175408Swnj tp->t_state |= TS_HUPCLS; 31839Sbill break; 31939Sbill 3203942Sbugs case TIOCFLUSH: { 3217625Ssam register int flags = *(int *)data; 3227625Ssam 3237625Ssam if (flags == 0) 3243942Sbugs flags = FREAD|FWRITE; 3257625Ssam else 3267625Ssam flags &= FREAD|FWRITE; 32712752Ssam ttyflush(tp, flags); 32839Sbill break; 3293944Sbugs } 33039Sbill 3318556Sroot /* return number of characters immediately available */ 3327625Ssam case FIONREAD: 3337625Ssam *(off_t *)data = ttnread(tp); 334174Sbill break; 335174Sbill 33613077Ssam case TIOCOUTQ: 33713077Ssam *(int *)data = tp->t_outq.c_cc; 33813077Ssam break; 33913077Ssam 3408589Sroot case TIOCSTOP: 3418589Sroot s = spl5(); 3429578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3435573Swnj tp->t_state |= TS_TTSTOP; 3445573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3455573Swnj } 3467625Ssam splx(s); 3475573Swnj break; 3485573Swnj 3498589Sroot case TIOCSTART: 3508589Sroot s = spl5(); 3519578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3525573Swnj tp->t_state &= ~TS_TTSTOP; 3539578Ssam tp->t_flags &= ~FLUSHO; 3545573Swnj ttstart(tp); 3555573Swnj } 3567625Ssam splx(s); 3575573Swnj break; 3585573Swnj 3599325Ssam /* 3609325Ssam * Simulate typing of a character at the terminal. 3619325Ssam */ 3629325Ssam case TIOCSTI: 363*17183Smckusick if (u.u_uid && (flag & FREAD) == 0) 364*17183Smckusick return (EPERM); 3659325Ssam if (u.u_uid && u.u_ttyp != tp) 3669325Ssam return (EACCES); 3679578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3689325Ssam break; 3699325Ssam 37012752Ssam case TIOCSETP: 37112752Ssam case TIOCSETN: { 37212752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37312752Ssam 37412752Ssam tp->t_erase = sg->sg_erase; 37512752Ssam tp->t_kill = sg->sg_kill; 37612752Ssam tp->t_ispeed = sg->sg_ispeed; 37712752Ssam tp->t_ospeed = sg->sg_ospeed; 37812752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37912752Ssam s = spl5(); 38012752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38112752Ssam ttywait(tp); 38212752Ssam ttyflush(tp, FREAD); 38312752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38412752Ssam if (newflags&CBREAK) { 38512752Ssam struct clist tq; 38612752Ssam 38712752Ssam catq(&tp->t_rawq, &tp->t_canq); 38812752Ssam tq = tp->t_rawq; 38912752Ssam tp->t_rawq = tp->t_canq; 39012752Ssam tp->t_canq = tq; 39112752Ssam } else { 39212752Ssam tp->t_flags |= PENDIN; 39313801Ssam newflags |= PENDIN; 39412752Ssam ttwakeup(tp); 39512752Ssam } 39612752Ssam } 39712752Ssam tp->t_flags = newflags; 39812752Ssam if (tp->t_flags&RAW) { 39912752Ssam tp->t_state &= ~TS_TTSTOP; 40012752Ssam ttstart(tp); 40112752Ssam } 40212752Ssam splx(s); 40312752Ssam break; 40412752Ssam } 40512752Ssam 40612752Ssam /* send current parameters to user */ 40712752Ssam case TIOCGETP: { 40812752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40912752Ssam 41012752Ssam sg->sg_ispeed = tp->t_ispeed; 41112752Ssam sg->sg_ospeed = tp->t_ospeed; 41212752Ssam sg->sg_erase = tp->t_erase; 41312752Ssam sg->sg_kill = tp->t_kill; 41412752Ssam sg->sg_flags = tp->t_flags; 41512752Ssam break; 41612752Ssam } 41712752Ssam 41812752Ssam case FIONBIO: 41912752Ssam if (*(int *)data) 42012752Ssam tp->t_state |= TS_NBIO; 42112752Ssam else 42212752Ssam tp->t_state &= ~TS_NBIO; 42312752Ssam break; 42412752Ssam 42512752Ssam case FIOASYNC: 42612752Ssam if (*(int *)data) 42712752Ssam tp->t_state |= TS_ASYNC; 42812752Ssam else 42912752Ssam tp->t_state &= ~TS_ASYNC; 43012752Ssam break; 43112752Ssam 43213077Ssam case TIOCGETC: 43313077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43413077Ssam break; 43513077Ssam 43613077Ssam case TIOCSETC: 43713077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43813077Ssam break; 43913077Ssam 44012752Ssam /* set/get local special characters */ 44112752Ssam case TIOCSLTC: 44212752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44312752Ssam break; 44412752Ssam 44512752Ssam case TIOCGLTC: 44612752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44712752Ssam break; 44812752Ssam 44912752Ssam /* 45012752Ssam * Modify local mode word. 45112752Ssam */ 45212752Ssam case TIOCLBIS: 45312752Ssam tp->t_flags |= *(int *)data << 16; 45412752Ssam break; 45512752Ssam 45612752Ssam case TIOCLBIC: 45712752Ssam tp->t_flags &= ~(*(int *)data << 16); 45812752Ssam break; 45912752Ssam 46012752Ssam case TIOCLSET: 46112752Ssam tp->t_flags &= 0xffff; 46212752Ssam tp->t_flags |= *(int *)data << 16; 46312752Ssam break; 46412752Ssam 46512752Ssam case TIOCLGET: 46615720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46712752Ssam break; 46812752Ssam 46912752Ssam /* should allow SPGRP and GPGRP only if tty open for reading */ 47012752Ssam case TIOCSPGRP: 47112752Ssam tp->t_pgrp = *(int *)data; 47212752Ssam break; 47312752Ssam 47412752Ssam case TIOCGPGRP: 47512752Ssam *(int *)data = tp->t_pgrp; 47612752Ssam break; 47712752Ssam 47839Sbill default: 4798556Sroot return (-1); 48039Sbill } 4818556Sroot return (0); 48239Sbill } 4834484Swnj 4844484Swnj ttnread(tp) 4854484Swnj struct tty *tp; 4864484Swnj { 4874484Swnj int nread = 0; 4884484Swnj 4899578Ssam if (tp->t_flags & PENDIN) 4904484Swnj ttypend(tp); 4914484Swnj nread = tp->t_canq.c_cc; 4924484Swnj if (tp->t_flags & (RAW|CBREAK)) 4934484Swnj nread += tp->t_rawq.c_cc; 4944484Swnj return (nread); 4954484Swnj } 4964484Swnj 4975408Swnj ttselect(dev, rw) 4984484Swnj dev_t dev; 4995408Swnj int rw; 5004484Swnj { 5014484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5024484Swnj int nread; 5035408Swnj int s = spl5(); 5044484Swnj 5055408Swnj switch (rw) { 5064484Swnj 5074484Swnj case FREAD: 5084484Swnj nread = ttnread(tp); 5094484Swnj if (nread > 0) 5105408Swnj goto win; 5114938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5125408Swnj tp->t_state |= TS_RCOLL; 5134484Swnj else 5144484Swnj tp->t_rsel = u.u_procp; 5155408Swnj break; 5164484Swnj 5175408Swnj case FWRITE: 5185408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5195408Swnj goto win; 5205408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5215408Swnj tp->t_state |= TS_WCOLL; 5225408Swnj else 5235408Swnj tp->t_wsel = u.u_procp; 5245408Swnj break; 5254484Swnj } 5265408Swnj splx(s); 5275408Swnj return (0); 5285408Swnj win: 5295408Swnj splx(s); 5305408Swnj return (1); 5314484Swnj } 5327436Skre 5337502Sroot /* 5349578Ssam * Establish a process group for distribution of 5357502Sroot * quits and interrupts from the tty. 5367502Sroot */ 5377502Sroot ttyopen(dev, tp) 5387625Ssam dev_t dev; 5397625Ssam register struct tty *tp; 5407502Sroot { 5417502Sroot register struct proc *pp; 5427502Sroot 5437502Sroot pp = u.u_procp; 5447502Sroot tp->t_dev = dev; 5457625Ssam if (pp->p_pgrp == 0) { 5467502Sroot u.u_ttyp = tp; 5477502Sroot u.u_ttyd = dev; 5487502Sroot if (tp->t_pgrp == 0) 5497502Sroot tp->t_pgrp = pp->p_pid; 5507502Sroot pp->p_pgrp = tp->t_pgrp; 5517502Sroot } 5527502Sroot tp->t_state &= ~TS_WOPEN; 5537502Sroot tp->t_state |= TS_ISOPEN; 5547502Sroot if (tp->t_line != NTTYDISC) 55512752Ssam ttywflush(tp); 5568556Sroot return (0); 5577502Sroot } 5587502Sroot 5597502Sroot /* 5607502Sroot * clean tp on last close 5617502Sroot */ 5627502Sroot ttyclose(tp) 5637625Ssam register struct tty *tp; 5647502Sroot { 5657502Sroot 5667502Sroot if (tp->t_line) { 56712752Ssam ttywflush(tp); 5687502Sroot tp->t_line = 0; 5697502Sroot return; 5707502Sroot } 5717502Sroot tp->t_pgrp = 0; 57212752Ssam ttywflush(tp); 5737502Sroot tp->t_state = 0; 5747502Sroot } 5757502Sroot 5767502Sroot /* 5777502Sroot * reinput pending characters after state switch 5787502Sroot * call at spl5(). 5797502Sroot */ 5807502Sroot ttypend(tp) 5817625Ssam register struct tty *tp; 5827502Sroot { 5837502Sroot struct clist tq; 5847502Sroot register c; 5857502Sroot 5869578Ssam tp->t_flags &= ~PENDIN; 5879578Ssam tp->t_state |= TS_TYPEN; 5887502Sroot tq = tp->t_rawq; 5897502Sroot tp->t_rawq.c_cc = 0; 5907502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5917502Sroot while ((c = getc(&tq)) >= 0) 5927502Sroot ttyinput(c, tp); 5939578Ssam tp->t_state &= ~TS_TYPEN; 5947502Sroot } 5957502Sroot 5967502Sroot /* 5979578Ssam * Place a character on raw TTY input queue, 5989578Ssam * putting in delimiters and waking up top 5999578Ssam * half as needed. Also echo if required. 6009578Ssam * The arguments are the character and the 6019578Ssam * appropriate tty structure. 6027502Sroot */ 6037502Sroot ttyinput(c, tp) 6047625Ssam register c; 6057625Ssam register struct tty *tp; 6067502Sroot { 6079578Ssam register int t_flags = tp->t_flags; 6087502Sroot int i; 6097502Sroot 6109578Ssam /* 6119578Ssam * If input is pending take it first. 6129578Ssam */ 6139578Ssam if (t_flags&PENDIN) 6147502Sroot ttypend(tp); 6157502Sroot tk_nin++; 6167502Sroot c &= 0377; 6179578Ssam 6189578Ssam /* 6199578Ssam * In tandem mode, check high water mark. 6209578Ssam */ 6217502Sroot if (t_flags&TANDEM) 6227502Sroot ttyblock(tp); 6239578Ssam 6249578Ssam if (t_flags&RAW) { 6259578Ssam /* 6269578Ssam * Raw mode, just put character 6279578Ssam * in input q w/o interpretation. 6289578Ssam */ 6299578Ssam if (tp->t_rawq.c_cc > TTYHOG) 63012752Ssam ttyflush(tp, FREAD|FWRITE); 6319578Ssam else { 6329578Ssam if (putc(c, &tp->t_rawq) >= 0) 6339578Ssam ttwakeup(tp); 6349578Ssam ttyecho(c, tp); 6357502Sroot } 6369578Ssam goto endcase; 6379578Ssam } 6389578Ssam 6399578Ssam /* 6409578Ssam * Ignore any high bit added during 6419578Ssam * previous ttyinput processing. 6429578Ssam */ 6439578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6449578Ssam c &= 0177; 6459578Ssam /* 6469578Ssam * Check for literal nexting very first 6479578Ssam */ 6489578Ssam if (tp->t_state&TS_LNCH) { 6499578Ssam c |= 0200; 6509578Ssam tp->t_state &= ~TS_LNCH; 6519578Ssam } 6529578Ssam 6539578Ssam /* 6549578Ssam * Scan for special characters. This code 6559578Ssam * is really just a big case statement with 6569578Ssam * non-constant cases. The bottom of the 6579578Ssam * case statement is labeled ``endcase'', so goto 6589578Ssam * it after a case match, or similar. 6599578Ssam */ 6609578Ssam if (tp->t_line == NTTYDISC) { 6619578Ssam if (c == tp->t_lnextc) { 6627502Sroot if (tp->t_flags&ECHO) 6637502Sroot ttyout("^\b", tp); 6649578Ssam tp->t_state |= TS_LNCH; 6659578Ssam goto endcase; 6669578Ssam } 6679578Ssam if (c == tp->t_flushc) { 6689578Ssam if (tp->t_flags&FLUSHO) 6699578Ssam tp->t_flags &= ~FLUSHO; 6707502Sroot else { 67112752Ssam ttyflush(tp, FWRITE); 6727502Sroot ttyecho(c, tp); 6739578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6747502Sroot ttyretype(tp); 6759578Ssam tp->t_flags |= FLUSHO; 6767502Sroot } 6779578Ssam goto startoutput; 6789578Ssam } 6799578Ssam if (c == tp->t_suspc) { 6809578Ssam if ((tp->t_flags&NOFLSH) == 0) 68112752Ssam ttyflush(tp, FREAD); 6829578Ssam ttyecho(c, tp); 6839578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6849578Ssam goto endcase; 6859578Ssam } 6869578Ssam } 6879578Ssam 6889578Ssam /* 6899578Ssam * Handle start/stop characters. 6909578Ssam */ 6919578Ssam if (c == tp->t_stopc) { 6929578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6939578Ssam tp->t_state |= TS_TTSTOP; 6949578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6957502Sroot return; 6969578Ssam } 6979578Ssam if (c != tp->t_startc) 6989578Ssam return; 6999578Ssam goto endcase; 7009578Ssam } 7019578Ssam if (c == tp->t_startc) 7029578Ssam goto restartoutput; 7039578Ssam 7049578Ssam /* 7059578Ssam * Look for interrupt/quit chars. 7069578Ssam */ 7079578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7089578Ssam if ((tp->t_flags&NOFLSH) == 0) 70912752Ssam ttyflush(tp, FREAD|FWRITE); 7109578Ssam ttyecho(c, tp); 7119578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7129578Ssam goto endcase; 7139578Ssam } 7149578Ssam 7159578Ssam /* 7169578Ssam * Cbreak mode, don't process line editing 7179578Ssam * characters; check high water mark for wakeup. 7189578Ssam */ 7199578Ssam if (t_flags&CBREAK) { 7209578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7217502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7227502Sroot tp->t_line == NTTYDISC) 7237502Sroot (void) ttyoutput(CTRL(g), tp); 7247502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7257502Sroot ttwakeup(tp); 7267502Sroot ttyecho(c, tp); 7277502Sroot } 7289578Ssam goto endcase; 7299578Ssam } 7309578Ssam 7319578Ssam /* 7329578Ssam * From here on down cooked mode character 7339578Ssam * processing takes place. 7349578Ssam */ 7359578Ssam if ((tp->t_state&TS_QUOT) && 7369578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7379578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7389578Ssam c |= 0200; 7399578Ssam } 7409578Ssam if (c == tp->t_erase) { 7419578Ssam if (tp->t_rawq.c_cc) 7429578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7439578Ssam goto endcase; 7449578Ssam } 7459578Ssam if (c == tp->t_kill) { 7469578Ssam if (tp->t_flags&CRTKIL && 7479578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7489578Ssam while (tp->t_rawq.c_cc) 7499578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7509578Ssam } else { 7519578Ssam ttyecho(c, tp); 7529578Ssam ttyecho('\n', tp); 7539578Ssam while (getc(&tp->t_rawq) > 0) 7549578Ssam ; 7559578Ssam tp->t_rocount = 0; 7569578Ssam } 7579578Ssam tp->t_state &= ~TS_LOCAL; 7589578Ssam goto endcase; 7599578Ssam } 7609578Ssam 7619578Ssam /* 7629578Ssam * New line discipline, 7639578Ssam * check word erase/reprint line. 7649578Ssam */ 7659578Ssam if (tp->t_line == NTTYDISC) { 7669578Ssam if (c == tp->t_werasc) { 7679578Ssam if (tp->t_rawq.c_cc == 0) 7689578Ssam goto endcase; 7699578Ssam do { 7709578Ssam c = unputc(&tp->t_rawq); 7719578Ssam if (c != ' ' && c != '\t') 7729578Ssam goto erasenb; 7739578Ssam ttyrub(c, tp); 7749578Ssam } while (tp->t_rawq.c_cc); 7759578Ssam goto endcase; 7769578Ssam erasenb: 7779578Ssam do { 7789578Ssam ttyrub(c, tp); 7799578Ssam if (tp->t_rawq.c_cc == 0) 7809578Ssam goto endcase; 7819578Ssam c = unputc(&tp->t_rawq); 7829578Ssam } while (c != ' ' && c != '\t'); 7839578Ssam (void) putc(c, &tp->t_rawq); 7849578Ssam goto endcase; 7859578Ssam } 7869578Ssam if (c == tp->t_rprntc) { 7879578Ssam ttyretype(tp); 7889578Ssam goto endcase; 7899578Ssam } 7909578Ssam } 7919578Ssam 7929578Ssam /* 7939578Ssam * Check for input buffer overflow 7949578Ssam */ 79510391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 79610391Ssam if (tp->t_line == NTTYDISC) 79710391Ssam (void) ttyoutput(CTRL(g), tp); 7989578Ssam goto endcase; 79910391Ssam } 8009578Ssam 8019578Ssam /* 8029578Ssam * Put data char in q for user and 8039578Ssam * wakeup on seeing a line delimiter. 8049578Ssam */ 8059578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8069578Ssam if (ttbreakc(c, tp)) { 8079578Ssam tp->t_rocount = 0; 8089578Ssam catq(&tp->t_rawq, &tp->t_canq); 8097502Sroot ttwakeup(tp); 8109578Ssam } else if (tp->t_rocount++ == 0) 8119578Ssam tp->t_rocol = tp->t_col; 8129578Ssam tp->t_state &= ~TS_QUOT; 8139578Ssam if (c == '\\') 8149578Ssam tp->t_state |= TS_QUOT; 8159578Ssam if (tp->t_state&TS_ERASE) { 8169578Ssam tp->t_state &= ~TS_ERASE; 8179578Ssam (void) ttyoutput('/', tp); 8189578Ssam } 8199578Ssam i = tp->t_col; 8207502Sroot ttyecho(c, tp); 8219578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8229578Ssam i = MIN(2, tp->t_col - i); 8239578Ssam while (i > 0) { 8249578Ssam (void) ttyoutput('\b', tp); 8259578Ssam i--; 8269578Ssam } 8279578Ssam } 8287502Sroot } 8299578Ssam 8309578Ssam endcase: 8319578Ssam /* 8329578Ssam * If DEC-style start/stop is enabled don't restart 8339578Ssam * output until seeing the start character. 8349578Ssam */ 8359578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8369578Ssam tp->t_startc != tp->t_stopc) 8377502Sroot return; 8389578Ssam 8399578Ssam restartoutput: 8407502Sroot tp->t_state &= ~TS_TTSTOP; 8419578Ssam tp->t_flags &= ~FLUSHO; 8429578Ssam 8439578Ssam startoutput: 8447502Sroot ttstart(tp); 8457502Sroot } 8467502Sroot 8477502Sroot /* 8489578Ssam * Put character on TTY output queue, adding delays, 8497502Sroot * expanding tabs, and handling the CR/NL bit. 8509578Ssam * This is called both from the top half for output, 8519578Ssam * and from interrupt level for echoing. 8527502Sroot * The arguments are the character and the tty structure. 8537502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8547502Sroot * Must be recursive. 8557502Sroot */ 8567502Sroot ttyoutput(c, tp) 8577502Sroot register c; 8587502Sroot register struct tty *tp; 8597502Sroot { 8607502Sroot register char *colp; 8617502Sroot register ctype; 8627502Sroot 8639578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8649578Ssam if (tp->t_flags&FLUSHO) 8657502Sroot return (-1); 8667502Sroot if (putc(c, &tp->t_outq)) 8677625Ssam return (c); 8687502Sroot tk_nout++; 8697502Sroot return (-1); 8707502Sroot } 8719578Ssam 8727502Sroot /* 8739578Ssam * Ignore EOT in normal mode to avoid 8749578Ssam * hanging up certain terminals. 8757502Sroot */ 8767502Sroot c &= 0177; 8779578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8787502Sroot return (-1); 8797502Sroot /* 8807502Sroot * Turn tabs to spaces as required 8817502Sroot */ 8829578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8837502Sroot register int s; 8847502Sroot 8857502Sroot c = 8 - (tp->t_col&7); 8869578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8877502Sroot s = spl5(); /* don't interrupt tabs */ 8887502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8897502Sroot tk_nout += c; 8907502Sroot splx(s); 8917502Sroot } 8927502Sroot tp->t_col += c; 8937502Sroot return (c ? -1 : '\t'); 8947502Sroot } 8957502Sroot tk_nout++; 8967502Sroot /* 8977502Sroot * for upper-case-only terminals, 8987502Sroot * generate escapes. 8997502Sroot */ 9007502Sroot if (tp->t_flags&LCASE) { 9017502Sroot colp = "({)}!|^~'`"; 9027625Ssam while (*colp++) 9037625Ssam if (c == *colp++) { 9047502Sroot if (ttyoutput('\\', tp) >= 0) 9057502Sroot return (c); 9067502Sroot c = colp[-2]; 9077502Sroot break; 9087502Sroot } 9099578Ssam if ('A' <= c && c <= 'Z') { 9107502Sroot if (ttyoutput('\\', tp) >= 0) 9117502Sroot return (c); 9129578Ssam } else if ('a' <= c && c <= 'z') 9137502Sroot c += 'A' - 'a'; 9147502Sroot } 9159578Ssam 9167502Sroot /* 9177502Sroot * turn <nl> to <cr><lf> if desired. 9187502Sroot */ 9199578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9207502Sroot if (ttyoutput('\r', tp) >= 0) 9217502Sroot return (c); 9229578Ssam if (c == '~' && tp->t_flags&TILDE) 9237502Sroot c = '`'; 9249578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9257502Sroot return (c); 9267502Sroot /* 9277502Sroot * Calculate delays. 9287502Sroot * The numbers here represent clock ticks 9297502Sroot * and are not necessarily optimal for all terminals. 9307502Sroot * The delays are indicated by characters above 0200. 9317502Sroot * In raw mode there are no delays and the 9327502Sroot * transmission path is 8 bits wide. 9339578Ssam * 9349578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9357502Sroot */ 9367502Sroot colp = &tp->t_col; 9377502Sroot ctype = partab[c]; 9387502Sroot c = 0; 9397502Sroot switch (ctype&077) { 9407502Sroot 9417502Sroot case ORDINARY: 9427502Sroot (*colp)++; 9437502Sroot 9447502Sroot case CONTROL: 9457502Sroot break; 9467502Sroot 9477502Sroot case BACKSPACE: 9487502Sroot if (*colp) 9497502Sroot (*colp)--; 9507502Sroot break; 9517502Sroot 95213821Ssam /* 95313821Ssam * This macro is close enough to the correct thing; 95413821Ssam * it should be replaced by real user settable delays 95513821Ssam * in any event... 95613821Ssam */ 95713821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9587502Sroot case NEWLINE: 9597502Sroot ctype = (tp->t_flags >> 8) & 03; 9607625Ssam if (ctype == 1) { /* tty 37 */ 96112752Ssam if (*colp > 0) 96213863Ssam c = max((((unsigned)*colp) >> 4) + 3, 96313863Ssam (unsigned)6); 9649578Ssam } else if (ctype == 2) /* vt05 */ 96513821Ssam c = mstohz(100); 9667502Sroot *colp = 0; 9677502Sroot break; 9687502Sroot 9697502Sroot case TAB: 9707502Sroot ctype = (tp->t_flags >> 10) & 03; 9717625Ssam if (ctype == 1) { /* tty 37 */ 9727502Sroot c = 1 - (*colp | ~07); 9737625Ssam if (c < 5) 9747502Sroot c = 0; 9757502Sroot } 9767502Sroot *colp |= 07; 9777502Sroot (*colp)++; 9787502Sroot break; 9797502Sroot 9807502Sroot case VTAB: 9819578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9827502Sroot c = 0177; 9837502Sroot break; 9847502Sroot 9857502Sroot case RETURN: 9867502Sroot ctype = (tp->t_flags >> 12) & 03; 9879578Ssam if (ctype == 1) /* tn 300 */ 98813821Ssam c = mstohz(83); 9899578Ssam else if (ctype == 2) /* ti 700 */ 99013821Ssam c = mstohz(166); 9919578Ssam else if (ctype == 3) { /* concept 100 */ 9927502Sroot int i; 9939578Ssam 9947502Sroot if ((i = *colp) >= 0) 9959578Ssam for (; i < 9; i++) 9967502Sroot (void) putc(0177, &tp->t_outq); 9977502Sroot } 9987502Sroot *colp = 0; 9997502Sroot } 10009578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10017502Sroot (void) putc(c|0200, &tp->t_outq); 10027502Sroot return (-1); 10037502Sroot } 100413821Ssam #undef mstohz 10057502Sroot 10067502Sroot /* 10077502Sroot * Called from device's read routine after it has 10087502Sroot * calculated the tty-structure given as argument. 10097502Sroot */ 10107722Swnj ttread(tp, uio) 10117625Ssam register struct tty *tp; 10127722Swnj struct uio *uio; 10137502Sroot { 10147502Sroot register struct clist *qp; 10159578Ssam register c, t_flags; 10169859Ssam int s, first, error = 0; 10177502Sroot 10187502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10198520Sroot return (EIO); 10207502Sroot loop: 10219578Ssam /* 10229578Ssam * Take any pending input first. 10239578Ssam */ 10249859Ssam s = spl5(); 10259578Ssam if (tp->t_flags&PENDIN) 10267502Sroot ttypend(tp); 10279859Ssam splx(s); 10289578Ssam 10299578Ssam /* 10309578Ssam * Hang process if it's in the background. 10319578Ssam */ 103215141Skarels #define bit(a) (1<<(a-1)) 10337502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 103415141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 103515141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10367502Sroot /* 10377502Sroot (u.u_procp->p_flag&SDETACH) || 10387502Sroot */ 10397502Sroot u.u_procp->p_flag&SVFORK) 10408520Sroot return (EIO); 10417502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10427502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10437502Sroot } 10449578Ssam t_flags = tp->t_flags; 104515141Skarels #undef bit 10469578Ssam 10479578Ssam /* 10489578Ssam * In raw mode take characters directly from the 10499578Ssam * raw queue w/o processing. Interlock against 10509578Ssam * device interrupts when interrogating rawq. 10519578Ssam */ 10529578Ssam if (t_flags&RAW) { 10539859Ssam s = spl5(); 10547502Sroot if (tp->t_rawq.c_cc <= 0) { 10559578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10567502Sroot (tp->t_state&TS_NBIO)) { 10579859Ssam splx(s); 105815094Skarels return (EWOULDBLOCK); 10597502Sroot } 10607502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10619859Ssam splx(s); 10627502Sroot goto loop; 10637502Sroot } 10649859Ssam splx(s); 106514938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 106614938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10679859Ssam goto checktandem; 10689578Ssam } 10699578Ssam 10709578Ssam /* 10719578Ssam * In cbreak mode use the rawq, otherwise 10729578Ssam * take characters from the canonicalized q. 10739578Ssam */ 10749578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10759578Ssam 10769578Ssam /* 10779578Ssam * No input, sleep on rawq awaiting hardware 10789578Ssam * receipt and notification. 10799578Ssam */ 10809859Ssam s = spl5(); 10819578Ssam if (qp->c_cc <= 0) { 10829578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10839578Ssam (tp->t_state&TS_NBIO)) { 10849859Ssam splx(s); 10859578Ssam return (EWOULDBLOCK); 10867502Sroot } 10879578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10889859Ssam splx(s); 10899578Ssam goto loop; 10909578Ssam } 10919859Ssam splx(s); 10929578Ssam 10939578Ssam /* 10949578Ssam * Input present, perform input mapping 10959578Ssam * and processing (we're not in raw mode). 10969578Ssam */ 10979578Ssam first = 1; 10989578Ssam while ((c = getc(qp)) >= 0) { 10999578Ssam if (t_flags&CRMOD && c == '\r') 11009578Ssam c = '\n'; 11019578Ssam /* 11029578Ssam * Hack lower case simulation on 11039578Ssam * upper case only terminals. 11049578Ssam */ 11059578Ssam if (t_flags&LCASE && c <= 0177) 11069578Ssam if (tp->t_state&TS_BKSL) { 11079578Ssam if (maptab[c]) 11089578Ssam c = maptab[c]; 11099578Ssam tp->t_state &= ~TS_BKSL; 11109578Ssam } else if (c >= 'A' && c <= 'Z') 11119578Ssam c += 'a' - 'A'; 11129578Ssam else if (c == '\\') { 11139578Ssam tp->t_state |= TS_BKSL; 11149578Ssam continue; 11157502Sroot } 11169578Ssam /* 11179578Ssam * Check for delayed suspend character. 11189578Ssam */ 11199578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11209578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11219578Ssam if (first) { 11229578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11239578Ssam goto loop; 11249578Ssam } 11259578Ssam break; 11267502Sroot } 11279578Ssam /* 11289578Ssam * Interpret EOF only in cooked mode. 11299578Ssam */ 11309578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11319578Ssam break; 11329578Ssam /* 11339578Ssam * Give user character. 11349578Ssam */ 113514938Smckusick error = ureadc(c & 0177, uio); 11369578Ssam if (error) 11379578Ssam break; 113814938Smckusick if (uio->uio_resid == 0) 11399578Ssam break; 11409578Ssam /* 11419578Ssam * In cooked mode check for a "break character" 11429578Ssam * marking the end of a "line of input". 11439578Ssam */ 11449578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11459578Ssam break; 11469578Ssam first = 0; 11477502Sroot } 11489578Ssam tp->t_state &= ~TS_BKSL; 11499578Ssam 11509859Ssam checktandem: 11519578Ssam /* 11529578Ssam * Look to unblock output now that (presumably) 11539578Ssam * the input queue has gone down. 11549578Ssam */ 11559859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11569578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11577502Sroot tp->t_state &= ~TS_TBLOCK; 11587502Sroot ttstart(tp); 11597502Sroot } 11608520Sroot return (error); 11617502Sroot } 11627502Sroot 11637502Sroot /* 11647502Sroot * Called from the device's write routine after it has 11657502Sroot * calculated the tty-structure given as argument. 11667502Sroot */ 11677822Sroot ttwrite(tp, uio) 11687625Ssam register struct tty *tp; 11699578Ssam register struct uio *uio; 11707502Sroot { 11717502Sroot register char *cp; 11729578Ssam register int cc, ce, c; 11739578Ssam int i, hiwat, cnt, error, s; 11747502Sroot char obuf[OBUFSIZ]; 11757502Sroot 11769578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11778520Sroot return (EIO); 11789578Ssam hiwat = TTHIWAT(tp); 11799578Ssam cnt = uio->uio_resid; 11809578Ssam error = 0; 11817502Sroot loop: 11829578Ssam /* 11839578Ssam * Hang the process if it's in the background. 11849578Ssam */ 118515141Skarels #define bit(a) (1<<(a-1)) 11867502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11879578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 118815141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 118915141Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU)) 11907502Sroot /* 11917502Sroot && 11927502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11937502Sroot */ 11947502Sroot ) { 11957502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11967502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11977502Sroot } 119815141Skarels #undef bit 11999578Ssam 12009578Ssam /* 12019578Ssam * Process the user's data in at most OBUFSIZ 12029578Ssam * chunks. Perform lower case simulation and 12039578Ssam * similar hacks. Keep track of high water 12049578Ssam * mark, sleep on overflow awaiting device aid 12059578Ssam * in acquiring new space. 12069578Ssam */ 12077822Sroot while (uio->uio_resid > 0) { 12089578Ssam /* 12099578Ssam * Grab a hunk of data from the user. 12109578Ssam */ 12117822Sroot cc = uio->uio_iov->iov_len; 12127822Sroot if (cc == 0) { 12137822Sroot uio->uio_iovcnt--; 12147822Sroot uio->uio_iov++; 12157822Sroot if (uio->uio_iovcnt < 0) 12167822Sroot panic("ttwrite"); 12177822Sroot continue; 12187822Sroot } 12197822Sroot if (cc > OBUFSIZ) 12207822Sroot cc = OBUFSIZ; 12217502Sroot cp = obuf; 122212752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12238520Sroot if (error) 12247502Sroot break; 12257502Sroot if (tp->t_outq.c_cc > hiwat) 12267502Sroot goto ovhiwat; 12279578Ssam if (tp->t_flags&FLUSHO) 12287502Sroot continue; 12299578Ssam /* 12309578Ssam * If we're mapping lower case or kludging tildes, 12319578Ssam * then we've got to look at each character, so 12329578Ssam * just feed the stuff to ttyoutput... 12339578Ssam */ 12349578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12359578Ssam while (cc > 0) { 12367502Sroot c = *cp++; 12377502Sroot tp->t_rocount = 0; 12387625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12397502Sroot /* out of clists, wait a bit */ 12407502Sroot ttstart(tp); 12417502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12427502Sroot tp->t_rocount = 0; 12437502Sroot } 12447502Sroot --cc; 12457502Sroot if (tp->t_outq.c_cc > hiwat) 12467502Sroot goto ovhiwat; 12477502Sroot } 12487502Sroot continue; 12497502Sroot } 12509578Ssam /* 12519578Ssam * If nothing fancy need be done, grab those characters we 12529578Ssam * can handle without any of ttyoutput's processing and 12539578Ssam * just transfer them to the output q. For those chars 12549578Ssam * which require special processing (as indicated by the 12559578Ssam * bits in partab), call ttyoutput. After processing 12569578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12579578Ssam * immediately. 12589578Ssam */ 12599578Ssam while (cc > 0) { 12609578Ssam if (tp->t_flags & (RAW|LITOUT)) 12617502Sroot ce = cc; 12627502Sroot else { 126312752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 126412752Ssam (caddr_t)partab, 077); 12659578Ssam /* 12669578Ssam * If ce is zero, then we're processing 12679578Ssam * a special character through ttyoutput. 12689578Ssam */ 12699578Ssam if (ce == 0) { 12707502Sroot tp->t_rocount = 0; 12717502Sroot if (ttyoutput(*cp, tp) >= 0) { 12729578Ssam /* no c-lists, wait a bit */ 12737502Sroot ttstart(tp); 12747502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12757502Sroot continue; 12767502Sroot } 12779578Ssam cp++, cc--; 12789578Ssam if (tp->t_flags&FLUSHO || 12799578Ssam tp->t_outq.c_cc > hiwat) 12807502Sroot goto ovhiwat; 12819578Ssam continue; 12827502Sroot } 12837502Sroot } 12849578Ssam /* 12859578Ssam * A bunch of normal characters have been found, 12869578Ssam * transfer them en masse to the output queue and 12879578Ssam * continue processing at the top of the loop. 12889578Ssam * If there are any further characters in this 12899578Ssam * <= OBUFSIZ chunk, the first should be a character 12909578Ssam * requiring special handling by ttyoutput. 12919578Ssam */ 12927502Sroot tp->t_rocount = 0; 12939578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12949578Ssam ce -= i; 12959578Ssam tp->t_col += ce; 12969578Ssam cp += ce, cc -= ce, tk_nout += ce; 12979578Ssam if (i > 0) { 12989578Ssam /* out of c-lists, wait a bit */ 12997502Sroot ttstart(tp); 13007502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13017502Sroot } 13029578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13037502Sroot goto ovhiwat; 13047502Sroot } 13057502Sroot } 13067502Sroot ttstart(tp); 13078520Sroot return (error); 13087502Sroot 13097502Sroot ovhiwat: 13109578Ssam s = spl5(); 13119578Ssam if (cc != 0) { 13129578Ssam uio->uio_iov->iov_base -= cc; 13139578Ssam uio->uio_iov->iov_len += cc; 13149578Ssam uio->uio_resid += cc; 13159578Ssam uio->uio_offset -= cc; 13169578Ssam } 13179578Ssam /* 13189578Ssam * This can only occur if FLUSHO 13199578Ssam * is also set in t_flags. 13209578Ssam */ 13217502Sroot if (tp->t_outq.c_cc <= hiwat) { 13229578Ssam splx(s); 13237502Sroot goto loop; 13247502Sroot } 13257502Sroot ttstart(tp); 13269578Ssam if (tp->t_state&TS_NBIO) { 13277822Sroot if (uio->uio_resid == cnt) 13288520Sroot return (EWOULDBLOCK); 13298520Sroot return (0); 13307502Sroot } 13317502Sroot tp->t_state |= TS_ASLEEP; 13327502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13339578Ssam splx(s); 13347502Sroot goto loop; 13357502Sroot } 13367502Sroot 13377502Sroot /* 13387502Sroot * Rubout one character from the rawq of tp 13397502Sroot * as cleanly as possible. 13407502Sroot */ 13417502Sroot ttyrub(c, tp) 13427625Ssam register c; 13437625Ssam register struct tty *tp; 13447502Sroot { 13457502Sroot register char *cp; 13467502Sroot register int savecol; 13477502Sroot int s; 13487502Sroot char *nextc(); 13497502Sroot 13509578Ssam if ((tp->t_flags&ECHO) == 0) 13517502Sroot return; 13529578Ssam tp->t_flags &= ~FLUSHO; 13537502Sroot c &= 0377; 13549578Ssam if (tp->t_flags&CRTBS) { 13557502Sroot if (tp->t_rocount == 0) { 13567502Sroot /* 13577502Sroot * Screwed by ttwrite; retype 13587502Sroot */ 13597502Sroot ttyretype(tp); 13607502Sroot return; 13617502Sroot } 13629578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13637502Sroot ttyrubo(tp, 2); 13649578Ssam else switch (partab[c&=0177]&0177) { 13657502Sroot 13667502Sroot case ORDINARY: 13677502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13687502Sroot ttyrubo(tp, 2); 13697502Sroot else 13707502Sroot ttyrubo(tp, 1); 13717502Sroot break; 13727502Sroot 13737502Sroot case VTAB: 13747502Sroot case BACKSPACE: 13757502Sroot case CONTROL: 13767502Sroot case RETURN: 13779578Ssam if (tp->t_flags&CTLECH) 13787502Sroot ttyrubo(tp, 2); 13797502Sroot break; 13807502Sroot 13817502Sroot case TAB: 13827502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13837502Sroot ttyretype(tp); 13847502Sroot return; 13857502Sroot } 13867502Sroot s = spl5(); 13877502Sroot savecol = tp->t_col; 13889578Ssam tp->t_state |= TS_CNTTB; 13899578Ssam tp->t_flags |= FLUSHO; 13907502Sroot tp->t_col = tp->t_rocol; 13919578Ssam cp = tp->t_rawq.c_cf; 13929578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13937502Sroot ttyecho(*cp, tp); 13949578Ssam tp->t_flags &= ~FLUSHO; 13959578Ssam tp->t_state &= ~TS_CNTTB; 13967502Sroot splx(s); 13977502Sroot /* 13987502Sroot * savecol will now be length of the tab 13997502Sroot */ 14007502Sroot savecol -= tp->t_col; 14017502Sroot tp->t_col += savecol; 14027502Sroot if (savecol > 8) 14037502Sroot savecol = 8; /* overflow screw */ 14047502Sroot while (--savecol >= 0) 14057502Sroot (void) ttyoutput('\b', tp); 14067502Sroot break; 14077502Sroot 14087502Sroot default: 14097502Sroot panic("ttyrub"); 14107502Sroot } 14119578Ssam } else if (tp->t_flags&PRTERA) { 14129578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14137502Sroot (void) ttyoutput('\\', tp); 14149578Ssam tp->t_state |= TS_ERASE; 14157502Sroot } 14167502Sroot ttyecho(c, tp); 14177502Sroot } else 14187502Sroot ttyecho(tp->t_erase, tp); 14197502Sroot tp->t_rocount--; 14207502Sroot } 14217502Sroot 14227502Sroot /* 14237502Sroot * Crt back over cnt chars perhaps 14247502Sroot * erasing them. 14257502Sroot */ 14267502Sroot ttyrubo(tp, cnt) 14277625Ssam register struct tty *tp; 14287625Ssam int cnt; 14297502Sroot { 14309578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14317502Sroot 14327502Sroot while (--cnt >= 0) 14339578Ssam ttyout(rubostring, tp); 14347502Sroot } 14357502Sroot 14367502Sroot /* 14377502Sroot * Reprint the rawq line. 14387502Sroot * We assume c_cc has already been checked. 14397502Sroot */ 14407502Sroot ttyretype(tp) 14417625Ssam register struct tty *tp; 14427502Sroot { 14437502Sroot register char *cp; 14447502Sroot char *nextc(); 14457502Sroot int s; 14467502Sroot 14479578Ssam if (tp->t_rprntc != 0377) 14489578Ssam ttyecho(tp->t_rprntc, tp); 14497502Sroot (void) ttyoutput('\n', tp); 14507502Sroot s = spl5(); 14517502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14527502Sroot ttyecho(*cp, tp); 14537502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14547502Sroot ttyecho(*cp, tp); 14559578Ssam tp->t_state &= ~TS_ERASE; 14567502Sroot splx(s); 14577502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14587502Sroot tp->t_rocol = 0; 14597502Sroot } 14607502Sroot 14617502Sroot /* 14627502Sroot * Echo a typed character to the terminal 14637502Sroot */ 14647502Sroot ttyecho(c, tp) 14657625Ssam register c; 14667625Ssam register struct tty *tp; 14677502Sroot { 14687502Sroot 14699578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14709578Ssam tp->t_flags &= ~FLUSHO; 14717502Sroot if ((tp->t_flags&ECHO) == 0) 14727502Sroot return; 14737502Sroot c &= 0377; 14747502Sroot if (tp->t_flags&RAW) { 14757502Sroot (void) ttyoutput(c, tp); 14767502Sroot return; 14777502Sroot } 14787502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14797502Sroot c = '\n'; 14809578Ssam if (tp->t_flags&CTLECH) { 14817502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14827502Sroot (void) ttyoutput('^', tp); 14837502Sroot c &= 0177; 14847502Sroot if (c == 0177) 14857502Sroot c = '?'; 14867502Sroot else if (tp->t_flags&LCASE) 14877502Sroot c += 'a' - 1; 14887502Sroot else 14897502Sroot c += 'A' - 1; 14907502Sroot } 14917502Sroot } 14927502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14937502Sroot c += 'a' - 'A'; 14949578Ssam (void) ttyoutput(c&0177, tp); 14957502Sroot } 14967502Sroot 14977502Sroot /* 14987502Sroot * Is c a break char for tp? 14997502Sroot */ 15007502Sroot ttbreakc(c, tp) 15017625Ssam register c; 15027625Ssam register struct tty *tp; 15037502Sroot { 15049578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15057502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15067502Sroot } 15077502Sroot 15087502Sroot /* 15097502Sroot * send string cp to tp 15107502Sroot */ 15117502Sroot ttyout(cp, tp) 15127625Ssam register char *cp; 15137625Ssam register struct tty *tp; 15147502Sroot { 15157502Sroot register char c; 15167502Sroot 15177502Sroot while (c = *cp++) 15187502Sroot (void) ttyoutput(c, tp); 15197502Sroot } 15207502Sroot 15217502Sroot ttwakeup(tp) 15227502Sroot struct tty *tp; 15237502Sroot { 15247502Sroot 15257502Sroot if (tp->t_rsel) { 15267502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15277502Sroot tp->t_state &= ~TS_RCOLL; 15287502Sroot tp->t_rsel = 0; 15297502Sroot } 153012752Ssam if (tp->t_state & TS_ASYNC) 153112752Ssam gsignal(tp->t_pgrp, SIGIO); 15327502Sroot wakeup((caddr_t)&tp->t_rawq); 15337502Sroot } 15347502Sroot 153513533Ssam #if !defined(vax) 15369578Ssam scanc(size, cp, table, mask) 15379578Ssam register int size; 15389578Ssam register char *cp, table[]; 15399578Ssam register int mask; 15407502Sroot { 15419578Ssam register int i = 0; 15427502Sroot 15439578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15449578Ssam i++; 154515100Skarels return (size - i); 15467502Sroot } 15479578Ssam #endif 1548