1*15118Skarels /* tty.c 6.6 83/09/28 */ 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 } 182*15118Skarels /* 183*15118Skarels * Block further input iff: 184*15118Skarels * Current input > threshold AND input is available to user program 185*15118Skarels */ 186*15118Skarels if (x >= TTYHOG/2 && (tp->t_delct>0 || (tp->t_flags&(RAW|CBREAK)))) { 187*15118Skarels if (putc(tp->t_stopc, &tp->t_outq)==0) { 188*15118Skarels tp->t_state |= TS_TBLOCK; 189*15118Skarels ttstart(tp); 190*15118Skarels } 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: 46412752Ssam *(int *)data = 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 */ 10307502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10317502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10327502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10337502Sroot /* 10347502Sroot (u.u_procp->p_flag&SDETACH) || 10357502Sroot */ 10367502Sroot u.u_procp->p_flag&SVFORK) 10378520Sroot return (EIO); 10387502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10397502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10407502Sroot } 10419578Ssam t_flags = tp->t_flags; 10429578Ssam 10439578Ssam /* 10449578Ssam * In raw mode take characters directly from the 10459578Ssam * raw queue w/o processing. Interlock against 10469578Ssam * device interrupts when interrogating rawq. 10479578Ssam */ 10489578Ssam if (t_flags&RAW) { 10499859Ssam s = spl5(); 10507502Sroot if (tp->t_rawq.c_cc <= 0) { 10519578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10527502Sroot (tp->t_state&TS_NBIO)) { 10539859Ssam splx(s); 105415094Skarels return (EWOULDBLOCK); 10557502Sroot } 10567502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10579859Ssam splx(s); 10587502Sroot goto loop; 10597502Sroot } 10609859Ssam splx(s); 106114938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 106214938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10639859Ssam goto checktandem; 10649578Ssam } 10659578Ssam 10669578Ssam /* 10679578Ssam * In cbreak mode use the rawq, otherwise 10689578Ssam * take characters from the canonicalized q. 10699578Ssam */ 10709578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10719578Ssam 10729578Ssam /* 10739578Ssam * No input, sleep on rawq awaiting hardware 10749578Ssam * receipt and notification. 10759578Ssam */ 10769859Ssam s = spl5(); 10779578Ssam if (qp->c_cc <= 0) { 10789578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10799578Ssam (tp->t_state&TS_NBIO)) { 10809859Ssam splx(s); 10819578Ssam return (EWOULDBLOCK); 10827502Sroot } 10839578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10849859Ssam splx(s); 10859578Ssam goto loop; 10869578Ssam } 10879859Ssam splx(s); 10889578Ssam 10899578Ssam /* 10909578Ssam * Input present, perform input mapping 10919578Ssam * and processing (we're not in raw mode). 10929578Ssam */ 10939578Ssam first = 1; 10949578Ssam while ((c = getc(qp)) >= 0) { 10959578Ssam if (t_flags&CRMOD && c == '\r') 10969578Ssam c = '\n'; 10979578Ssam /* 10989578Ssam * Hack lower case simulation on 10999578Ssam * upper case only terminals. 11009578Ssam */ 11019578Ssam if (t_flags&LCASE && c <= 0177) 11029578Ssam if (tp->t_state&TS_BKSL) { 11039578Ssam if (maptab[c]) 11049578Ssam c = maptab[c]; 11059578Ssam tp->t_state &= ~TS_BKSL; 11069578Ssam } else if (c >= 'A' && c <= 'Z') 11079578Ssam c += 'a' - 'A'; 11089578Ssam else if (c == '\\') { 11099578Ssam tp->t_state |= TS_BKSL; 11109578Ssam continue; 11117502Sroot } 11129578Ssam /* 11139578Ssam * Check for delayed suspend character. 11149578Ssam */ 11159578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11169578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11179578Ssam if (first) { 11189578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11199578Ssam goto loop; 11209578Ssam } 11219578Ssam break; 11227502Sroot } 11239578Ssam /* 11249578Ssam * Interpret EOF only in cooked mode. 11259578Ssam */ 11269578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11279578Ssam break; 11289578Ssam /* 11299578Ssam * Give user character. 11309578Ssam */ 113114938Smckusick error = ureadc(c & 0177, uio); 11329578Ssam if (error) 11339578Ssam break; 113414938Smckusick if (uio->uio_resid == 0) 11359578Ssam break; 11369578Ssam /* 11379578Ssam * In cooked mode check for a "break character" 11389578Ssam * marking the end of a "line of input". 11399578Ssam */ 11409578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11419578Ssam break; 11429578Ssam first = 0; 11437502Sroot } 11449578Ssam tp->t_state &= ~TS_BKSL; 11459578Ssam 11469859Ssam checktandem: 11479578Ssam /* 11489578Ssam * Look to unblock output now that (presumably) 11499578Ssam * the input queue has gone down. 11509578Ssam */ 11519859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11529578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11537502Sroot tp->t_state &= ~TS_TBLOCK; 11547502Sroot ttstart(tp); 11557502Sroot } 11568520Sroot return (error); 11577502Sroot } 11587502Sroot 11597502Sroot /* 11607502Sroot * Called from the device's write routine after it has 11617502Sroot * calculated the tty-structure given as argument. 11627502Sroot */ 11637822Sroot ttwrite(tp, uio) 11647625Ssam register struct tty *tp; 11659578Ssam register struct uio *uio; 11667502Sroot { 11677502Sroot register char *cp; 11689578Ssam register int cc, ce, c; 11699578Ssam int i, hiwat, cnt, error, s; 11707502Sroot char obuf[OBUFSIZ]; 11717502Sroot 11729578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11738520Sroot return (EIO); 11749578Ssam hiwat = TTHIWAT(tp); 11759578Ssam cnt = uio->uio_resid; 11769578Ssam error = 0; 11777502Sroot loop: 11789578Ssam /* 11799578Ssam * Hang the process if it's in the background. 11809578Ssam */ 11817502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11829578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11837502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11847502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11857502Sroot /* 11867502Sroot && 11877502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11887502Sroot */ 11897502Sroot ) { 11907502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11917502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11927502Sroot } 11939578Ssam 11949578Ssam /* 11959578Ssam * Process the user's data in at most OBUFSIZ 11969578Ssam * chunks. Perform lower case simulation and 11979578Ssam * similar hacks. Keep track of high water 11989578Ssam * mark, sleep on overflow awaiting device aid 11999578Ssam * in acquiring new space. 12009578Ssam */ 12017822Sroot while (uio->uio_resid > 0) { 12029578Ssam /* 12039578Ssam * Grab a hunk of data from the user. 12049578Ssam */ 12057822Sroot cc = uio->uio_iov->iov_len; 12067822Sroot if (cc == 0) { 12077822Sroot uio->uio_iovcnt--; 12087822Sroot uio->uio_iov++; 12097822Sroot if (uio->uio_iovcnt < 0) 12107822Sroot panic("ttwrite"); 12117822Sroot continue; 12127822Sroot } 12137822Sroot if (cc > OBUFSIZ) 12147822Sroot cc = OBUFSIZ; 12157502Sroot cp = obuf; 121612752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12178520Sroot if (error) 12187502Sroot break; 12197502Sroot if (tp->t_outq.c_cc > hiwat) 12207502Sroot goto ovhiwat; 12219578Ssam if (tp->t_flags&FLUSHO) 12227502Sroot continue; 12239578Ssam /* 12249578Ssam * If we're mapping lower case or kludging tildes, 12259578Ssam * then we've got to look at each character, so 12269578Ssam * just feed the stuff to ttyoutput... 12279578Ssam */ 12289578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12299578Ssam while (cc > 0) { 12307502Sroot c = *cp++; 12317502Sroot tp->t_rocount = 0; 12327625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12337502Sroot /* out of clists, wait a bit */ 12347502Sroot ttstart(tp); 12357502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12367502Sroot tp->t_rocount = 0; 12377502Sroot } 12387502Sroot --cc; 12397502Sroot if (tp->t_outq.c_cc > hiwat) 12407502Sroot goto ovhiwat; 12417502Sroot } 12427502Sroot continue; 12437502Sroot } 12449578Ssam /* 12459578Ssam * If nothing fancy need be done, grab those characters we 12469578Ssam * can handle without any of ttyoutput's processing and 12479578Ssam * just transfer them to the output q. For those chars 12489578Ssam * which require special processing (as indicated by the 12499578Ssam * bits in partab), call ttyoutput. After processing 12509578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12519578Ssam * immediately. 12529578Ssam */ 12539578Ssam while (cc > 0) { 12549578Ssam if (tp->t_flags & (RAW|LITOUT)) 12557502Sroot ce = cc; 12567502Sroot else { 125712752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 125812752Ssam (caddr_t)partab, 077); 12599578Ssam /* 12609578Ssam * If ce is zero, then we're processing 12619578Ssam * a special character through ttyoutput. 12629578Ssam */ 12639578Ssam if (ce == 0) { 12647502Sroot tp->t_rocount = 0; 12657502Sroot if (ttyoutput(*cp, tp) >= 0) { 12669578Ssam /* no c-lists, wait a bit */ 12677502Sroot ttstart(tp); 12687502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12697502Sroot continue; 12707502Sroot } 12719578Ssam cp++, cc--; 12729578Ssam if (tp->t_flags&FLUSHO || 12739578Ssam tp->t_outq.c_cc > hiwat) 12747502Sroot goto ovhiwat; 12759578Ssam continue; 12767502Sroot } 12777502Sroot } 12789578Ssam /* 12799578Ssam * A bunch of normal characters have been found, 12809578Ssam * transfer them en masse to the output queue and 12819578Ssam * continue processing at the top of the loop. 12829578Ssam * If there are any further characters in this 12839578Ssam * <= OBUFSIZ chunk, the first should be a character 12849578Ssam * requiring special handling by ttyoutput. 12859578Ssam */ 12867502Sroot tp->t_rocount = 0; 12879578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12889578Ssam ce -= i; 12899578Ssam tp->t_col += ce; 12909578Ssam cp += ce, cc -= ce, tk_nout += ce; 12919578Ssam if (i > 0) { 12929578Ssam /* out of c-lists, wait a bit */ 12937502Sroot ttstart(tp); 12947502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12957502Sroot } 12969578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12977502Sroot goto ovhiwat; 12987502Sroot } 12997502Sroot } 13007502Sroot ttstart(tp); 13018520Sroot return (error); 13027502Sroot 13037502Sroot ovhiwat: 13049578Ssam s = spl5(); 13059578Ssam if (cc != 0) { 13069578Ssam uio->uio_iov->iov_base -= cc; 13079578Ssam uio->uio_iov->iov_len += cc; 13089578Ssam uio->uio_resid += cc; 13099578Ssam uio->uio_offset -= cc; 13109578Ssam } 13119578Ssam /* 13129578Ssam * This can only occur if FLUSHO 13139578Ssam * is also set in t_flags. 13149578Ssam */ 13157502Sroot if (tp->t_outq.c_cc <= hiwat) { 13169578Ssam splx(s); 13177502Sroot goto loop; 13187502Sroot } 13197502Sroot ttstart(tp); 13209578Ssam if (tp->t_state&TS_NBIO) { 13217822Sroot if (uio->uio_resid == cnt) 13228520Sroot return (EWOULDBLOCK); 13238520Sroot return (0); 13247502Sroot } 13257502Sroot tp->t_state |= TS_ASLEEP; 13267502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13279578Ssam splx(s); 13287502Sroot goto loop; 13297502Sroot } 13307502Sroot 13317502Sroot /* 13327502Sroot * Rubout one character from the rawq of tp 13337502Sroot * as cleanly as possible. 13347502Sroot */ 13357502Sroot ttyrub(c, tp) 13367625Ssam register c; 13377625Ssam register struct tty *tp; 13387502Sroot { 13397502Sroot register char *cp; 13407502Sroot register int savecol; 13417502Sroot int s; 13427502Sroot char *nextc(); 13437502Sroot 13449578Ssam if ((tp->t_flags&ECHO) == 0) 13457502Sroot return; 13469578Ssam tp->t_flags &= ~FLUSHO; 13477502Sroot c &= 0377; 13489578Ssam if (tp->t_flags&CRTBS) { 13497502Sroot if (tp->t_rocount == 0) { 13507502Sroot /* 13517502Sroot * Screwed by ttwrite; retype 13527502Sroot */ 13537502Sroot ttyretype(tp); 13547502Sroot return; 13557502Sroot } 13569578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13577502Sroot ttyrubo(tp, 2); 13589578Ssam else switch (partab[c&=0177]&0177) { 13597502Sroot 13607502Sroot case ORDINARY: 13617502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13627502Sroot ttyrubo(tp, 2); 13637502Sroot else 13647502Sroot ttyrubo(tp, 1); 13657502Sroot break; 13667502Sroot 13677502Sroot case VTAB: 13687502Sroot case BACKSPACE: 13697502Sroot case CONTROL: 13707502Sroot case RETURN: 13719578Ssam if (tp->t_flags&CTLECH) 13727502Sroot ttyrubo(tp, 2); 13737502Sroot break; 13747502Sroot 13757502Sroot case TAB: 13767502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13777502Sroot ttyretype(tp); 13787502Sroot return; 13797502Sroot } 13807502Sroot s = spl5(); 13817502Sroot savecol = tp->t_col; 13829578Ssam tp->t_state |= TS_CNTTB; 13839578Ssam tp->t_flags |= FLUSHO; 13847502Sroot tp->t_col = tp->t_rocol; 13859578Ssam cp = tp->t_rawq.c_cf; 13869578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13877502Sroot ttyecho(*cp, tp); 13889578Ssam tp->t_flags &= ~FLUSHO; 13899578Ssam tp->t_state &= ~TS_CNTTB; 13907502Sroot splx(s); 13917502Sroot /* 13927502Sroot * savecol will now be length of the tab 13937502Sroot */ 13947502Sroot savecol -= tp->t_col; 13957502Sroot tp->t_col += savecol; 13967502Sroot if (savecol > 8) 13977502Sroot savecol = 8; /* overflow screw */ 13987502Sroot while (--savecol >= 0) 13997502Sroot (void) ttyoutput('\b', tp); 14007502Sroot break; 14017502Sroot 14027502Sroot default: 14037502Sroot panic("ttyrub"); 14047502Sroot } 14059578Ssam } else if (tp->t_flags&PRTERA) { 14069578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14077502Sroot (void) ttyoutput('\\', tp); 14089578Ssam tp->t_state |= TS_ERASE; 14097502Sroot } 14107502Sroot ttyecho(c, tp); 14117502Sroot } else 14127502Sroot ttyecho(tp->t_erase, tp); 14137502Sroot tp->t_rocount--; 14147502Sroot } 14157502Sroot 14167502Sroot /* 14177502Sroot * Crt back over cnt chars perhaps 14187502Sroot * erasing them. 14197502Sroot */ 14207502Sroot ttyrubo(tp, cnt) 14217625Ssam register struct tty *tp; 14227625Ssam int cnt; 14237502Sroot { 14249578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14257502Sroot 14267502Sroot while (--cnt >= 0) 14279578Ssam ttyout(rubostring, tp); 14287502Sroot } 14297502Sroot 14307502Sroot /* 14317502Sroot * Reprint the rawq line. 14327502Sroot * We assume c_cc has already been checked. 14337502Sroot */ 14347502Sroot ttyretype(tp) 14357625Ssam register struct tty *tp; 14367502Sroot { 14377502Sroot register char *cp; 14387502Sroot char *nextc(); 14397502Sroot int s; 14407502Sroot 14419578Ssam if (tp->t_rprntc != 0377) 14429578Ssam ttyecho(tp->t_rprntc, tp); 14437502Sroot (void) ttyoutput('\n', tp); 14447502Sroot s = spl5(); 14457502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14467502Sroot ttyecho(*cp, tp); 14477502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14487502Sroot ttyecho(*cp, tp); 14499578Ssam tp->t_state &= ~TS_ERASE; 14507502Sroot splx(s); 14517502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14527502Sroot tp->t_rocol = 0; 14537502Sroot } 14547502Sroot 14557502Sroot /* 14567502Sroot * Echo a typed character to the terminal 14577502Sroot */ 14587502Sroot ttyecho(c, tp) 14597625Ssam register c; 14607625Ssam register struct tty *tp; 14617502Sroot { 14627502Sroot 14639578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14649578Ssam tp->t_flags &= ~FLUSHO; 14657502Sroot if ((tp->t_flags&ECHO) == 0) 14667502Sroot return; 14677502Sroot c &= 0377; 14687502Sroot if (tp->t_flags&RAW) { 14697502Sroot (void) ttyoutput(c, tp); 14707502Sroot return; 14717502Sroot } 14727502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14737502Sroot c = '\n'; 14749578Ssam if (tp->t_flags&CTLECH) { 14757502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14767502Sroot (void) ttyoutput('^', tp); 14777502Sroot c &= 0177; 14787502Sroot if (c == 0177) 14797502Sroot c = '?'; 14807502Sroot else if (tp->t_flags&LCASE) 14817502Sroot c += 'a' - 1; 14827502Sroot else 14837502Sroot c += 'A' - 1; 14847502Sroot } 14857502Sroot } 14867502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14877502Sroot c += 'a' - 'A'; 14889578Ssam (void) ttyoutput(c&0177, tp); 14897502Sroot } 14907502Sroot 14917502Sroot /* 14927502Sroot * Is c a break char for tp? 14937502Sroot */ 14947502Sroot ttbreakc(c, tp) 14957625Ssam register c; 14967625Ssam register struct tty *tp; 14977502Sroot { 14989578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14997502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15007502Sroot } 15017502Sroot 15027502Sroot /* 15037502Sroot * send string cp to tp 15047502Sroot */ 15057502Sroot ttyout(cp, tp) 15067625Ssam register char *cp; 15077625Ssam register struct tty *tp; 15087502Sroot { 15097502Sroot register char c; 15107502Sroot 15117502Sroot while (c = *cp++) 15127502Sroot (void) ttyoutput(c, tp); 15137502Sroot } 15147502Sroot 15157502Sroot ttwakeup(tp) 15167502Sroot struct tty *tp; 15177502Sroot { 15187502Sroot 15197502Sroot if (tp->t_rsel) { 15207502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15217502Sroot tp->t_state &= ~TS_RCOLL; 15227502Sroot tp->t_rsel = 0; 15237502Sroot } 152412752Ssam if (tp->t_state & TS_ASYNC) 152512752Ssam gsignal(tp->t_pgrp, SIGIO); 15267502Sroot wakeup((caddr_t)&tp->t_rawq); 15277502Sroot } 15287502Sroot 152913533Ssam #if !defined(vax) 15309578Ssam scanc(size, cp, table, mask) 15319578Ssam register int size; 15329578Ssam register char *cp, table[]; 15339578Ssam register int mask; 15347502Sroot { 15359578Ssam register int i = 0; 15367502Sroot 15379578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15389578Ssam i++; 153915100Skarels return (size - i); 15407502Sroot } 15419578Ssam #endif 1542