1*15720Skarels /* tty.c 6.8 83/12/16 */ 239Sbill 39760Ssam #include "../machine/reg.h" 49760Ssam 539Sbill #include "../h/param.h" 639Sbill #include "../h/systm.h" 739Sbill #include "../h/dir.h" 839Sbill #include "../h/user.h" 99578Ssam #include "../h/ioctl.h" 1039Sbill #include "../h/tty.h" 1139Sbill #include "../h/proc.h" 1239Sbill #include "../h/inode.h" 1339Sbill #include "../h/file.h" 1439Sbill #include "../h/conf.h" 1539Sbill #include "../h/buf.h" 16340Sbill #include "../h/dk.h" 177722Swnj #include "../h/uio.h" 188154Sroot #include "../h/kernel.h" 1939Sbill 207436Skre /* 217436Skre * Table giving parity for characters and indicating 227436Skre * character classes to tty driver. In particular, 237436Skre * if the low 6 bits are 0, then the character needs 247436Skre * no special processing on output. 257436Skre */ 2639Sbill 277436Skre char partab[] = { 287436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 297436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 307436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 317436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 327436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 407436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 447436Skre 457436Skre /* 467436Skre * 7 bit ascii ends with the last character above, 477436Skre * but we contine through all 256 codes for the sake 487436Skre * of the tty output routines which use special vax 497436Skre * instructions which need a 256 character trt table. 507436Skre */ 517436Skre 527436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 537436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 547436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 557436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 567436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 577436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007 687436Skre }; 697436Skre 70146Sbill /* 7139Sbill * Input mapping table-- if an entry is non-zero, when the 7239Sbill * corresponding character is typed preceded by "\" the escape 7339Sbill * sequence is replaced by the table value. Mostly used for 7439Sbill * upper-case only terminals. 7539Sbill */ 7639Sbill char maptab[] ={ 7739Sbill 000,000,000,000,000,000,000,000, 7839Sbill 000,000,000,000,000,000,000,000, 7939Sbill 000,000,000,000,000,000,000,000, 8039Sbill 000,000,000,000,000,000,000,000, 8139Sbill 000,'|',000,000,000,000,000,'`', 8239Sbill '{','}',000,000,000,000,000,000, 8339Sbill 000,000,000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,000,000,000,000,000,000,000, 8639Sbill 000,000,000,000,000,000,000,000, 8739Sbill 000,000,000,000,000,000,000,000, 8839Sbill 000,000,000,000,000,000,'~',000, 8939Sbill 000,'A','B','C','D','E','F','G', 9039Sbill 'H','I','J','K','L','M','N','O', 9139Sbill 'P','Q','R','S','T','U','V','W', 9239Sbill 'X','Y','Z',000,000,000,000,000, 9339Sbill }; 9439Sbill 95925Sbill short tthiwat[16] = 968954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 97925Sbill short ttlowat[16] = 98925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 99925Sbill 1009578Ssam struct ttychars ttydefaults = { 1019578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1029578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1039578Ssam }; 10439Sbill 10539Sbill ttychars(tp) 1069578Ssam struct tty *tp; 10739Sbill { 108174Sbill 1099578Ssam tp->t_chars = ttydefaults; 11039Sbill } 11139Sbill 11239Sbill /* 113903Sbill * Wait for output to drain, then flush input waiting. 11439Sbill */ 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 ; 161903Sbill tp->t_delct = 0; 1629578Ssam tp->t_rocount = 0; 163903Sbill tp->t_rocol = 0; 1649578Ssam tp->t_state &= ~TS_LOCAL; 165903Sbill } 166903Sbill splx(s); 16739Sbill } 16839Sbill 169903Sbill /* 170903Sbill * Send stop character on input overflow. 171903Sbill */ 172903Sbill ttyblock(tp) 1737625Ssam register struct tty *tp; 17439Sbill { 175903Sbill register x; 1769578Ssam 177903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 178903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 17912752Ssam ttyflush(tp, FREAD|FWRITE); 1805408Swnj tp->t_state &= ~TS_TBLOCK; 181903Sbill } 18215118Skarels /* 18315118Skarels * Block further input iff: 18415118Skarels * Current input > threshold AND input is available to user program 18515118Skarels */ 18615118Skarels if (x >= TTYHOG/2 && (tp->t_delct>0 || (tp->t_flags&(RAW|CBREAK)))) { 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: 3639325Ssam if (u.u_uid && u.u_ttyp != tp) 3649325Ssam return (EACCES); 3659578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3669325Ssam break; 3679325Ssam 36812752Ssam case TIOCSETP: 36912752Ssam case TIOCSETN: { 37012752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37112752Ssam 37212752Ssam tp->t_erase = sg->sg_erase; 37312752Ssam tp->t_kill = sg->sg_kill; 37412752Ssam tp->t_ispeed = sg->sg_ispeed; 37512752Ssam tp->t_ospeed = sg->sg_ospeed; 37612752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37712752Ssam s = spl5(); 37812752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 37912752Ssam ttywait(tp); 38012752Ssam ttyflush(tp, FREAD); 38112752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38212752Ssam if (newflags&CBREAK) { 38312752Ssam struct clist tq; 38412752Ssam 38512752Ssam catq(&tp->t_rawq, &tp->t_canq); 38612752Ssam tq = tp->t_rawq; 38712752Ssam tp->t_rawq = tp->t_canq; 38812752Ssam tp->t_canq = tq; 38912752Ssam } else { 39012752Ssam tp->t_flags |= PENDIN; 39113801Ssam newflags |= PENDIN; 39212752Ssam ttwakeup(tp); 39312752Ssam } 39412752Ssam } 39512752Ssam tp->t_flags = newflags; 39612752Ssam if (tp->t_flags&RAW) { 39712752Ssam tp->t_state &= ~TS_TTSTOP; 39812752Ssam ttstart(tp); 39912752Ssam } 40012752Ssam splx(s); 40112752Ssam break; 40212752Ssam } 40312752Ssam 40412752Ssam /* send current parameters to user */ 40512752Ssam case TIOCGETP: { 40612752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40712752Ssam 40812752Ssam sg->sg_ispeed = tp->t_ispeed; 40912752Ssam sg->sg_ospeed = tp->t_ospeed; 41012752Ssam sg->sg_erase = tp->t_erase; 41112752Ssam sg->sg_kill = tp->t_kill; 41212752Ssam sg->sg_flags = tp->t_flags; 41312752Ssam break; 41412752Ssam } 41512752Ssam 41612752Ssam case FIONBIO: 41712752Ssam if (*(int *)data) 41812752Ssam tp->t_state |= TS_NBIO; 41912752Ssam else 42012752Ssam tp->t_state &= ~TS_NBIO; 42112752Ssam break; 42212752Ssam 42312752Ssam case FIOASYNC: 42412752Ssam if (*(int *)data) 42512752Ssam tp->t_state |= TS_ASYNC; 42612752Ssam else 42712752Ssam tp->t_state &= ~TS_ASYNC; 42812752Ssam break; 42912752Ssam 43013077Ssam case TIOCGETC: 43113077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43213077Ssam break; 43313077Ssam 43413077Ssam case TIOCSETC: 43513077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43613077Ssam break; 43713077Ssam 43812752Ssam /* set/get local special characters */ 43912752Ssam case TIOCSLTC: 44012752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44112752Ssam break; 44212752Ssam 44312752Ssam case TIOCGLTC: 44412752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44512752Ssam break; 44612752Ssam 44712752Ssam /* 44812752Ssam * Modify local mode word. 44912752Ssam */ 45012752Ssam case TIOCLBIS: 45112752Ssam tp->t_flags |= *(int *)data << 16; 45212752Ssam break; 45312752Ssam 45412752Ssam case TIOCLBIC: 45512752Ssam tp->t_flags &= ~(*(int *)data << 16); 45612752Ssam break; 45712752Ssam 45812752Ssam case TIOCLSET: 45912752Ssam tp->t_flags &= 0xffff; 46012752Ssam tp->t_flags |= *(int *)data << 16; 46112752Ssam break; 46212752Ssam 46312752Ssam case TIOCLGET: 464*15720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46512752Ssam break; 46612752Ssam 46712752Ssam /* should allow SPGRP and GPGRP only if tty open for reading */ 46812752Ssam case TIOCSPGRP: 46912752Ssam tp->t_pgrp = *(int *)data; 47012752Ssam break; 47112752Ssam 47212752Ssam case TIOCGPGRP: 47312752Ssam *(int *)data = tp->t_pgrp; 47412752Ssam break; 47512752Ssam 47639Sbill default: 4778556Sroot return (-1); 47839Sbill } 4798556Sroot return (0); 48039Sbill } 4814484Swnj 4824484Swnj ttnread(tp) 4834484Swnj struct tty *tp; 4844484Swnj { 4854484Swnj int nread = 0; 4864484Swnj 4879578Ssam if (tp->t_flags & PENDIN) 4884484Swnj ttypend(tp); 4894484Swnj nread = tp->t_canq.c_cc; 4904484Swnj if (tp->t_flags & (RAW|CBREAK)) 4914484Swnj nread += tp->t_rawq.c_cc; 4924484Swnj return (nread); 4934484Swnj } 4944484Swnj 4955408Swnj ttselect(dev, rw) 4964484Swnj dev_t dev; 4975408Swnj int rw; 4984484Swnj { 4994484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5004484Swnj int nread; 5015408Swnj int s = spl5(); 5024484Swnj 5035408Swnj switch (rw) { 5044484Swnj 5054484Swnj case FREAD: 5064484Swnj nread = ttnread(tp); 5074484Swnj if (nread > 0) 5085408Swnj goto win; 5094938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5105408Swnj tp->t_state |= TS_RCOLL; 5114484Swnj else 5124484Swnj tp->t_rsel = u.u_procp; 5135408Swnj break; 5144484Swnj 5155408Swnj case FWRITE: 5165408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5175408Swnj goto win; 5185408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5195408Swnj tp->t_state |= TS_WCOLL; 5205408Swnj else 5215408Swnj tp->t_wsel = u.u_procp; 5225408Swnj break; 5234484Swnj } 5245408Swnj splx(s); 5255408Swnj return (0); 5265408Swnj win: 5275408Swnj splx(s); 5285408Swnj return (1); 5294484Swnj } 5307436Skre 5317502Sroot /* 5329578Ssam * Establish a process group for distribution of 5337502Sroot * quits and interrupts from the tty. 5347502Sroot */ 5357502Sroot ttyopen(dev, tp) 5367625Ssam dev_t dev; 5377625Ssam register struct tty *tp; 5387502Sroot { 5397502Sroot register struct proc *pp; 5407502Sroot 5417502Sroot pp = u.u_procp; 5427502Sroot tp->t_dev = dev; 5437625Ssam if (pp->p_pgrp == 0) { 5447502Sroot u.u_ttyp = tp; 5457502Sroot u.u_ttyd = dev; 5467502Sroot if (tp->t_pgrp == 0) 5477502Sroot tp->t_pgrp = pp->p_pid; 5487502Sroot pp->p_pgrp = tp->t_pgrp; 5497502Sroot } 5507502Sroot tp->t_state &= ~TS_WOPEN; 5517502Sroot tp->t_state |= TS_ISOPEN; 5527502Sroot if (tp->t_line != NTTYDISC) 55312752Ssam ttywflush(tp); 5548556Sroot return (0); 5557502Sroot } 5567502Sroot 5577502Sroot /* 5587502Sroot * clean tp on last close 5597502Sroot */ 5607502Sroot ttyclose(tp) 5617625Ssam register struct tty *tp; 5627502Sroot { 5637502Sroot 5647502Sroot if (tp->t_line) { 56512752Ssam ttywflush(tp); 5667502Sroot tp->t_line = 0; 5677502Sroot return; 5687502Sroot } 5697502Sroot tp->t_pgrp = 0; 57012752Ssam ttywflush(tp); 5717502Sroot tp->t_state = 0; 5727502Sroot } 5737502Sroot 5747502Sroot /* 5757502Sroot * reinput pending characters after state switch 5767502Sroot * call at spl5(). 5777502Sroot */ 5787502Sroot ttypend(tp) 5797625Ssam register struct tty *tp; 5807502Sroot { 5817502Sroot struct clist tq; 5827502Sroot register c; 5837502Sroot 5849578Ssam tp->t_flags &= ~PENDIN; 5859578Ssam tp->t_state |= TS_TYPEN; 5867502Sroot tq = tp->t_rawq; 5877502Sroot tp->t_rawq.c_cc = 0; 5887502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5897502Sroot while ((c = getc(&tq)) >= 0) 5907502Sroot ttyinput(c, tp); 5919578Ssam tp->t_state &= ~TS_TYPEN; 5927502Sroot } 5937502Sroot 5947502Sroot /* 5959578Ssam * Place a character on raw TTY input queue, 5969578Ssam * putting in delimiters and waking up top 5979578Ssam * half as needed. Also echo if required. 5989578Ssam * The arguments are the character and the 5999578Ssam * appropriate tty structure. 6007502Sroot */ 6017502Sroot ttyinput(c, tp) 6027625Ssam register c; 6037625Ssam register struct tty *tp; 6047502Sroot { 6059578Ssam register int t_flags = tp->t_flags; 6067502Sroot int i; 6077502Sroot 6089578Ssam /* 6099578Ssam * If input is pending take it first. 6109578Ssam */ 6119578Ssam if (t_flags&PENDIN) 6127502Sroot ttypend(tp); 6137502Sroot tk_nin++; 6147502Sroot c &= 0377; 6159578Ssam 6169578Ssam /* 6179578Ssam * In tandem mode, check high water mark. 6189578Ssam */ 6197502Sroot if (t_flags&TANDEM) 6207502Sroot ttyblock(tp); 6219578Ssam 6229578Ssam if (t_flags&RAW) { 6239578Ssam /* 6249578Ssam * Raw mode, just put character 6259578Ssam * in input q w/o interpretation. 6269578Ssam */ 6279578Ssam if (tp->t_rawq.c_cc > TTYHOG) 62812752Ssam ttyflush(tp, FREAD|FWRITE); 6299578Ssam else { 6309578Ssam if (putc(c, &tp->t_rawq) >= 0) 6319578Ssam ttwakeup(tp); 6329578Ssam ttyecho(c, tp); 6337502Sroot } 6349578Ssam goto endcase; 6359578Ssam } 6369578Ssam 6379578Ssam /* 6389578Ssam * Ignore any high bit added during 6399578Ssam * previous ttyinput processing. 6409578Ssam */ 6419578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6429578Ssam c &= 0177; 6439578Ssam /* 6449578Ssam * Check for literal nexting very first 6459578Ssam */ 6469578Ssam if (tp->t_state&TS_LNCH) { 6479578Ssam c |= 0200; 6489578Ssam tp->t_state &= ~TS_LNCH; 6499578Ssam } 6509578Ssam 6519578Ssam /* 6529578Ssam * Scan for special characters. This code 6539578Ssam * is really just a big case statement with 6549578Ssam * non-constant cases. The bottom of the 6559578Ssam * case statement is labeled ``endcase'', so goto 6569578Ssam * it after a case match, or similar. 6579578Ssam */ 6589578Ssam if (tp->t_line == NTTYDISC) { 6599578Ssam if (c == tp->t_lnextc) { 6607502Sroot if (tp->t_flags&ECHO) 6617502Sroot ttyout("^\b", tp); 6629578Ssam tp->t_state |= TS_LNCH; 6639578Ssam goto endcase; 6649578Ssam } 6659578Ssam if (c == tp->t_flushc) { 6669578Ssam if (tp->t_flags&FLUSHO) 6679578Ssam tp->t_flags &= ~FLUSHO; 6687502Sroot else { 66912752Ssam ttyflush(tp, FWRITE); 6707502Sroot ttyecho(c, tp); 6719578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6727502Sroot ttyretype(tp); 6739578Ssam tp->t_flags |= FLUSHO; 6747502Sroot } 6759578Ssam goto startoutput; 6769578Ssam } 6779578Ssam if (c == tp->t_suspc) { 6789578Ssam if ((tp->t_flags&NOFLSH) == 0) 67912752Ssam ttyflush(tp, FREAD); 6809578Ssam ttyecho(c, tp); 6819578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6829578Ssam goto endcase; 6839578Ssam } 6849578Ssam } 6859578Ssam 6869578Ssam /* 6879578Ssam * Handle start/stop characters. 6889578Ssam */ 6899578Ssam if (c == tp->t_stopc) { 6909578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6919578Ssam tp->t_state |= TS_TTSTOP; 6929578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6937502Sroot return; 6949578Ssam } 6959578Ssam if (c != tp->t_startc) 6969578Ssam return; 6979578Ssam goto endcase; 6989578Ssam } 6999578Ssam if (c == tp->t_startc) 7009578Ssam goto restartoutput; 7019578Ssam 7029578Ssam /* 7039578Ssam * Look for interrupt/quit chars. 7049578Ssam */ 7059578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7069578Ssam if ((tp->t_flags&NOFLSH) == 0) 70712752Ssam ttyflush(tp, FREAD|FWRITE); 7089578Ssam ttyecho(c, tp); 7099578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7109578Ssam goto endcase; 7119578Ssam } 7129578Ssam 7139578Ssam /* 7149578Ssam * Cbreak mode, don't process line editing 7159578Ssam * characters; check high water mark for wakeup. 7169578Ssam */ 7179578Ssam if (t_flags&CBREAK) { 7189578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7197502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7207502Sroot tp->t_line == NTTYDISC) 7217502Sroot (void) ttyoutput(CTRL(g), tp); 7227502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7237502Sroot ttwakeup(tp); 7247502Sroot ttyecho(c, tp); 7257502Sroot } 7269578Ssam goto endcase; 7279578Ssam } 7289578Ssam 7299578Ssam /* 7309578Ssam * From here on down cooked mode character 7319578Ssam * processing takes place. 7329578Ssam */ 7339578Ssam if ((tp->t_state&TS_QUOT) && 7349578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7359578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7369578Ssam c |= 0200; 7379578Ssam } 7389578Ssam if (c == tp->t_erase) { 7399578Ssam if (tp->t_rawq.c_cc) 7409578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7419578Ssam goto endcase; 7429578Ssam } 7439578Ssam if (c == tp->t_kill) { 7449578Ssam if (tp->t_flags&CRTKIL && 7459578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7469578Ssam while (tp->t_rawq.c_cc) 7479578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7489578Ssam } else { 7499578Ssam ttyecho(c, tp); 7509578Ssam ttyecho('\n', tp); 7519578Ssam while (getc(&tp->t_rawq) > 0) 7529578Ssam ; 7539578Ssam tp->t_rocount = 0; 7549578Ssam } 7559578Ssam tp->t_state &= ~TS_LOCAL; 7569578Ssam goto endcase; 7579578Ssam } 7589578Ssam 7599578Ssam /* 7609578Ssam * New line discipline, 7619578Ssam * check word erase/reprint line. 7629578Ssam */ 7639578Ssam if (tp->t_line == NTTYDISC) { 7649578Ssam if (c == tp->t_werasc) { 7659578Ssam if (tp->t_rawq.c_cc == 0) 7669578Ssam goto endcase; 7679578Ssam do { 7689578Ssam c = unputc(&tp->t_rawq); 7699578Ssam if (c != ' ' && c != '\t') 7709578Ssam goto erasenb; 7719578Ssam ttyrub(c, tp); 7729578Ssam } while (tp->t_rawq.c_cc); 7739578Ssam goto endcase; 7749578Ssam erasenb: 7759578Ssam do { 7769578Ssam ttyrub(c, tp); 7779578Ssam if (tp->t_rawq.c_cc == 0) 7789578Ssam goto endcase; 7799578Ssam c = unputc(&tp->t_rawq); 7809578Ssam } while (c != ' ' && c != '\t'); 7819578Ssam (void) putc(c, &tp->t_rawq); 7829578Ssam goto endcase; 7839578Ssam } 7849578Ssam if (c == tp->t_rprntc) { 7859578Ssam ttyretype(tp); 7869578Ssam goto endcase; 7879578Ssam } 7889578Ssam } 7899578Ssam 7909578Ssam /* 7919578Ssam * Check for input buffer overflow 7929578Ssam */ 79310391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 79410391Ssam if (tp->t_line == NTTYDISC) 79510391Ssam (void) ttyoutput(CTRL(g), tp); 7969578Ssam goto endcase; 79710391Ssam } 7989578Ssam 7999578Ssam /* 8009578Ssam * Put data char in q for user and 8019578Ssam * wakeup on seeing a line delimiter. 8029578Ssam */ 8039578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8049578Ssam if (ttbreakc(c, tp)) { 8059578Ssam tp->t_rocount = 0; 8069578Ssam catq(&tp->t_rawq, &tp->t_canq); 8077502Sroot ttwakeup(tp); 8089578Ssam } else if (tp->t_rocount++ == 0) 8099578Ssam tp->t_rocol = tp->t_col; 8109578Ssam tp->t_state &= ~TS_QUOT; 8119578Ssam if (c == '\\') 8129578Ssam tp->t_state |= TS_QUOT; 8139578Ssam if (tp->t_state&TS_ERASE) { 8149578Ssam tp->t_state &= ~TS_ERASE; 8159578Ssam (void) ttyoutput('/', tp); 8169578Ssam } 8179578Ssam i = tp->t_col; 8187502Sroot ttyecho(c, tp); 8199578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8209578Ssam i = MIN(2, tp->t_col - i); 8219578Ssam while (i > 0) { 8229578Ssam (void) ttyoutput('\b', tp); 8239578Ssam i--; 8249578Ssam } 8259578Ssam } 8267502Sroot } 8279578Ssam 8289578Ssam endcase: 8299578Ssam /* 8309578Ssam * If DEC-style start/stop is enabled don't restart 8319578Ssam * output until seeing the start character. 8329578Ssam */ 8339578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8349578Ssam tp->t_startc != tp->t_stopc) 8357502Sroot return; 8369578Ssam 8379578Ssam restartoutput: 8387502Sroot tp->t_state &= ~TS_TTSTOP; 8399578Ssam tp->t_flags &= ~FLUSHO; 8409578Ssam 8419578Ssam startoutput: 8427502Sroot ttstart(tp); 8437502Sroot } 8447502Sroot 8457502Sroot /* 8469578Ssam * Put character on TTY output queue, adding delays, 8477502Sroot * expanding tabs, and handling the CR/NL bit. 8489578Ssam * This is called both from the top half for output, 8499578Ssam * and from interrupt level for echoing. 8507502Sroot * The arguments are the character and the tty structure. 8517502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8527502Sroot * Must be recursive. 8537502Sroot */ 8547502Sroot ttyoutput(c, tp) 8557502Sroot register c; 8567502Sroot register struct tty *tp; 8577502Sroot { 8587502Sroot register char *colp; 8597502Sroot register ctype; 8607502Sroot 8619578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8629578Ssam if (tp->t_flags&FLUSHO) 8637502Sroot return (-1); 8647502Sroot if (putc(c, &tp->t_outq)) 8657625Ssam return (c); 8667502Sroot tk_nout++; 8677502Sroot return (-1); 8687502Sroot } 8699578Ssam 8707502Sroot /* 8719578Ssam * Ignore EOT in normal mode to avoid 8729578Ssam * hanging up certain terminals. 8737502Sroot */ 8747502Sroot c &= 0177; 8759578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8767502Sroot return (-1); 8777502Sroot /* 8787502Sroot * Turn tabs to spaces as required 8797502Sroot */ 8809578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8817502Sroot register int s; 8827502Sroot 8837502Sroot c = 8 - (tp->t_col&7); 8849578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8857502Sroot s = spl5(); /* don't interrupt tabs */ 8867502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8877502Sroot tk_nout += c; 8887502Sroot splx(s); 8897502Sroot } 8907502Sroot tp->t_col += c; 8917502Sroot return (c ? -1 : '\t'); 8927502Sroot } 8937502Sroot tk_nout++; 8947502Sroot /* 8957502Sroot * for upper-case-only terminals, 8967502Sroot * generate escapes. 8977502Sroot */ 8987502Sroot if (tp->t_flags&LCASE) { 8997502Sroot colp = "({)}!|^~'`"; 9007625Ssam while (*colp++) 9017625Ssam if (c == *colp++) { 9027502Sroot if (ttyoutput('\\', tp) >= 0) 9037502Sroot return (c); 9047502Sroot c = colp[-2]; 9057502Sroot break; 9067502Sroot } 9079578Ssam if ('A' <= c && c <= 'Z') { 9087502Sroot if (ttyoutput('\\', tp) >= 0) 9097502Sroot return (c); 9109578Ssam } else if ('a' <= c && c <= 'z') 9117502Sroot c += 'A' - 'a'; 9127502Sroot } 9139578Ssam 9147502Sroot /* 9157502Sroot * turn <nl> to <cr><lf> if desired. 9167502Sroot */ 9179578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9187502Sroot if (ttyoutput('\r', tp) >= 0) 9197502Sroot return (c); 9209578Ssam if (c == '~' && tp->t_flags&TILDE) 9217502Sroot c = '`'; 9229578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9237502Sroot return (c); 9247502Sroot /* 9257502Sroot * Calculate delays. 9267502Sroot * The numbers here represent clock ticks 9277502Sroot * and are not necessarily optimal for all terminals. 9287502Sroot * The delays are indicated by characters above 0200. 9297502Sroot * In raw mode there are no delays and the 9307502Sroot * transmission path is 8 bits wide. 9319578Ssam * 9329578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9337502Sroot */ 9347502Sroot colp = &tp->t_col; 9357502Sroot ctype = partab[c]; 9367502Sroot c = 0; 9377502Sroot switch (ctype&077) { 9387502Sroot 9397502Sroot case ORDINARY: 9407502Sroot (*colp)++; 9417502Sroot 9427502Sroot case CONTROL: 9437502Sroot break; 9447502Sroot 9457502Sroot case BACKSPACE: 9467502Sroot if (*colp) 9477502Sroot (*colp)--; 9487502Sroot break; 9497502Sroot 95013821Ssam /* 95113821Ssam * This macro is close enough to the correct thing; 95213821Ssam * it should be replaced by real user settable delays 95313821Ssam * in any event... 95413821Ssam */ 95513821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9567502Sroot case NEWLINE: 9577502Sroot ctype = (tp->t_flags >> 8) & 03; 9587625Ssam if (ctype == 1) { /* tty 37 */ 95912752Ssam if (*colp > 0) 96013863Ssam c = max((((unsigned)*colp) >> 4) + 3, 96113863Ssam (unsigned)6); 9629578Ssam } else if (ctype == 2) /* vt05 */ 96313821Ssam c = mstohz(100); 9647502Sroot *colp = 0; 9657502Sroot break; 9667502Sroot 9677502Sroot case TAB: 9687502Sroot ctype = (tp->t_flags >> 10) & 03; 9697625Ssam if (ctype == 1) { /* tty 37 */ 9707502Sroot c = 1 - (*colp | ~07); 9717625Ssam if (c < 5) 9727502Sroot c = 0; 9737502Sroot } 9747502Sroot *colp |= 07; 9757502Sroot (*colp)++; 9767502Sroot break; 9777502Sroot 9787502Sroot case VTAB: 9799578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9807502Sroot c = 0177; 9817502Sroot break; 9827502Sroot 9837502Sroot case RETURN: 9847502Sroot ctype = (tp->t_flags >> 12) & 03; 9859578Ssam if (ctype == 1) /* tn 300 */ 98613821Ssam c = mstohz(83); 9879578Ssam else if (ctype == 2) /* ti 700 */ 98813821Ssam c = mstohz(166); 9899578Ssam else if (ctype == 3) { /* concept 100 */ 9907502Sroot int i; 9919578Ssam 9927502Sroot if ((i = *colp) >= 0) 9939578Ssam for (; i < 9; i++) 9947502Sroot (void) putc(0177, &tp->t_outq); 9957502Sroot } 9967502Sroot *colp = 0; 9977502Sroot } 9989578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9997502Sroot (void) putc(c|0200, &tp->t_outq); 10007502Sroot return (-1); 10017502Sroot } 100213821Ssam #undef mstohz 10037502Sroot 10047502Sroot /* 10057502Sroot * Called from device's read routine after it has 10067502Sroot * calculated the tty-structure given as argument. 10077502Sroot */ 10087722Swnj ttread(tp, uio) 10097625Ssam register struct tty *tp; 10107722Swnj struct uio *uio; 10117502Sroot { 10127502Sroot register struct clist *qp; 10139578Ssam register c, t_flags; 10149859Ssam int s, first, error = 0; 10157502Sroot 10167502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10178520Sroot return (EIO); 10187502Sroot loop: 10199578Ssam /* 10209578Ssam * Take any pending input first. 10219578Ssam */ 10229859Ssam s = spl5(); 10239578Ssam if (tp->t_flags&PENDIN) 10247502Sroot ttypend(tp); 10259859Ssam splx(s); 10269578Ssam 10279578Ssam /* 10289578Ssam * Hang process if it's in the background. 10299578Ssam */ 103015141Skarels #define bit(a) (1<<(a-1)) 10317502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 103215141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 103315141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10347502Sroot /* 10357502Sroot (u.u_procp->p_flag&SDETACH) || 10367502Sroot */ 10377502Sroot u.u_procp->p_flag&SVFORK) 10388520Sroot return (EIO); 10397502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10407502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10417502Sroot } 10429578Ssam t_flags = tp->t_flags; 104315141Skarels #undef bit 10449578Ssam 10459578Ssam /* 10469578Ssam * In raw mode take characters directly from the 10479578Ssam * raw queue w/o processing. Interlock against 10489578Ssam * device interrupts when interrogating rawq. 10499578Ssam */ 10509578Ssam if (t_flags&RAW) { 10519859Ssam s = spl5(); 10527502Sroot if (tp->t_rawq.c_cc <= 0) { 10539578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10547502Sroot (tp->t_state&TS_NBIO)) { 10559859Ssam splx(s); 105615094Skarels return (EWOULDBLOCK); 10577502Sroot } 10587502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10599859Ssam splx(s); 10607502Sroot goto loop; 10617502Sroot } 10629859Ssam splx(s); 106314938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 106414938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10659859Ssam goto checktandem; 10669578Ssam } 10679578Ssam 10689578Ssam /* 10699578Ssam * In cbreak mode use the rawq, otherwise 10709578Ssam * take characters from the canonicalized q. 10719578Ssam */ 10729578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10739578Ssam 10749578Ssam /* 10759578Ssam * No input, sleep on rawq awaiting hardware 10769578Ssam * receipt and notification. 10779578Ssam */ 10789859Ssam s = spl5(); 10799578Ssam if (qp->c_cc <= 0) { 10809578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10819578Ssam (tp->t_state&TS_NBIO)) { 10829859Ssam splx(s); 10839578Ssam return (EWOULDBLOCK); 10847502Sroot } 10859578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10869859Ssam splx(s); 10879578Ssam goto loop; 10889578Ssam } 10899859Ssam splx(s); 10909578Ssam 10919578Ssam /* 10929578Ssam * Input present, perform input mapping 10939578Ssam * and processing (we're not in raw mode). 10949578Ssam */ 10959578Ssam first = 1; 10969578Ssam while ((c = getc(qp)) >= 0) { 10979578Ssam if (t_flags&CRMOD && c == '\r') 10989578Ssam c = '\n'; 10999578Ssam /* 11009578Ssam * Hack lower case simulation on 11019578Ssam * upper case only terminals. 11029578Ssam */ 11039578Ssam if (t_flags&LCASE && c <= 0177) 11049578Ssam if (tp->t_state&TS_BKSL) { 11059578Ssam if (maptab[c]) 11069578Ssam c = maptab[c]; 11079578Ssam tp->t_state &= ~TS_BKSL; 11089578Ssam } else if (c >= 'A' && c <= 'Z') 11099578Ssam c += 'a' - 'A'; 11109578Ssam else if (c == '\\') { 11119578Ssam tp->t_state |= TS_BKSL; 11129578Ssam continue; 11137502Sroot } 11149578Ssam /* 11159578Ssam * Check for delayed suspend character. 11169578Ssam */ 11179578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11189578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11199578Ssam if (first) { 11209578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11219578Ssam goto loop; 11229578Ssam } 11239578Ssam break; 11247502Sroot } 11259578Ssam /* 11269578Ssam * Interpret EOF only in cooked mode. 11279578Ssam */ 11289578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11299578Ssam break; 11309578Ssam /* 11319578Ssam * Give user character. 11329578Ssam */ 113314938Smckusick error = ureadc(c & 0177, uio); 11349578Ssam if (error) 11359578Ssam break; 113614938Smckusick if (uio->uio_resid == 0) 11379578Ssam break; 11389578Ssam /* 11399578Ssam * In cooked mode check for a "break character" 11409578Ssam * marking the end of a "line of input". 11419578Ssam */ 11429578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11439578Ssam break; 11449578Ssam first = 0; 11457502Sroot } 11469578Ssam tp->t_state &= ~TS_BKSL; 11479578Ssam 11489859Ssam checktandem: 11499578Ssam /* 11509578Ssam * Look to unblock output now that (presumably) 11519578Ssam * the input queue has gone down. 11529578Ssam */ 11539859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11549578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11557502Sroot tp->t_state &= ~TS_TBLOCK; 11567502Sroot ttstart(tp); 11577502Sroot } 11588520Sroot return (error); 11597502Sroot } 11607502Sroot 11617502Sroot /* 11627502Sroot * Called from the device's write routine after it has 11637502Sroot * calculated the tty-structure given as argument. 11647502Sroot */ 11657822Sroot ttwrite(tp, uio) 11667625Ssam register struct tty *tp; 11679578Ssam register struct uio *uio; 11687502Sroot { 11697502Sroot register char *cp; 11709578Ssam register int cc, ce, c; 11719578Ssam int i, hiwat, cnt, error, s; 11727502Sroot char obuf[OBUFSIZ]; 11737502Sroot 11749578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11758520Sroot return (EIO); 11769578Ssam hiwat = TTHIWAT(tp); 11779578Ssam cnt = uio->uio_resid; 11789578Ssam error = 0; 11797502Sroot loop: 11809578Ssam /* 11819578Ssam * Hang the process if it's in the background. 11829578Ssam */ 118315141Skarels #define bit(a) (1<<(a-1)) 11847502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11859578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 118615141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 118715141Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU)) 11887502Sroot /* 11897502Sroot && 11907502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11917502Sroot */ 11927502Sroot ) { 11937502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11947502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11957502Sroot } 119615141Skarels #undef bit 11979578Ssam 11989578Ssam /* 11999578Ssam * Process the user's data in at most OBUFSIZ 12009578Ssam * chunks. Perform lower case simulation and 12019578Ssam * similar hacks. Keep track of high water 12029578Ssam * mark, sleep on overflow awaiting device aid 12039578Ssam * in acquiring new space. 12049578Ssam */ 12057822Sroot while (uio->uio_resid > 0) { 12069578Ssam /* 12079578Ssam * Grab a hunk of data from the user. 12089578Ssam */ 12097822Sroot cc = uio->uio_iov->iov_len; 12107822Sroot if (cc == 0) { 12117822Sroot uio->uio_iovcnt--; 12127822Sroot uio->uio_iov++; 12137822Sroot if (uio->uio_iovcnt < 0) 12147822Sroot panic("ttwrite"); 12157822Sroot continue; 12167822Sroot } 12177822Sroot if (cc > OBUFSIZ) 12187822Sroot cc = OBUFSIZ; 12197502Sroot cp = obuf; 122012752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12218520Sroot if (error) 12227502Sroot break; 12237502Sroot if (tp->t_outq.c_cc > hiwat) 12247502Sroot goto ovhiwat; 12259578Ssam if (tp->t_flags&FLUSHO) 12267502Sroot continue; 12279578Ssam /* 12289578Ssam * If we're mapping lower case or kludging tildes, 12299578Ssam * then we've got to look at each character, so 12309578Ssam * just feed the stuff to ttyoutput... 12319578Ssam */ 12329578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12339578Ssam while (cc > 0) { 12347502Sroot c = *cp++; 12357502Sroot tp->t_rocount = 0; 12367625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12377502Sroot /* out of clists, wait a bit */ 12387502Sroot ttstart(tp); 12397502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12407502Sroot tp->t_rocount = 0; 12417502Sroot } 12427502Sroot --cc; 12437502Sroot if (tp->t_outq.c_cc > hiwat) 12447502Sroot goto ovhiwat; 12457502Sroot } 12467502Sroot continue; 12477502Sroot } 12489578Ssam /* 12499578Ssam * If nothing fancy need be done, grab those characters we 12509578Ssam * can handle without any of ttyoutput's processing and 12519578Ssam * just transfer them to the output q. For those chars 12529578Ssam * which require special processing (as indicated by the 12539578Ssam * bits in partab), call ttyoutput. After processing 12549578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12559578Ssam * immediately. 12569578Ssam */ 12579578Ssam while (cc > 0) { 12589578Ssam if (tp->t_flags & (RAW|LITOUT)) 12597502Sroot ce = cc; 12607502Sroot else { 126112752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 126212752Ssam (caddr_t)partab, 077); 12639578Ssam /* 12649578Ssam * If ce is zero, then we're processing 12659578Ssam * a special character through ttyoutput. 12669578Ssam */ 12679578Ssam if (ce == 0) { 12687502Sroot tp->t_rocount = 0; 12697502Sroot if (ttyoutput(*cp, tp) >= 0) { 12709578Ssam /* no c-lists, wait a bit */ 12717502Sroot ttstart(tp); 12727502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12737502Sroot continue; 12747502Sroot } 12759578Ssam cp++, cc--; 12769578Ssam if (tp->t_flags&FLUSHO || 12779578Ssam tp->t_outq.c_cc > hiwat) 12787502Sroot goto ovhiwat; 12799578Ssam continue; 12807502Sroot } 12817502Sroot } 12829578Ssam /* 12839578Ssam * A bunch of normal characters have been found, 12849578Ssam * transfer them en masse to the output queue and 12859578Ssam * continue processing at the top of the loop. 12869578Ssam * If there are any further characters in this 12879578Ssam * <= OBUFSIZ chunk, the first should be a character 12889578Ssam * requiring special handling by ttyoutput. 12899578Ssam */ 12907502Sroot tp->t_rocount = 0; 12919578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12929578Ssam ce -= i; 12939578Ssam tp->t_col += ce; 12949578Ssam cp += ce, cc -= ce, tk_nout += ce; 12959578Ssam if (i > 0) { 12969578Ssam /* out of c-lists, wait a bit */ 12977502Sroot ttstart(tp); 12987502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12997502Sroot } 13009578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13017502Sroot goto ovhiwat; 13027502Sroot } 13037502Sroot } 13047502Sroot ttstart(tp); 13058520Sroot return (error); 13067502Sroot 13077502Sroot ovhiwat: 13089578Ssam s = spl5(); 13099578Ssam if (cc != 0) { 13109578Ssam uio->uio_iov->iov_base -= cc; 13119578Ssam uio->uio_iov->iov_len += cc; 13129578Ssam uio->uio_resid += cc; 13139578Ssam uio->uio_offset -= cc; 13149578Ssam } 13159578Ssam /* 13169578Ssam * This can only occur if FLUSHO 13179578Ssam * is also set in t_flags. 13189578Ssam */ 13197502Sroot if (tp->t_outq.c_cc <= hiwat) { 13209578Ssam splx(s); 13217502Sroot goto loop; 13227502Sroot } 13237502Sroot ttstart(tp); 13249578Ssam if (tp->t_state&TS_NBIO) { 13257822Sroot if (uio->uio_resid == cnt) 13268520Sroot return (EWOULDBLOCK); 13278520Sroot return (0); 13287502Sroot } 13297502Sroot tp->t_state |= TS_ASLEEP; 13307502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13319578Ssam splx(s); 13327502Sroot goto loop; 13337502Sroot } 13347502Sroot 13357502Sroot /* 13367502Sroot * Rubout one character from the rawq of tp 13377502Sroot * as cleanly as possible. 13387502Sroot */ 13397502Sroot ttyrub(c, tp) 13407625Ssam register c; 13417625Ssam register struct tty *tp; 13427502Sroot { 13437502Sroot register char *cp; 13447502Sroot register int savecol; 13457502Sroot int s; 13467502Sroot char *nextc(); 13477502Sroot 13489578Ssam if ((tp->t_flags&ECHO) == 0) 13497502Sroot return; 13509578Ssam tp->t_flags &= ~FLUSHO; 13517502Sroot c &= 0377; 13529578Ssam if (tp->t_flags&CRTBS) { 13537502Sroot if (tp->t_rocount == 0) { 13547502Sroot /* 13557502Sroot * Screwed by ttwrite; retype 13567502Sroot */ 13577502Sroot ttyretype(tp); 13587502Sroot return; 13597502Sroot } 13609578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13617502Sroot ttyrubo(tp, 2); 13629578Ssam else switch (partab[c&=0177]&0177) { 13637502Sroot 13647502Sroot case ORDINARY: 13657502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13667502Sroot ttyrubo(tp, 2); 13677502Sroot else 13687502Sroot ttyrubo(tp, 1); 13697502Sroot break; 13707502Sroot 13717502Sroot case VTAB: 13727502Sroot case BACKSPACE: 13737502Sroot case CONTROL: 13747502Sroot case RETURN: 13759578Ssam if (tp->t_flags&CTLECH) 13767502Sroot ttyrubo(tp, 2); 13777502Sroot break; 13787502Sroot 13797502Sroot case TAB: 13807502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13817502Sroot ttyretype(tp); 13827502Sroot return; 13837502Sroot } 13847502Sroot s = spl5(); 13857502Sroot savecol = tp->t_col; 13869578Ssam tp->t_state |= TS_CNTTB; 13879578Ssam tp->t_flags |= FLUSHO; 13887502Sroot tp->t_col = tp->t_rocol; 13899578Ssam cp = tp->t_rawq.c_cf; 13909578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13917502Sroot ttyecho(*cp, tp); 13929578Ssam tp->t_flags &= ~FLUSHO; 13939578Ssam tp->t_state &= ~TS_CNTTB; 13947502Sroot splx(s); 13957502Sroot /* 13967502Sroot * savecol will now be length of the tab 13977502Sroot */ 13987502Sroot savecol -= tp->t_col; 13997502Sroot tp->t_col += savecol; 14007502Sroot if (savecol > 8) 14017502Sroot savecol = 8; /* overflow screw */ 14027502Sroot while (--savecol >= 0) 14037502Sroot (void) ttyoutput('\b', tp); 14047502Sroot break; 14057502Sroot 14067502Sroot default: 14077502Sroot panic("ttyrub"); 14087502Sroot } 14099578Ssam } else if (tp->t_flags&PRTERA) { 14109578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14117502Sroot (void) ttyoutput('\\', tp); 14129578Ssam tp->t_state |= TS_ERASE; 14137502Sroot } 14147502Sroot ttyecho(c, tp); 14157502Sroot } else 14167502Sroot ttyecho(tp->t_erase, tp); 14177502Sroot tp->t_rocount--; 14187502Sroot } 14197502Sroot 14207502Sroot /* 14217502Sroot * Crt back over cnt chars perhaps 14227502Sroot * erasing them. 14237502Sroot */ 14247502Sroot ttyrubo(tp, cnt) 14257625Ssam register struct tty *tp; 14267625Ssam int cnt; 14277502Sroot { 14289578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14297502Sroot 14307502Sroot while (--cnt >= 0) 14319578Ssam ttyout(rubostring, tp); 14327502Sroot } 14337502Sroot 14347502Sroot /* 14357502Sroot * Reprint the rawq line. 14367502Sroot * We assume c_cc has already been checked. 14377502Sroot */ 14387502Sroot ttyretype(tp) 14397625Ssam register struct tty *tp; 14407502Sroot { 14417502Sroot register char *cp; 14427502Sroot char *nextc(); 14437502Sroot int s; 14447502Sroot 14459578Ssam if (tp->t_rprntc != 0377) 14469578Ssam ttyecho(tp->t_rprntc, tp); 14477502Sroot (void) ttyoutput('\n', tp); 14487502Sroot s = spl5(); 14497502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14507502Sroot ttyecho(*cp, tp); 14517502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14527502Sroot ttyecho(*cp, tp); 14539578Ssam tp->t_state &= ~TS_ERASE; 14547502Sroot splx(s); 14557502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14567502Sroot tp->t_rocol = 0; 14577502Sroot } 14587502Sroot 14597502Sroot /* 14607502Sroot * Echo a typed character to the terminal 14617502Sroot */ 14627502Sroot ttyecho(c, tp) 14637625Ssam register c; 14647625Ssam register struct tty *tp; 14657502Sroot { 14667502Sroot 14679578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14689578Ssam tp->t_flags &= ~FLUSHO; 14697502Sroot if ((tp->t_flags&ECHO) == 0) 14707502Sroot return; 14717502Sroot c &= 0377; 14727502Sroot if (tp->t_flags&RAW) { 14737502Sroot (void) ttyoutput(c, tp); 14747502Sroot return; 14757502Sroot } 14767502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14777502Sroot c = '\n'; 14789578Ssam if (tp->t_flags&CTLECH) { 14797502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14807502Sroot (void) ttyoutput('^', tp); 14817502Sroot c &= 0177; 14827502Sroot if (c == 0177) 14837502Sroot c = '?'; 14847502Sroot else if (tp->t_flags&LCASE) 14857502Sroot c += 'a' - 1; 14867502Sroot else 14877502Sroot c += 'A' - 1; 14887502Sroot } 14897502Sroot } 14907502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14917502Sroot c += 'a' - 'A'; 14929578Ssam (void) ttyoutput(c&0177, tp); 14937502Sroot } 14947502Sroot 14957502Sroot /* 14967502Sroot * Is c a break char for tp? 14977502Sroot */ 14987502Sroot ttbreakc(c, tp) 14997625Ssam register c; 15007625Ssam register struct tty *tp; 15017502Sroot { 15029578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15037502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15047502Sroot } 15057502Sroot 15067502Sroot /* 15077502Sroot * send string cp to tp 15087502Sroot */ 15097502Sroot ttyout(cp, tp) 15107625Ssam register char *cp; 15117625Ssam register struct tty *tp; 15127502Sroot { 15137502Sroot register char c; 15147502Sroot 15157502Sroot while (c = *cp++) 15167502Sroot (void) ttyoutput(c, tp); 15177502Sroot } 15187502Sroot 15197502Sroot ttwakeup(tp) 15207502Sroot struct tty *tp; 15217502Sroot { 15227502Sroot 15237502Sroot if (tp->t_rsel) { 15247502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15257502Sroot tp->t_state &= ~TS_RCOLL; 15267502Sroot tp->t_rsel = 0; 15277502Sroot } 152812752Ssam if (tp->t_state & TS_ASYNC) 152912752Ssam gsignal(tp->t_pgrp, SIGIO); 15307502Sroot wakeup((caddr_t)&tp->t_rawq); 15317502Sroot } 15327502Sroot 153313533Ssam #if !defined(vax) 15349578Ssam scanc(size, cp, table, mask) 15359578Ssam register int size; 15369578Ssam register char *cp, table[]; 15379578Ssam register int mask; 15387502Sroot { 15399578Ssam register int i = 0; 15407502Sroot 15419578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15429578Ssam i++; 154315100Skarels return (size - i); 15447502Sroot } 15459578Ssam #endif 1546