1*15078Skarels /* tty.c 6.3 83/09/25 */ 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 } 1829578Ssam if (x >= TTYHOG/2 && putc(tp->t_stopc, &tp->t_outq) == 0) { 1839578Ssam tp->t_state |= TS_TBLOCK; 1849578Ssam ttstart(tp); 185903Sbill } 18639Sbill } 18739Sbill 18839Sbill /* 189903Sbill * Restart typewriter output following a delay 190903Sbill * timeout. 191903Sbill * The name of the routine is passed to the timeout 192903Sbill * subroutine and it is called during a clock interrupt. 193121Sbill */ 194903Sbill ttrstrt(tp) 1957625Ssam register struct tty *tp; 196121Sbill { 197121Sbill 1989578Ssam if (tp == 0) 1999578Ssam panic("ttrstrt"); 2005408Swnj tp->t_state &= ~TS_TIMEOUT; 201903Sbill ttstart(tp); 202121Sbill } 203121Sbill 204121Sbill /* 205903Sbill * Start output on the typewriter. It is used from the top half 206903Sbill * after some characters have been put on the output queue, 207903Sbill * from the interrupt routine to transmit the next 208903Sbill * character, and after a timeout has finished. 20939Sbill */ 210903Sbill ttstart(tp) 2117625Ssam register struct tty *tp; 21239Sbill { 213903Sbill register s; 21439Sbill 215903Sbill s = spl5(); 2169578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2175622Swnj tp->t_oproc) /* kludge for pty */ 218903Sbill (*tp->t_oproc)(tp); 219903Sbill splx(s); 22039Sbill } 22139Sbill 22239Sbill /* 223903Sbill * Common code for tty ioctls. 22439Sbill */ 2251780Sbill /*ARGSUSED*/ 2267625Ssam ttioctl(tp, com, data, flag) 2277625Ssam register struct tty *tp; 2287625Ssam caddr_t data; 22939Sbill { 2308520Sroot int dev = tp->t_dev; 23139Sbill extern int nldisp; 2328556Sroot int s; 23312752Ssam register int newflags; 23439Sbill 235903Sbill /* 236903Sbill * If the ioctl involves modification, 237903Sbill * insist on being able to write the device, 238903Sbill * and hang if in the background. 239903Sbill */ 2407625Ssam switch (com) { 24139Sbill 242915Sbill case TIOCSETD: 243915Sbill case TIOCSETP: 244915Sbill case TIOCSETN: 245903Sbill case TIOCFLUSH: 246903Sbill case TIOCSETC: 247903Sbill case TIOCSLTC: 248903Sbill case TIOCSPGRP: 249903Sbill case TIOCLBIS: 250903Sbill case TIOCLBIC: 251903Sbill case TIOCLSET: 2529325Ssam case TIOCSTI: 253*15078Skarels #define bit(a) (1<<(a-1)) 254903Sbill while (tp->t_line == NTTYDISC && 255903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 256903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 257*15078Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 258*15078Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU))) { 259903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 260903Sbill sleep((caddr_t)&lbolt, TTOPRI); 261903Sbill } 262903Sbill break; 263903Sbill } 264*15078Skarels #undef bit 265903Sbill 2669578Ssam /* 2679578Ssam * Process the ioctl. 2689578Ssam */ 2697625Ssam switch (com) { 270903Sbill 2718556Sroot /* get discipline number */ 27239Sbill case TIOCGETD: 2737625Ssam *(int *)data = tp->t_line; 27439Sbill break; 27539Sbill 2768556Sroot /* set line discipline */ 2777625Ssam case TIOCSETD: { 2787625Ssam register int t = *(int *)data; 2799578Ssam int error = 0; 2807625Ssam 281*15078Skarels if ((unsigned) t >= nldisp) 28210851Ssam return (ENXIO); 2838556Sroot s = spl5(); 28439Sbill if (tp->t_line) 28539Sbill (*linesw[tp->t_line].l_close)(tp); 28639Sbill if (t) 2878556Sroot error = (*linesw[t].l_open)(dev, tp); 2888556Sroot splx(s); 28910851Ssam if (error) { 29010851Ssam s = spl5(); 29110851Ssam if (tp->t_line) 29210851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29310851Ssam splx(s); 2948556Sroot return (error); 29510851Ssam } 2968556Sroot tp->t_line = t; 29739Sbill break; 2987625Ssam } 29939Sbill 3008556Sroot /* prevent more opens on channel */ 3015614Swnj case TIOCEXCL: 3025614Swnj tp->t_state |= TS_XCLUDE; 3035614Swnj break; 3045614Swnj 3055614Swnj case TIOCNXCL: 3065614Swnj tp->t_state &= ~TS_XCLUDE; 3075614Swnj break; 3085614Swnj 3098556Sroot /* hang up line on last close */ 31039Sbill case TIOCHPCL: 3115408Swnj tp->t_state |= TS_HUPCLS; 31239Sbill break; 31339Sbill 3143942Sbugs case TIOCFLUSH: { 3157625Ssam register int flags = *(int *)data; 3167625Ssam 3177625Ssam if (flags == 0) 3183942Sbugs flags = FREAD|FWRITE; 3197625Ssam else 3207625Ssam flags &= FREAD|FWRITE; 32112752Ssam ttyflush(tp, flags); 32239Sbill break; 3233944Sbugs } 32439Sbill 3258556Sroot /* return number of characters immediately available */ 3267625Ssam case FIONREAD: 3277625Ssam *(off_t *)data = ttnread(tp); 328174Sbill break; 329174Sbill 33013077Ssam case TIOCOUTQ: 33113077Ssam *(int *)data = tp->t_outq.c_cc; 33213077Ssam break; 33313077Ssam 3348589Sroot case TIOCSTOP: 3358589Sroot s = spl5(); 3369578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3375573Swnj tp->t_state |= TS_TTSTOP; 3385573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3395573Swnj } 3407625Ssam splx(s); 3415573Swnj break; 3425573Swnj 3438589Sroot case TIOCSTART: 3448589Sroot s = spl5(); 3459578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3465573Swnj tp->t_state &= ~TS_TTSTOP; 3479578Ssam tp->t_flags &= ~FLUSHO; 3485573Swnj ttstart(tp); 3495573Swnj } 3507625Ssam splx(s); 3515573Swnj break; 3525573Swnj 3539325Ssam /* 3549325Ssam * Simulate typing of a character at the terminal. 3559325Ssam */ 3569325Ssam case TIOCSTI: 3579325Ssam if (u.u_uid && u.u_ttyp != tp) 3589325Ssam return (EACCES); 3599578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3609325Ssam break; 3619325Ssam 36212752Ssam case TIOCSETP: 36312752Ssam case TIOCSETN: { 36412752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 36512752Ssam 36612752Ssam tp->t_erase = sg->sg_erase; 36712752Ssam tp->t_kill = sg->sg_kill; 36812752Ssam tp->t_ispeed = sg->sg_ispeed; 36912752Ssam tp->t_ospeed = sg->sg_ospeed; 37012752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37112752Ssam s = spl5(); 37212752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 37312752Ssam ttywait(tp); 37412752Ssam ttyflush(tp, FREAD); 37512752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 37612752Ssam if (newflags&CBREAK) { 37712752Ssam struct clist tq; 37812752Ssam 37912752Ssam catq(&tp->t_rawq, &tp->t_canq); 38012752Ssam tq = tp->t_rawq; 38112752Ssam tp->t_rawq = tp->t_canq; 38212752Ssam tp->t_canq = tq; 38312752Ssam } else { 38412752Ssam tp->t_flags |= PENDIN; 38513801Ssam newflags |= PENDIN; 38612752Ssam ttwakeup(tp); 38712752Ssam } 38812752Ssam } 38912752Ssam tp->t_flags = newflags; 39012752Ssam if (tp->t_flags&RAW) { 39112752Ssam tp->t_state &= ~TS_TTSTOP; 39212752Ssam ttstart(tp); 39312752Ssam } 39412752Ssam splx(s); 39512752Ssam break; 39612752Ssam } 39712752Ssam 39812752Ssam /* send current parameters to user */ 39912752Ssam case TIOCGETP: { 40012752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40112752Ssam 40212752Ssam sg->sg_ispeed = tp->t_ispeed; 40312752Ssam sg->sg_ospeed = tp->t_ospeed; 40412752Ssam sg->sg_erase = tp->t_erase; 40512752Ssam sg->sg_kill = tp->t_kill; 40612752Ssam sg->sg_flags = tp->t_flags; 40712752Ssam break; 40812752Ssam } 40912752Ssam 41012752Ssam case FIONBIO: 41112752Ssam if (*(int *)data) 41212752Ssam tp->t_state |= TS_NBIO; 41312752Ssam else 41412752Ssam tp->t_state &= ~TS_NBIO; 41512752Ssam break; 41612752Ssam 41712752Ssam case FIOASYNC: 41812752Ssam if (*(int *)data) 41912752Ssam tp->t_state |= TS_ASYNC; 42012752Ssam else 42112752Ssam tp->t_state &= ~TS_ASYNC; 42212752Ssam break; 42312752Ssam 42413077Ssam case TIOCGETC: 42513077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 42613077Ssam break; 42713077Ssam 42813077Ssam case TIOCSETC: 42913077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43013077Ssam break; 43113077Ssam 43212752Ssam /* set/get local special characters */ 43312752Ssam case TIOCSLTC: 43412752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 43512752Ssam break; 43612752Ssam 43712752Ssam case TIOCGLTC: 43812752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 43912752Ssam break; 44012752Ssam 44112752Ssam /* 44212752Ssam * Modify local mode word. 44312752Ssam */ 44412752Ssam case TIOCLBIS: 44512752Ssam tp->t_flags |= *(int *)data << 16; 44612752Ssam break; 44712752Ssam 44812752Ssam case TIOCLBIC: 44912752Ssam tp->t_flags &= ~(*(int *)data << 16); 45012752Ssam break; 45112752Ssam 45212752Ssam case TIOCLSET: 45312752Ssam tp->t_flags &= 0xffff; 45412752Ssam tp->t_flags |= *(int *)data << 16; 45512752Ssam break; 45612752Ssam 45712752Ssam case TIOCLGET: 45812752Ssam *(int *)data = tp->t_flags >> 16; 45912752Ssam break; 46012752Ssam 46112752Ssam /* should allow SPGRP and GPGRP only if tty open for reading */ 46212752Ssam case TIOCSPGRP: 46312752Ssam tp->t_pgrp = *(int *)data; 46412752Ssam break; 46512752Ssam 46612752Ssam case TIOCGPGRP: 46712752Ssam *(int *)data = tp->t_pgrp; 46812752Ssam break; 46912752Ssam 47039Sbill default: 4718556Sroot return (-1); 47239Sbill } 4738556Sroot return (0); 47439Sbill } 4754484Swnj 4764484Swnj ttnread(tp) 4774484Swnj struct tty *tp; 4784484Swnj { 4794484Swnj int nread = 0; 4804484Swnj 4819578Ssam if (tp->t_flags & PENDIN) 4824484Swnj ttypend(tp); 4834484Swnj nread = tp->t_canq.c_cc; 4844484Swnj if (tp->t_flags & (RAW|CBREAK)) 4854484Swnj nread += tp->t_rawq.c_cc; 4864484Swnj return (nread); 4874484Swnj } 4884484Swnj 4895408Swnj ttselect(dev, rw) 4904484Swnj dev_t dev; 4915408Swnj int rw; 4924484Swnj { 4934484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 4944484Swnj int nread; 4955408Swnj int s = spl5(); 4964484Swnj 4975408Swnj switch (rw) { 4984484Swnj 4994484Swnj case FREAD: 5004484Swnj nread = ttnread(tp); 5014484Swnj if (nread > 0) 5025408Swnj goto win; 5034938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5045408Swnj tp->t_state |= TS_RCOLL; 5054484Swnj else 5064484Swnj tp->t_rsel = u.u_procp; 5075408Swnj break; 5084484Swnj 5095408Swnj case FWRITE: 5105408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5115408Swnj goto win; 5125408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5135408Swnj tp->t_state |= TS_WCOLL; 5145408Swnj else 5155408Swnj tp->t_wsel = u.u_procp; 5165408Swnj break; 5174484Swnj } 5185408Swnj splx(s); 5195408Swnj return (0); 5205408Swnj win: 5215408Swnj splx(s); 5225408Swnj return (1); 5234484Swnj } 5247436Skre 5257502Sroot /* 5269578Ssam * Establish a process group for distribution of 5277502Sroot * quits and interrupts from the tty. 5287502Sroot */ 5297502Sroot ttyopen(dev, tp) 5307625Ssam dev_t dev; 5317625Ssam register struct tty *tp; 5327502Sroot { 5337502Sroot register struct proc *pp; 5347502Sroot 5357502Sroot pp = u.u_procp; 5367502Sroot tp->t_dev = dev; 5377625Ssam if (pp->p_pgrp == 0) { 5387502Sroot u.u_ttyp = tp; 5397502Sroot u.u_ttyd = dev; 5407502Sroot if (tp->t_pgrp == 0) 5417502Sroot tp->t_pgrp = pp->p_pid; 5427502Sroot pp->p_pgrp = tp->t_pgrp; 5437502Sroot } 5447502Sroot tp->t_state &= ~TS_WOPEN; 5457502Sroot tp->t_state |= TS_ISOPEN; 5467502Sroot if (tp->t_line != NTTYDISC) 54712752Ssam ttywflush(tp); 5488556Sroot return (0); 5497502Sroot } 5507502Sroot 5517502Sroot /* 5527502Sroot * clean tp on last close 5537502Sroot */ 5547502Sroot ttyclose(tp) 5557625Ssam register struct tty *tp; 5567502Sroot { 5577502Sroot 5587502Sroot if (tp->t_line) { 55912752Ssam ttywflush(tp); 5607502Sroot tp->t_line = 0; 5617502Sroot return; 5627502Sroot } 5637502Sroot tp->t_pgrp = 0; 56412752Ssam ttywflush(tp); 5657502Sroot tp->t_state = 0; 5667502Sroot } 5677502Sroot 5687502Sroot /* 5697502Sroot * reinput pending characters after state switch 5707502Sroot * call at spl5(). 5717502Sroot */ 5727502Sroot ttypend(tp) 5737625Ssam register struct tty *tp; 5747502Sroot { 5757502Sroot struct clist tq; 5767502Sroot register c; 5777502Sroot 5789578Ssam tp->t_flags &= ~PENDIN; 5799578Ssam tp->t_state |= TS_TYPEN; 5807502Sroot tq = tp->t_rawq; 5817502Sroot tp->t_rawq.c_cc = 0; 5827502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 5837502Sroot while ((c = getc(&tq)) >= 0) 5847502Sroot ttyinput(c, tp); 5859578Ssam tp->t_state &= ~TS_TYPEN; 5867502Sroot } 5877502Sroot 5887502Sroot /* 5899578Ssam * Place a character on raw TTY input queue, 5909578Ssam * putting in delimiters and waking up top 5919578Ssam * half as needed. Also echo if required. 5929578Ssam * The arguments are the character and the 5939578Ssam * appropriate tty structure. 5947502Sroot */ 5957502Sroot ttyinput(c, tp) 5967625Ssam register c; 5977625Ssam register struct tty *tp; 5987502Sroot { 5999578Ssam register int t_flags = tp->t_flags; 6007502Sroot int i; 6017502Sroot 6029578Ssam /* 6039578Ssam * If input is pending take it first. 6049578Ssam */ 6059578Ssam if (t_flags&PENDIN) 6067502Sroot ttypend(tp); 6077502Sroot tk_nin++; 6087502Sroot c &= 0377; 6099578Ssam 6109578Ssam /* 6119578Ssam * In tandem mode, check high water mark. 6129578Ssam */ 6137502Sroot if (t_flags&TANDEM) 6147502Sroot ttyblock(tp); 6159578Ssam 6169578Ssam if (t_flags&RAW) { 6179578Ssam /* 6189578Ssam * Raw mode, just put character 6199578Ssam * in input q w/o interpretation. 6209578Ssam */ 6219578Ssam if (tp->t_rawq.c_cc > TTYHOG) 62212752Ssam ttyflush(tp, FREAD|FWRITE); 6239578Ssam else { 6249578Ssam if (putc(c, &tp->t_rawq) >= 0) 6259578Ssam ttwakeup(tp); 6269578Ssam ttyecho(c, tp); 6277502Sroot } 6289578Ssam goto endcase; 6299578Ssam } 6309578Ssam 6319578Ssam /* 6329578Ssam * Ignore any high bit added during 6339578Ssam * previous ttyinput processing. 6349578Ssam */ 6359578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6369578Ssam c &= 0177; 6379578Ssam /* 6389578Ssam * Check for literal nexting very first 6399578Ssam */ 6409578Ssam if (tp->t_state&TS_LNCH) { 6419578Ssam c |= 0200; 6429578Ssam tp->t_state &= ~TS_LNCH; 6439578Ssam } 6449578Ssam 6459578Ssam /* 6469578Ssam * Scan for special characters. This code 6479578Ssam * is really just a big case statement with 6489578Ssam * non-constant cases. The bottom of the 6499578Ssam * case statement is labeled ``endcase'', so goto 6509578Ssam * it after a case match, or similar. 6519578Ssam */ 6529578Ssam if (tp->t_line == NTTYDISC) { 6539578Ssam if (c == tp->t_lnextc) { 6547502Sroot if (tp->t_flags&ECHO) 6557502Sroot ttyout("^\b", tp); 6569578Ssam tp->t_state |= TS_LNCH; 6579578Ssam goto endcase; 6589578Ssam } 6599578Ssam if (c == tp->t_flushc) { 6609578Ssam if (tp->t_flags&FLUSHO) 6619578Ssam tp->t_flags &= ~FLUSHO; 6627502Sroot else { 66312752Ssam ttyflush(tp, FWRITE); 6647502Sroot ttyecho(c, tp); 6659578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 6667502Sroot ttyretype(tp); 6679578Ssam tp->t_flags |= FLUSHO; 6687502Sroot } 6699578Ssam goto startoutput; 6709578Ssam } 6719578Ssam if (c == tp->t_suspc) { 6729578Ssam if ((tp->t_flags&NOFLSH) == 0) 67312752Ssam ttyflush(tp, FREAD); 6749578Ssam ttyecho(c, tp); 6759578Ssam gsignal(tp->t_pgrp, SIGTSTP); 6769578Ssam goto endcase; 6779578Ssam } 6789578Ssam } 6799578Ssam 6809578Ssam /* 6819578Ssam * Handle start/stop characters. 6829578Ssam */ 6839578Ssam if (c == tp->t_stopc) { 6849578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 6859578Ssam tp->t_state |= TS_TTSTOP; 6869578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 6877502Sroot return; 6889578Ssam } 6899578Ssam if (c != tp->t_startc) 6909578Ssam return; 6919578Ssam goto endcase; 6929578Ssam } 6939578Ssam if (c == tp->t_startc) 6949578Ssam goto restartoutput; 6959578Ssam 6969578Ssam /* 6979578Ssam * Look for interrupt/quit chars. 6989578Ssam */ 6999578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7009578Ssam if ((tp->t_flags&NOFLSH) == 0) 70112752Ssam ttyflush(tp, FREAD|FWRITE); 7029578Ssam ttyecho(c, tp); 7039578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7049578Ssam goto endcase; 7059578Ssam } 7069578Ssam 7079578Ssam /* 7089578Ssam * Cbreak mode, don't process line editing 7099578Ssam * characters; check high water mark for wakeup. 7109578Ssam */ 7119578Ssam if (t_flags&CBREAK) { 7129578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7137502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7147502Sroot tp->t_line == NTTYDISC) 7157502Sroot (void) ttyoutput(CTRL(g), tp); 7167502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7177502Sroot ttwakeup(tp); 7187502Sroot ttyecho(c, tp); 7197502Sroot } 7209578Ssam goto endcase; 7219578Ssam } 7229578Ssam 7239578Ssam /* 7249578Ssam * From here on down cooked mode character 7259578Ssam * processing takes place. 7269578Ssam */ 7279578Ssam if ((tp->t_state&TS_QUOT) && 7289578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7299578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7309578Ssam c |= 0200; 7319578Ssam } 7329578Ssam if (c == tp->t_erase) { 7339578Ssam if (tp->t_rawq.c_cc) 7349578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7359578Ssam goto endcase; 7369578Ssam } 7379578Ssam if (c == tp->t_kill) { 7389578Ssam if (tp->t_flags&CRTKIL && 7399578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7409578Ssam while (tp->t_rawq.c_cc) 7419578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7429578Ssam } else { 7439578Ssam ttyecho(c, tp); 7449578Ssam ttyecho('\n', tp); 7459578Ssam while (getc(&tp->t_rawq) > 0) 7469578Ssam ; 7479578Ssam tp->t_rocount = 0; 7489578Ssam } 7499578Ssam tp->t_state &= ~TS_LOCAL; 7509578Ssam goto endcase; 7519578Ssam } 7529578Ssam 7539578Ssam /* 7549578Ssam * New line discipline, 7559578Ssam * check word erase/reprint line. 7569578Ssam */ 7579578Ssam if (tp->t_line == NTTYDISC) { 7589578Ssam if (c == tp->t_werasc) { 7599578Ssam if (tp->t_rawq.c_cc == 0) 7609578Ssam goto endcase; 7619578Ssam do { 7629578Ssam c = unputc(&tp->t_rawq); 7639578Ssam if (c != ' ' && c != '\t') 7649578Ssam goto erasenb; 7659578Ssam ttyrub(c, tp); 7669578Ssam } while (tp->t_rawq.c_cc); 7679578Ssam goto endcase; 7689578Ssam erasenb: 7699578Ssam do { 7709578Ssam ttyrub(c, tp); 7719578Ssam if (tp->t_rawq.c_cc == 0) 7729578Ssam goto endcase; 7739578Ssam c = unputc(&tp->t_rawq); 7749578Ssam } while (c != ' ' && c != '\t'); 7759578Ssam (void) putc(c, &tp->t_rawq); 7769578Ssam goto endcase; 7779578Ssam } 7789578Ssam if (c == tp->t_rprntc) { 7799578Ssam ttyretype(tp); 7809578Ssam goto endcase; 7819578Ssam } 7829578Ssam } 7839578Ssam 7849578Ssam /* 7859578Ssam * Check for input buffer overflow 7869578Ssam */ 78710391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 78810391Ssam if (tp->t_line == NTTYDISC) 78910391Ssam (void) ttyoutput(CTRL(g), tp); 7909578Ssam goto endcase; 79110391Ssam } 7929578Ssam 7939578Ssam /* 7949578Ssam * Put data char in q for user and 7959578Ssam * wakeup on seeing a line delimiter. 7969578Ssam */ 7979578Ssam if (putc(c, &tp->t_rawq) >= 0) { 7989578Ssam if (ttbreakc(c, tp)) { 7999578Ssam tp->t_rocount = 0; 8009578Ssam catq(&tp->t_rawq, &tp->t_canq); 8017502Sroot ttwakeup(tp); 8029578Ssam } else if (tp->t_rocount++ == 0) 8039578Ssam tp->t_rocol = tp->t_col; 8049578Ssam tp->t_state &= ~TS_QUOT; 8059578Ssam if (c == '\\') 8069578Ssam tp->t_state |= TS_QUOT; 8079578Ssam if (tp->t_state&TS_ERASE) { 8089578Ssam tp->t_state &= ~TS_ERASE; 8099578Ssam (void) ttyoutput('/', tp); 8109578Ssam } 8119578Ssam i = tp->t_col; 8127502Sroot ttyecho(c, tp); 8139578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8149578Ssam i = MIN(2, tp->t_col - i); 8159578Ssam while (i > 0) { 8169578Ssam (void) ttyoutput('\b', tp); 8179578Ssam i--; 8189578Ssam } 8199578Ssam } 8207502Sroot } 8219578Ssam 8229578Ssam endcase: 8239578Ssam /* 8249578Ssam * If DEC-style start/stop is enabled don't restart 8259578Ssam * output until seeing the start character. 8269578Ssam */ 8279578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8289578Ssam tp->t_startc != tp->t_stopc) 8297502Sroot return; 8309578Ssam 8319578Ssam restartoutput: 8327502Sroot tp->t_state &= ~TS_TTSTOP; 8339578Ssam tp->t_flags &= ~FLUSHO; 8349578Ssam 8359578Ssam startoutput: 8367502Sroot ttstart(tp); 8377502Sroot } 8387502Sroot 8397502Sroot /* 8409578Ssam * Put character on TTY output queue, adding delays, 8417502Sroot * expanding tabs, and handling the CR/NL bit. 8429578Ssam * This is called both from the top half for output, 8439578Ssam * and from interrupt level for echoing. 8447502Sroot * The arguments are the character and the tty structure. 8457502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8467502Sroot * Must be recursive. 8477502Sroot */ 8487502Sroot ttyoutput(c, tp) 8497502Sroot register c; 8507502Sroot register struct tty *tp; 8517502Sroot { 8527502Sroot register char *colp; 8537502Sroot register ctype; 8547502Sroot 8559578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8569578Ssam if (tp->t_flags&FLUSHO) 8577502Sroot return (-1); 8587502Sroot if (putc(c, &tp->t_outq)) 8597625Ssam return (c); 8607502Sroot tk_nout++; 8617502Sroot return (-1); 8627502Sroot } 8639578Ssam 8647502Sroot /* 8659578Ssam * Ignore EOT in normal mode to avoid 8669578Ssam * hanging up certain terminals. 8677502Sroot */ 8687502Sroot c &= 0177; 8699578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 8707502Sroot return (-1); 8717502Sroot /* 8727502Sroot * Turn tabs to spaces as required 8737502Sroot */ 8749578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 8757502Sroot register int s; 8767502Sroot 8777502Sroot c = 8 - (tp->t_col&7); 8789578Ssam if ((tp->t_flags&FLUSHO) == 0) { 8797502Sroot s = spl5(); /* don't interrupt tabs */ 8807502Sroot c -= b_to_q(" ", c, &tp->t_outq); 8817502Sroot tk_nout += c; 8827502Sroot splx(s); 8837502Sroot } 8847502Sroot tp->t_col += c; 8857502Sroot return (c ? -1 : '\t'); 8867502Sroot } 8877502Sroot tk_nout++; 8887502Sroot /* 8897502Sroot * for upper-case-only terminals, 8907502Sroot * generate escapes. 8917502Sroot */ 8927502Sroot if (tp->t_flags&LCASE) { 8937502Sroot colp = "({)}!|^~'`"; 8947625Ssam while (*colp++) 8957625Ssam if (c == *colp++) { 8967502Sroot if (ttyoutput('\\', tp) >= 0) 8977502Sroot return (c); 8987502Sroot c = colp[-2]; 8997502Sroot break; 9007502Sroot } 9019578Ssam if ('A' <= c && c <= 'Z') { 9027502Sroot if (ttyoutput('\\', tp) >= 0) 9037502Sroot return (c); 9049578Ssam } else if ('a' <= c && c <= 'z') 9057502Sroot c += 'A' - 'a'; 9067502Sroot } 9079578Ssam 9087502Sroot /* 9097502Sroot * turn <nl> to <cr><lf> if desired. 9107502Sroot */ 9119578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9127502Sroot if (ttyoutput('\r', tp) >= 0) 9137502Sroot return (c); 9149578Ssam if (c == '~' && tp->t_flags&TILDE) 9157502Sroot c = '`'; 9169578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9177502Sroot return (c); 9187502Sroot /* 9197502Sroot * Calculate delays. 9207502Sroot * The numbers here represent clock ticks 9217502Sroot * and are not necessarily optimal for all terminals. 9227502Sroot * The delays are indicated by characters above 0200. 9237502Sroot * In raw mode there are no delays and the 9247502Sroot * transmission path is 8 bits wide. 9259578Ssam * 9269578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9277502Sroot */ 9287502Sroot colp = &tp->t_col; 9297502Sroot ctype = partab[c]; 9307502Sroot c = 0; 9317502Sroot switch (ctype&077) { 9327502Sroot 9337502Sroot case ORDINARY: 9347502Sroot (*colp)++; 9357502Sroot 9367502Sroot case CONTROL: 9377502Sroot break; 9387502Sroot 9397502Sroot case BACKSPACE: 9407502Sroot if (*colp) 9417502Sroot (*colp)--; 9427502Sroot break; 9437502Sroot 94413821Ssam /* 94513821Ssam * This macro is close enough to the correct thing; 94613821Ssam * it should be replaced by real user settable delays 94713821Ssam * in any event... 94813821Ssam */ 94913821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9507502Sroot case NEWLINE: 9517502Sroot ctype = (tp->t_flags >> 8) & 03; 9527625Ssam if (ctype == 1) { /* tty 37 */ 95312752Ssam if (*colp > 0) 95413863Ssam c = max((((unsigned)*colp) >> 4) + 3, 95513863Ssam (unsigned)6); 9569578Ssam } else if (ctype == 2) /* vt05 */ 95713821Ssam c = mstohz(100); 9587502Sroot *colp = 0; 9597502Sroot break; 9607502Sroot 9617502Sroot case TAB: 9627502Sroot ctype = (tp->t_flags >> 10) & 03; 9637625Ssam if (ctype == 1) { /* tty 37 */ 9647502Sroot c = 1 - (*colp | ~07); 9657625Ssam if (c < 5) 9667502Sroot c = 0; 9677502Sroot } 9687502Sroot *colp |= 07; 9697502Sroot (*colp)++; 9707502Sroot break; 9717502Sroot 9727502Sroot case VTAB: 9739578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 9747502Sroot c = 0177; 9757502Sroot break; 9767502Sroot 9777502Sroot case RETURN: 9787502Sroot ctype = (tp->t_flags >> 12) & 03; 9799578Ssam if (ctype == 1) /* tn 300 */ 98013821Ssam c = mstohz(83); 9819578Ssam else if (ctype == 2) /* ti 700 */ 98213821Ssam c = mstohz(166); 9839578Ssam else if (ctype == 3) { /* concept 100 */ 9847502Sroot int i; 9859578Ssam 9867502Sroot if ((i = *colp) >= 0) 9879578Ssam for (; i < 9; i++) 9887502Sroot (void) putc(0177, &tp->t_outq); 9897502Sroot } 9907502Sroot *colp = 0; 9917502Sroot } 9929578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 9937502Sroot (void) putc(c|0200, &tp->t_outq); 9947502Sroot return (-1); 9957502Sroot } 99613821Ssam #undef mstohz 9977502Sroot 9987502Sroot /* 9997502Sroot * Called from device's read routine after it has 10007502Sroot * calculated the tty-structure given as argument. 10017502Sroot */ 10027722Swnj ttread(tp, uio) 10037625Ssam register struct tty *tp; 10047722Swnj struct uio *uio; 10057502Sroot { 10067502Sroot register struct clist *qp; 10079578Ssam register c, t_flags; 10089859Ssam int s, first, error = 0; 10097502Sroot 10107502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10118520Sroot return (EIO); 10127502Sroot loop: 10139578Ssam /* 10149578Ssam * Take any pending input first. 10159578Ssam */ 10169859Ssam s = spl5(); 10179578Ssam if (tp->t_flags&PENDIN) 10187502Sroot ttypend(tp); 10199859Ssam splx(s); 10209578Ssam 10219578Ssam /* 10229578Ssam * Hang process if it's in the background. 10239578Ssam */ 10247502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 10257502Sroot if (u.u_signal[SIGTTIN] == SIG_IGN || 10267502Sroot u.u_signal[SIGTTIN] == SIG_HOLD || 10277502Sroot /* 10287502Sroot (u.u_procp->p_flag&SDETACH) || 10297502Sroot */ 10307502Sroot u.u_procp->p_flag&SVFORK) 10318520Sroot return (EIO); 10327502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10337502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10347502Sroot } 10359578Ssam t_flags = tp->t_flags; 10369578Ssam 10379578Ssam /* 10389578Ssam * In raw mode take characters directly from the 10399578Ssam * raw queue w/o processing. Interlock against 10409578Ssam * device interrupts when interrogating rawq. 10419578Ssam */ 10429578Ssam if (t_flags&RAW) { 10439859Ssam s = spl5(); 10447502Sroot if (tp->t_rawq.c_cc <= 0) { 10459578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10467502Sroot (tp->t_state&TS_NBIO)) { 10479859Ssam splx(s); 10489578Ssam return (0); 10497502Sroot } 10507502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10519859Ssam splx(s); 10527502Sroot goto loop; 10537502Sroot } 10549859Ssam splx(s); 105514938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 105614938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10579859Ssam goto checktandem; 10589578Ssam } 10599578Ssam 10609578Ssam /* 10619578Ssam * In cbreak mode use the rawq, otherwise 10629578Ssam * take characters from the canonicalized q. 10639578Ssam */ 10649578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 10659578Ssam 10669578Ssam /* 10679578Ssam * No input, sleep on rawq awaiting hardware 10689578Ssam * receipt and notification. 10699578Ssam */ 10709859Ssam s = spl5(); 10719578Ssam if (qp->c_cc <= 0) { 10729578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10739578Ssam (tp->t_state&TS_NBIO)) { 10749859Ssam splx(s); 10759578Ssam return (EWOULDBLOCK); 10767502Sroot } 10779578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 10789859Ssam splx(s); 10799578Ssam goto loop; 10809578Ssam } 10819859Ssam splx(s); 10829578Ssam 10839578Ssam /* 10849578Ssam * Input present, perform input mapping 10859578Ssam * and processing (we're not in raw mode). 10869578Ssam */ 10879578Ssam first = 1; 10889578Ssam while ((c = getc(qp)) >= 0) { 10899578Ssam if (t_flags&CRMOD && c == '\r') 10909578Ssam c = '\n'; 10919578Ssam /* 10929578Ssam * Hack lower case simulation on 10939578Ssam * upper case only terminals. 10949578Ssam */ 10959578Ssam if (t_flags&LCASE && c <= 0177) 10969578Ssam if (tp->t_state&TS_BKSL) { 10979578Ssam if (maptab[c]) 10989578Ssam c = maptab[c]; 10999578Ssam tp->t_state &= ~TS_BKSL; 11009578Ssam } else if (c >= 'A' && c <= 'Z') 11019578Ssam c += 'a' - 'A'; 11029578Ssam else if (c == '\\') { 11039578Ssam tp->t_state |= TS_BKSL; 11049578Ssam continue; 11057502Sroot } 11069578Ssam /* 11079578Ssam * Check for delayed suspend character. 11089578Ssam */ 11099578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11109578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11119578Ssam if (first) { 11129578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11139578Ssam goto loop; 11149578Ssam } 11159578Ssam break; 11167502Sroot } 11179578Ssam /* 11189578Ssam * Interpret EOF only in cooked mode. 11199578Ssam */ 11209578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11219578Ssam break; 11229578Ssam /* 11239578Ssam * Give user character. 11249578Ssam */ 112514938Smckusick error = ureadc(c & 0177, uio); 11269578Ssam if (error) 11279578Ssam break; 112814938Smckusick if (uio->uio_resid == 0) 11299578Ssam break; 11309578Ssam /* 11319578Ssam * In cooked mode check for a "break character" 11329578Ssam * marking the end of a "line of input". 11339578Ssam */ 11349578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11359578Ssam break; 11369578Ssam first = 0; 11377502Sroot } 11389578Ssam tp->t_state &= ~TS_BKSL; 11399578Ssam 11409859Ssam checktandem: 11419578Ssam /* 11429578Ssam * Look to unblock output now that (presumably) 11439578Ssam * the input queue has gone down. 11449578Ssam */ 11459859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11469578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11477502Sroot tp->t_state &= ~TS_TBLOCK; 11487502Sroot ttstart(tp); 11497502Sroot } 11508520Sroot return (error); 11517502Sroot } 11527502Sroot 11537502Sroot /* 11547502Sroot * Called from the device's write routine after it has 11557502Sroot * calculated the tty-structure given as argument. 11567502Sroot */ 11577822Sroot ttwrite(tp, uio) 11587625Ssam register struct tty *tp; 11599578Ssam register struct uio *uio; 11607502Sroot { 11617502Sroot register char *cp; 11629578Ssam register int cc, ce, c; 11639578Ssam int i, hiwat, cnt, error, s; 11647502Sroot char obuf[OBUFSIZ]; 11657502Sroot 11669578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 11678520Sroot return (EIO); 11689578Ssam hiwat = TTHIWAT(tp); 11699578Ssam cnt = uio->uio_resid; 11709578Ssam error = 0; 11717502Sroot loop: 11729578Ssam /* 11739578Ssam * Hang the process if it's in the background. 11749578Ssam */ 11757502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 11769578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 11777502Sroot u.u_signal[SIGTTOU] != SIG_IGN && 11787502Sroot u.u_signal[SIGTTOU] != SIG_HOLD 11797502Sroot /* 11807502Sroot && 11817502Sroot (u.u_procp->p_flag&SDETACH)==0) { 11827502Sroot */ 11837502Sroot ) { 11847502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 11857502Sroot sleep((caddr_t)&lbolt, TTIPRI); 11867502Sroot } 11879578Ssam 11889578Ssam /* 11899578Ssam * Process the user's data in at most OBUFSIZ 11909578Ssam * chunks. Perform lower case simulation and 11919578Ssam * similar hacks. Keep track of high water 11929578Ssam * mark, sleep on overflow awaiting device aid 11939578Ssam * in acquiring new space. 11949578Ssam */ 11957822Sroot while (uio->uio_resid > 0) { 11969578Ssam /* 11979578Ssam * Grab a hunk of data from the user. 11989578Ssam */ 11997822Sroot cc = uio->uio_iov->iov_len; 12007822Sroot if (cc == 0) { 12017822Sroot uio->uio_iovcnt--; 12027822Sroot uio->uio_iov++; 12037822Sroot if (uio->uio_iovcnt < 0) 12047822Sroot panic("ttwrite"); 12057822Sroot continue; 12067822Sroot } 12077822Sroot if (cc > OBUFSIZ) 12087822Sroot cc = OBUFSIZ; 12097502Sroot cp = obuf; 121012752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12118520Sroot if (error) 12127502Sroot break; 12137502Sroot if (tp->t_outq.c_cc > hiwat) 12147502Sroot goto ovhiwat; 12159578Ssam if (tp->t_flags&FLUSHO) 12167502Sroot continue; 12179578Ssam /* 12189578Ssam * If we're mapping lower case or kludging tildes, 12199578Ssam * then we've got to look at each character, so 12209578Ssam * just feed the stuff to ttyoutput... 12219578Ssam */ 12229578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12239578Ssam while (cc > 0) { 12247502Sroot c = *cp++; 12257502Sroot tp->t_rocount = 0; 12267625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12277502Sroot /* out of clists, wait a bit */ 12287502Sroot ttstart(tp); 12297502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12307502Sroot tp->t_rocount = 0; 12317502Sroot } 12327502Sroot --cc; 12337502Sroot if (tp->t_outq.c_cc > hiwat) 12347502Sroot goto ovhiwat; 12357502Sroot } 12367502Sroot continue; 12377502Sroot } 12389578Ssam /* 12399578Ssam * If nothing fancy need be done, grab those characters we 12409578Ssam * can handle without any of ttyoutput's processing and 12419578Ssam * just transfer them to the output q. For those chars 12429578Ssam * which require special processing (as indicated by the 12439578Ssam * bits in partab), call ttyoutput. After processing 12449578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12459578Ssam * immediately. 12469578Ssam */ 12479578Ssam while (cc > 0) { 12489578Ssam if (tp->t_flags & (RAW|LITOUT)) 12497502Sroot ce = cc; 12507502Sroot else { 125112752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 125212752Ssam (caddr_t)partab, 077); 12539578Ssam /* 12549578Ssam * If ce is zero, then we're processing 12559578Ssam * a special character through ttyoutput. 12569578Ssam */ 12579578Ssam if (ce == 0) { 12587502Sroot tp->t_rocount = 0; 12597502Sroot if (ttyoutput(*cp, tp) >= 0) { 12609578Ssam /* no c-lists, wait a bit */ 12617502Sroot ttstart(tp); 12627502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12637502Sroot continue; 12647502Sroot } 12659578Ssam cp++, cc--; 12669578Ssam if (tp->t_flags&FLUSHO || 12679578Ssam tp->t_outq.c_cc > hiwat) 12687502Sroot goto ovhiwat; 12699578Ssam continue; 12707502Sroot } 12717502Sroot } 12729578Ssam /* 12739578Ssam * A bunch of normal characters have been found, 12749578Ssam * transfer them en masse to the output queue and 12759578Ssam * continue processing at the top of the loop. 12769578Ssam * If there are any further characters in this 12779578Ssam * <= OBUFSIZ chunk, the first should be a character 12789578Ssam * requiring special handling by ttyoutput. 12799578Ssam */ 12807502Sroot tp->t_rocount = 0; 12819578Ssam i = b_to_q(cp, ce, &tp->t_outq); 12829578Ssam ce -= i; 12839578Ssam tp->t_col += ce; 12849578Ssam cp += ce, cc -= ce, tk_nout += ce; 12859578Ssam if (i > 0) { 12869578Ssam /* out of c-lists, wait a bit */ 12877502Sroot ttstart(tp); 12887502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12897502Sroot } 12909578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 12917502Sroot goto ovhiwat; 12927502Sroot } 12937502Sroot } 12947502Sroot ttstart(tp); 12958520Sroot return (error); 12967502Sroot 12977502Sroot ovhiwat: 12989578Ssam s = spl5(); 12999578Ssam if (cc != 0) { 13009578Ssam uio->uio_iov->iov_base -= cc; 13019578Ssam uio->uio_iov->iov_len += cc; 13029578Ssam uio->uio_resid += cc; 13039578Ssam uio->uio_offset -= cc; 13049578Ssam } 13059578Ssam /* 13069578Ssam * This can only occur if FLUSHO 13079578Ssam * is also set in t_flags. 13089578Ssam */ 13097502Sroot if (tp->t_outq.c_cc <= hiwat) { 13109578Ssam splx(s); 13117502Sroot goto loop; 13127502Sroot } 13137502Sroot ttstart(tp); 13149578Ssam if (tp->t_state&TS_NBIO) { 13157822Sroot if (uio->uio_resid == cnt) 13168520Sroot return (EWOULDBLOCK); 13178520Sroot return (0); 13187502Sroot } 13197502Sroot tp->t_state |= TS_ASLEEP; 13207502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13219578Ssam splx(s); 13227502Sroot goto loop; 13237502Sroot } 13247502Sroot 13257502Sroot /* 13267502Sroot * Rubout one character from the rawq of tp 13277502Sroot * as cleanly as possible. 13287502Sroot */ 13297502Sroot ttyrub(c, tp) 13307625Ssam register c; 13317625Ssam register struct tty *tp; 13327502Sroot { 13337502Sroot register char *cp; 13347502Sroot register int savecol; 13357502Sroot int s; 13367502Sroot char *nextc(); 13377502Sroot 13389578Ssam if ((tp->t_flags&ECHO) == 0) 13397502Sroot return; 13409578Ssam tp->t_flags &= ~FLUSHO; 13417502Sroot c &= 0377; 13429578Ssam if (tp->t_flags&CRTBS) { 13437502Sroot if (tp->t_rocount == 0) { 13447502Sroot /* 13457502Sroot * Screwed by ttwrite; retype 13467502Sroot */ 13477502Sroot ttyretype(tp); 13487502Sroot return; 13497502Sroot } 13509578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13517502Sroot ttyrubo(tp, 2); 13529578Ssam else switch (partab[c&=0177]&0177) { 13537502Sroot 13547502Sroot case ORDINARY: 13557502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13567502Sroot ttyrubo(tp, 2); 13577502Sroot else 13587502Sroot ttyrubo(tp, 1); 13597502Sroot break; 13607502Sroot 13617502Sroot case VTAB: 13627502Sroot case BACKSPACE: 13637502Sroot case CONTROL: 13647502Sroot case RETURN: 13659578Ssam if (tp->t_flags&CTLECH) 13667502Sroot ttyrubo(tp, 2); 13677502Sroot break; 13687502Sroot 13697502Sroot case TAB: 13707502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 13717502Sroot ttyretype(tp); 13727502Sroot return; 13737502Sroot } 13747502Sroot s = spl5(); 13757502Sroot savecol = tp->t_col; 13769578Ssam tp->t_state |= TS_CNTTB; 13779578Ssam tp->t_flags |= FLUSHO; 13787502Sroot tp->t_col = tp->t_rocol; 13799578Ssam cp = tp->t_rawq.c_cf; 13809578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 13817502Sroot ttyecho(*cp, tp); 13829578Ssam tp->t_flags &= ~FLUSHO; 13839578Ssam tp->t_state &= ~TS_CNTTB; 13847502Sroot splx(s); 13857502Sroot /* 13867502Sroot * savecol will now be length of the tab 13877502Sroot */ 13887502Sroot savecol -= tp->t_col; 13897502Sroot tp->t_col += savecol; 13907502Sroot if (savecol > 8) 13917502Sroot savecol = 8; /* overflow screw */ 13927502Sroot while (--savecol >= 0) 13937502Sroot (void) ttyoutput('\b', tp); 13947502Sroot break; 13957502Sroot 13967502Sroot default: 13977502Sroot panic("ttyrub"); 13987502Sroot } 13999578Ssam } else if (tp->t_flags&PRTERA) { 14009578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14017502Sroot (void) ttyoutput('\\', tp); 14029578Ssam tp->t_state |= TS_ERASE; 14037502Sroot } 14047502Sroot ttyecho(c, tp); 14057502Sroot } else 14067502Sroot ttyecho(tp->t_erase, tp); 14077502Sroot tp->t_rocount--; 14087502Sroot } 14097502Sroot 14107502Sroot /* 14117502Sroot * Crt back over cnt chars perhaps 14127502Sroot * erasing them. 14137502Sroot */ 14147502Sroot ttyrubo(tp, cnt) 14157625Ssam register struct tty *tp; 14167625Ssam int cnt; 14177502Sroot { 14189578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14197502Sroot 14207502Sroot while (--cnt >= 0) 14219578Ssam ttyout(rubostring, tp); 14227502Sroot } 14237502Sroot 14247502Sroot /* 14257502Sroot * Reprint the rawq line. 14267502Sroot * We assume c_cc has already been checked. 14277502Sroot */ 14287502Sroot ttyretype(tp) 14297625Ssam register struct tty *tp; 14307502Sroot { 14317502Sroot register char *cp; 14327502Sroot char *nextc(); 14337502Sroot int s; 14347502Sroot 14359578Ssam if (tp->t_rprntc != 0377) 14369578Ssam ttyecho(tp->t_rprntc, tp); 14377502Sroot (void) ttyoutput('\n', tp); 14387502Sroot s = spl5(); 14397502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14407502Sroot ttyecho(*cp, tp); 14417502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14427502Sroot ttyecho(*cp, tp); 14439578Ssam tp->t_state &= ~TS_ERASE; 14447502Sroot splx(s); 14457502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14467502Sroot tp->t_rocol = 0; 14477502Sroot } 14487502Sroot 14497502Sroot /* 14507502Sroot * Echo a typed character to the terminal 14517502Sroot */ 14527502Sroot ttyecho(c, tp) 14537625Ssam register c; 14547625Ssam register struct tty *tp; 14557502Sroot { 14567502Sroot 14579578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14589578Ssam tp->t_flags &= ~FLUSHO; 14597502Sroot if ((tp->t_flags&ECHO) == 0) 14607502Sroot return; 14617502Sroot c &= 0377; 14627502Sroot if (tp->t_flags&RAW) { 14637502Sroot (void) ttyoutput(c, tp); 14647502Sroot return; 14657502Sroot } 14667502Sroot if (c == '\r' && tp->t_flags&CRMOD) 14677502Sroot c = '\n'; 14689578Ssam if (tp->t_flags&CTLECH) { 14697502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 14707502Sroot (void) ttyoutput('^', tp); 14717502Sroot c &= 0177; 14727502Sroot if (c == 0177) 14737502Sroot c = '?'; 14747502Sroot else if (tp->t_flags&LCASE) 14757502Sroot c += 'a' - 1; 14767502Sroot else 14777502Sroot c += 'A' - 1; 14787502Sroot } 14797502Sroot } 14807502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 14817502Sroot c += 'a' - 'A'; 14829578Ssam (void) ttyoutput(c&0177, tp); 14837502Sroot } 14847502Sroot 14857502Sroot /* 14867502Sroot * Is c a break char for tp? 14877502Sroot */ 14887502Sroot ttbreakc(c, tp) 14897625Ssam register c; 14907625Ssam register struct tty *tp; 14917502Sroot { 14929578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 14937502Sroot c == '\r' && (tp->t_flags&CRMOD)); 14947502Sroot } 14957502Sroot 14967502Sroot /* 14977502Sroot * send string cp to tp 14987502Sroot */ 14997502Sroot ttyout(cp, tp) 15007625Ssam register char *cp; 15017625Ssam register struct tty *tp; 15027502Sroot { 15037502Sroot register char c; 15047502Sroot 15057502Sroot while (c = *cp++) 15067502Sroot (void) ttyoutput(c, tp); 15077502Sroot } 15087502Sroot 15097502Sroot ttwakeup(tp) 15107502Sroot struct tty *tp; 15117502Sroot { 15127502Sroot 15137502Sroot if (tp->t_rsel) { 15147502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15157502Sroot tp->t_state &= ~TS_RCOLL; 15167502Sroot tp->t_rsel = 0; 15177502Sroot } 151812752Ssam if (tp->t_state & TS_ASYNC) 151912752Ssam gsignal(tp->t_pgrp, SIGIO); 15207502Sroot wakeup((caddr_t)&tp->t_rawq); 15217502Sroot } 15227502Sroot 152313533Ssam #if !defined(vax) 15249578Ssam scanc(size, cp, table, mask) 15259578Ssam register int size; 15269578Ssam register char *cp, table[]; 15279578Ssam register int mask; 15287502Sroot { 15299578Ssam register int i = 0; 15307502Sroot 15319578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15329578Ssam i++; 15339578Ssam return (i); 15347502Sroot } 15359578Ssam #endif 1536