1*17598Sbloom /* tty.c 6.13 84/12/31 */ 239Sbill 39760Ssam #include "../machine/reg.h" 49760Ssam 517095Sbloom #include "param.h" 617095Sbloom #include "systm.h" 717095Sbloom #include "dir.h" 817095Sbloom #include "user.h" 917095Sbloom #include "ioctl.h" 1017095Sbloom #include "tty.h" 1117095Sbloom #include "proc.h" 1217095Sbloom #include "inode.h" 1317095Sbloom #include "file.h" 1417095Sbloom #include "conf.h" 1517095Sbloom #include "buf.h" 1617095Sbloom #include "dk.h" 1717095Sbloom #include "uio.h" 1817095Sbloom #include "kernel.h" 1939Sbill 207436Skre /* 217436Skre * Table giving parity for characters and indicating 227436Skre * character classes to tty driver. In particular, 237436Skre * if the low 6 bits are 0, then the character needs 247436Skre * no special processing on output. 257436Skre */ 2639Sbill 277436Skre char partab[] = { 287436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 297436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 307436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 317436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 327436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 337436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 347436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 357436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 407436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 447436Skre 457436Skre /* 467436Skre * 7 bit ascii ends with the last character above, 477436Skre * but we contine through all 256 codes for the sake 487436Skre * of the tty output routines which use special vax 497436Skre * instructions which need a 256 character trt table. 507436Skre */ 517436Skre 527436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 537436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 547436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 557436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 567436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 577436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007 687436Skre }; 697436Skre 70146Sbill /* 7139Sbill * Input mapping table-- if an entry is non-zero, when the 7239Sbill * corresponding character is typed preceded by "\" the escape 7339Sbill * sequence is replaced by the table value. Mostly used for 7439Sbill * upper-case only terminals. 7539Sbill */ 7639Sbill char maptab[] ={ 7739Sbill 000,000,000,000,000,000,000,000, 7839Sbill 000,000,000,000,000,000,000,000, 7939Sbill 000,000,000,000,000,000,000,000, 8039Sbill 000,000,000,000,000,000,000,000, 8139Sbill 000,'|',000,000,000,000,000,'`', 8239Sbill '{','}',000,000,000,000,000,000, 8339Sbill 000,000,000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,000,000,000,000,000,000,000, 8639Sbill 000,000,000,000,000,000,000,000, 8739Sbill 000,000,000,000,000,000,000,000, 8839Sbill 000,000,000,000,000,000,'~',000, 8939Sbill 000,'A','B','C','D','E','F','G', 9039Sbill 'H','I','J','K','L','M','N','O', 9139Sbill 'P','Q','R','S','T','U','V','W', 9239Sbill 'X','Y','Z',000,000,000,000,000, 9339Sbill }; 9439Sbill 95925Sbill short tthiwat[16] = 968954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 97925Sbill short ttlowat[16] = 98925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 99925Sbill 1009578Ssam struct ttychars ttydefaults = { 1019578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1029578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1039578Ssam }; 10439Sbill 10539Sbill ttychars(tp) 1069578Ssam struct tty *tp; 10739Sbill { 108174Sbill 1099578Ssam tp->t_chars = ttydefaults; 11039Sbill } 11139Sbill 11239Sbill /* 113903Sbill * Wait for output to drain, then flush input waiting. 11439Sbill */ 11512752Ssam ttywflush(tp) 1165408Swnj register struct tty *tp; 11739Sbill { 11839Sbill 11912752Ssam ttywait(tp); 12012752Ssam ttyflush(tp, FREAD); 12112752Ssam } 12212752Ssam 12312752Ssam ttywait(tp) 12412752Ssam register struct tty *tp; 12512752Ssam { 12617545Skarels register int s = spltty(); 12712752Ssam 12813809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 12913809Ssam tp->t_state&TS_CARR_ON && tp->t_oproc) { /* kludge for pty */ 130903Sbill (*tp->t_oproc)(tp); 1315408Swnj tp->t_state |= TS_ASLEEP; 132903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 133903Sbill } 1349859Ssam splx(s); 13539Sbill } 13639Sbill 13739Sbill /* 1389578Ssam * Flush all TTY queues 13939Sbill */ 14012752Ssam ttyflush(tp, rw) 1417625Ssam register struct tty *tp; 14239Sbill { 143903Sbill register s; 144903Sbill 14517545Skarels s = spltty(); 146903Sbill if (rw & FREAD) { 147903Sbill while (getc(&tp->t_canq) >= 0) 148903Sbill ; 149903Sbill wakeup((caddr_t)&tp->t_rawq); 150903Sbill } 151903Sbill if (rw & FWRITE) { 152903Sbill wakeup((caddr_t)&tp->t_outq); 1535408Swnj tp->t_state &= ~TS_TTSTOP; 1545426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 155903Sbill while (getc(&tp->t_outq) >= 0) 156903Sbill ; 157903Sbill } 158903Sbill if (rw & FREAD) { 159903Sbill while (getc(&tp->t_rawq) >= 0) 160903Sbill ; 1619578Ssam tp->t_rocount = 0; 162903Sbill tp->t_rocol = 0; 1639578Ssam tp->t_state &= ~TS_LOCAL; 164903Sbill } 165903Sbill splx(s); 16639Sbill } 16739Sbill 168903Sbill /* 169903Sbill * Send stop character on input overflow. 170903Sbill */ 171903Sbill ttyblock(tp) 1727625Ssam register struct tty *tp; 17339Sbill { 174903Sbill register x; 1759578Ssam 176903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 177903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 17812752Ssam ttyflush(tp, FREAD|FWRITE); 1795408Swnj tp->t_state &= ~TS_TBLOCK; 180903Sbill } 18115118Skarels /* 18215118Skarels * Block further input iff: 18315118Skarels * Current input > threshold AND input is available to user program 18415118Skarels */ 18516055Skarels if (x >= TTYHOG/2 && 18616055Skarels ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) { 18715118Skarels if (putc(tp->t_stopc, &tp->t_outq)==0) { 18815118Skarels tp->t_state |= TS_TBLOCK; 18915118Skarels ttstart(tp); 19015118Skarels } 191903Sbill } 19239Sbill } 19339Sbill 19439Sbill /* 195903Sbill * Restart typewriter output following a delay 196903Sbill * timeout. 197903Sbill * The name of the routine is passed to the timeout 198903Sbill * subroutine and it is called during a clock interrupt. 199121Sbill */ 200903Sbill ttrstrt(tp) 2017625Ssam register struct tty *tp; 202121Sbill { 203121Sbill 2049578Ssam if (tp == 0) 2059578Ssam panic("ttrstrt"); 2065408Swnj tp->t_state &= ~TS_TIMEOUT; 207903Sbill ttstart(tp); 208121Sbill } 209121Sbill 210121Sbill /* 211903Sbill * Start output on the typewriter. It is used from the top half 212903Sbill * after some characters have been put on the output queue, 213903Sbill * from the interrupt routine to transmit the next 214903Sbill * character, and after a timeout has finished. 21539Sbill */ 216903Sbill ttstart(tp) 2177625Ssam register struct tty *tp; 21839Sbill { 219903Sbill register s; 22039Sbill 22117545Skarels s = spltty(); 2229578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2235622Swnj tp->t_oproc) /* kludge for pty */ 224903Sbill (*tp->t_oproc)(tp); 225903Sbill splx(s); 22639Sbill } 22739Sbill 22839Sbill /* 229903Sbill * Common code for tty ioctls. 23039Sbill */ 2311780Sbill /*ARGSUSED*/ 2327625Ssam ttioctl(tp, com, data, flag) 2337625Ssam register struct tty *tp; 2347625Ssam caddr_t data; 23539Sbill { 2368520Sroot int dev = tp->t_dev; 23739Sbill extern int nldisp; 2388556Sroot int s; 23912752Ssam register int newflags; 24039Sbill 241903Sbill /* 242903Sbill * If the ioctl involves modification, 24317545Skarels * hang if in the background. 244903Sbill */ 2457625Ssam switch (com) { 24639Sbill 247915Sbill case TIOCSETD: 248915Sbill case TIOCSETP: 249915Sbill case TIOCSETN: 250903Sbill case TIOCFLUSH: 251903Sbill case TIOCSETC: 252903Sbill case TIOCSLTC: 253903Sbill case TIOCSPGRP: 254903Sbill case TIOCLBIS: 255903Sbill case TIOCLBIC: 256903Sbill case TIOCLSET: 2579325Ssam case TIOCSTI: 258*17598Sbloom case TIOCSWINSZ: 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); 28917545Skarels s = spltty(); 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) { 29617545Skarels s = spltty(); 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: 34117545Skarels s = spltty(); 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: 35017545Skarels s = spltty(); 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: 36317183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36417183Smckusick return (EPERM); 3659325Ssam if (u.u_uid && u.u_ttyp != tp) 3669325Ssam return (EACCES); 3679578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3689325Ssam break; 3699325Ssam 37012752Ssam case TIOCSETP: 37112752Ssam case TIOCSETN: { 37212752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37312752Ssam 37412752Ssam tp->t_erase = sg->sg_erase; 37512752Ssam tp->t_kill = sg->sg_kill; 37612752Ssam tp->t_ispeed = sg->sg_ispeed; 37712752Ssam tp->t_ospeed = sg->sg_ospeed; 37812752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37917545Skarels s = spltty(); 38012752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38112752Ssam ttywait(tp); 38212752Ssam ttyflush(tp, FREAD); 38312752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38412752Ssam if (newflags&CBREAK) { 38512752Ssam struct clist tq; 38612752Ssam 38712752Ssam catq(&tp->t_rawq, &tp->t_canq); 38812752Ssam tq = tp->t_rawq; 38912752Ssam tp->t_rawq = tp->t_canq; 39012752Ssam tp->t_canq = tq; 39112752Ssam } else { 39212752Ssam tp->t_flags |= PENDIN; 39313801Ssam newflags |= PENDIN; 39412752Ssam ttwakeup(tp); 39512752Ssam } 39612752Ssam } 39712752Ssam tp->t_flags = newflags; 39812752Ssam if (tp->t_flags&RAW) { 39912752Ssam tp->t_state &= ~TS_TTSTOP; 40012752Ssam ttstart(tp); 40112752Ssam } 40212752Ssam splx(s); 40312752Ssam break; 40412752Ssam } 40512752Ssam 40612752Ssam /* send current parameters to user */ 40712752Ssam case TIOCGETP: { 40812752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40912752Ssam 41012752Ssam sg->sg_ispeed = tp->t_ispeed; 41112752Ssam sg->sg_ospeed = tp->t_ospeed; 41212752Ssam sg->sg_erase = tp->t_erase; 41312752Ssam sg->sg_kill = tp->t_kill; 41412752Ssam sg->sg_flags = tp->t_flags; 41512752Ssam break; 41612752Ssam } 41712752Ssam 41812752Ssam case FIONBIO: 41912752Ssam if (*(int *)data) 42012752Ssam tp->t_state |= TS_NBIO; 42112752Ssam else 42212752Ssam tp->t_state &= ~TS_NBIO; 42312752Ssam break; 42412752Ssam 42512752Ssam case FIOASYNC: 42612752Ssam if (*(int *)data) 42712752Ssam tp->t_state |= TS_ASYNC; 42812752Ssam else 42912752Ssam tp->t_state &= ~TS_ASYNC; 43012752Ssam break; 43112752Ssam 43213077Ssam case TIOCGETC: 43313077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43413077Ssam break; 43513077Ssam 43613077Ssam case TIOCSETC: 43713077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43813077Ssam break; 43913077Ssam 44012752Ssam /* set/get local special characters */ 44112752Ssam case TIOCSLTC: 44212752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44312752Ssam break; 44412752Ssam 44512752Ssam case TIOCGLTC: 44612752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44712752Ssam break; 44812752Ssam 44912752Ssam /* 45012752Ssam * Modify local mode word. 45112752Ssam */ 45212752Ssam case TIOCLBIS: 45312752Ssam tp->t_flags |= *(int *)data << 16; 45412752Ssam break; 45512752Ssam 45612752Ssam case TIOCLBIC: 45712752Ssam tp->t_flags &= ~(*(int *)data << 16); 45812752Ssam break; 45912752Ssam 46012752Ssam case TIOCLSET: 46112752Ssam tp->t_flags &= 0xffff; 46212752Ssam tp->t_flags |= *(int *)data << 16; 46312752Ssam break; 46412752Ssam 46512752Ssam case TIOCLGET: 46615720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46712752Ssam break; 46812752Ssam 46917545Skarels /* 47017545Skarels * Allow SPGRP only if tty is ours and is open for reading. 471*17598Sbloom * Quick check: if we can find a process in the new pgrp, 472*17598Sbloom * this user must own that process. 473*17598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47417545Skarels */ 47512752Ssam case TIOCSPGRP: 47617545Skarels { 47717545Skarels struct proc *p; 47817545Skarels int pgrp = *(int *)data; 47917545Skarels 48017545Skarels if (u.u_uid && (flag & FREAD) == 0) 48117545Skarels return (EPERM); 48217545Skarels if (u.u_uid && u.u_ttyp != tp) 48317545Skarels return (EACCES); 484*17598Sbloom p = pfind(pgrp); 485*17598Sbloom if (p && p->p_pgrp == pgrp && 486*17598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 487*17598Sbloom return (EPERM); 48817545Skarels tp->t_pgrp = pgrp; 48912752Ssam break; 49017545Skarels } 49112752Ssam 49212752Ssam case TIOCGPGRP: 49312752Ssam *(int *)data = tp->t_pgrp; 49412752Ssam break; 49512752Ssam 496*17598Sbloom case TIOCSWINSZ: 497*17598Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 498*17598Sbloom sizeof(struct winsize))) { 499*17598Sbloom tp->t_winsize = *(struct winsize *)data; 500*17598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 501*17598Sbloom } 502*17598Sbloom break; 503*17598Sbloom 504*17598Sbloom case TIOCGWINSZ: 505*17598Sbloom *(struct winsize *)data = tp->t_winsize; 506*17598Sbloom break; 507*17598Sbloom 50839Sbill default: 5098556Sroot return (-1); 51039Sbill } 5118556Sroot return (0); 51239Sbill } 5134484Swnj 5144484Swnj ttnread(tp) 5154484Swnj struct tty *tp; 5164484Swnj { 5174484Swnj int nread = 0; 5184484Swnj 5199578Ssam if (tp->t_flags & PENDIN) 5204484Swnj ttypend(tp); 5214484Swnj nread = tp->t_canq.c_cc; 5224484Swnj if (tp->t_flags & (RAW|CBREAK)) 5234484Swnj nread += tp->t_rawq.c_cc; 5244484Swnj return (nread); 5254484Swnj } 5264484Swnj 5275408Swnj ttselect(dev, rw) 5284484Swnj dev_t dev; 5295408Swnj int rw; 5304484Swnj { 5314484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5324484Swnj int nread; 53317545Skarels int s = spltty(); 5344484Swnj 5355408Swnj switch (rw) { 5364484Swnj 5374484Swnj case FREAD: 5384484Swnj nread = ttnread(tp); 5394484Swnj if (nread > 0) 5405408Swnj goto win; 5414938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5425408Swnj tp->t_state |= TS_RCOLL; 5434484Swnj else 5444484Swnj tp->t_rsel = u.u_procp; 5455408Swnj break; 5464484Swnj 5475408Swnj case FWRITE: 5485408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5495408Swnj goto win; 5505408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5515408Swnj tp->t_state |= TS_WCOLL; 5525408Swnj else 5535408Swnj tp->t_wsel = u.u_procp; 5545408Swnj break; 5554484Swnj } 5565408Swnj splx(s); 5575408Swnj return (0); 5585408Swnj win: 5595408Swnj splx(s); 5605408Swnj return (1); 5614484Swnj } 5627436Skre 5637502Sroot /* 5649578Ssam * Establish a process group for distribution of 5657502Sroot * quits and interrupts from the tty. 5667502Sroot */ 5677502Sroot ttyopen(dev, tp) 5687625Ssam dev_t dev; 5697625Ssam register struct tty *tp; 5707502Sroot { 5717502Sroot register struct proc *pp; 5727502Sroot 5737502Sroot pp = u.u_procp; 5747502Sroot tp->t_dev = dev; 5757625Ssam if (pp->p_pgrp == 0) { 5767502Sroot u.u_ttyp = tp; 5777502Sroot u.u_ttyd = dev; 5787502Sroot if (tp->t_pgrp == 0) 5797502Sroot tp->t_pgrp = pp->p_pid; 5807502Sroot pp->p_pgrp = tp->t_pgrp; 5817502Sroot } 5827502Sroot tp->t_state &= ~TS_WOPEN; 58317545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 58417545Skarels tp->t_state |= TS_ISOPEN; 585*17598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58617545Skarels if (tp->t_line != NTTYDISC) 58717545Skarels ttywflush(tp); 58817545Skarels } 5898556Sroot return (0); 5907502Sroot } 5917502Sroot 5927502Sroot /* 5937502Sroot * clean tp on last close 5947502Sroot */ 5957502Sroot ttyclose(tp) 5967625Ssam register struct tty *tp; 5977502Sroot { 5987502Sroot 5997502Sroot if (tp->t_line) { 60012752Ssam ttywflush(tp); 6017502Sroot tp->t_line = 0; 6027502Sroot return; 6037502Sroot } 6047502Sroot tp->t_pgrp = 0; 60512752Ssam ttywflush(tp); 6067502Sroot tp->t_state = 0; 6077502Sroot } 6087502Sroot 6097502Sroot /* 6107502Sroot * reinput pending characters after state switch 61117545Skarels * call at spltty(). 6127502Sroot */ 6137502Sroot ttypend(tp) 6147625Ssam register struct tty *tp; 6157502Sroot { 6167502Sroot struct clist tq; 6177502Sroot register c; 6187502Sroot 6199578Ssam tp->t_flags &= ~PENDIN; 6209578Ssam tp->t_state |= TS_TYPEN; 6217502Sroot tq = tp->t_rawq; 6227502Sroot tp->t_rawq.c_cc = 0; 6237502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6247502Sroot while ((c = getc(&tq)) >= 0) 6257502Sroot ttyinput(c, tp); 6269578Ssam tp->t_state &= ~TS_TYPEN; 6277502Sroot } 6287502Sroot 6297502Sroot /* 6309578Ssam * Place a character on raw TTY input queue, 6319578Ssam * putting in delimiters and waking up top 6329578Ssam * half as needed. Also echo if required. 6339578Ssam * The arguments are the character and the 6349578Ssam * appropriate tty structure. 6357502Sroot */ 6367502Sroot ttyinput(c, tp) 6377625Ssam register c; 6387625Ssam register struct tty *tp; 6397502Sroot { 6409578Ssam register int t_flags = tp->t_flags; 6417502Sroot int i; 6427502Sroot 6439578Ssam /* 6449578Ssam * If input is pending take it first. 6459578Ssam */ 6469578Ssam if (t_flags&PENDIN) 6477502Sroot ttypend(tp); 6487502Sroot tk_nin++; 6497502Sroot c &= 0377; 6509578Ssam 6519578Ssam /* 6529578Ssam * In tandem mode, check high water mark. 6539578Ssam */ 6547502Sroot if (t_flags&TANDEM) 6557502Sroot ttyblock(tp); 6569578Ssam 6579578Ssam if (t_flags&RAW) { 6589578Ssam /* 6599578Ssam * Raw mode, just put character 6609578Ssam * in input q w/o interpretation. 6619578Ssam */ 6629578Ssam if (tp->t_rawq.c_cc > TTYHOG) 66312752Ssam ttyflush(tp, FREAD|FWRITE); 6649578Ssam else { 6659578Ssam if (putc(c, &tp->t_rawq) >= 0) 6669578Ssam ttwakeup(tp); 6679578Ssam ttyecho(c, tp); 6687502Sroot } 6699578Ssam goto endcase; 6709578Ssam } 6719578Ssam 6729578Ssam /* 6739578Ssam * Ignore any high bit added during 6749578Ssam * previous ttyinput processing. 6759578Ssam */ 6769578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6779578Ssam c &= 0177; 6789578Ssam /* 6799578Ssam * Check for literal nexting very first 6809578Ssam */ 6819578Ssam if (tp->t_state&TS_LNCH) { 6829578Ssam c |= 0200; 6839578Ssam tp->t_state &= ~TS_LNCH; 6849578Ssam } 6859578Ssam 6869578Ssam /* 6879578Ssam * Scan for special characters. This code 6889578Ssam * is really just a big case statement with 6899578Ssam * non-constant cases. The bottom of the 6909578Ssam * case statement is labeled ``endcase'', so goto 6919578Ssam * it after a case match, or similar. 6929578Ssam */ 6939578Ssam if (tp->t_line == NTTYDISC) { 6949578Ssam if (c == tp->t_lnextc) { 6957502Sroot if (tp->t_flags&ECHO) 6967502Sroot ttyout("^\b", tp); 6979578Ssam tp->t_state |= TS_LNCH; 6989578Ssam goto endcase; 6999578Ssam } 7009578Ssam if (c == tp->t_flushc) { 7019578Ssam if (tp->t_flags&FLUSHO) 7029578Ssam tp->t_flags &= ~FLUSHO; 7037502Sroot else { 70412752Ssam ttyflush(tp, FWRITE); 7057502Sroot ttyecho(c, tp); 7069578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7077502Sroot ttyretype(tp); 7089578Ssam tp->t_flags |= FLUSHO; 7097502Sroot } 7109578Ssam goto startoutput; 7119578Ssam } 7129578Ssam if (c == tp->t_suspc) { 7139578Ssam if ((tp->t_flags&NOFLSH) == 0) 71412752Ssam ttyflush(tp, FREAD); 7159578Ssam ttyecho(c, tp); 7169578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7179578Ssam goto endcase; 7189578Ssam } 7199578Ssam } 7209578Ssam 7219578Ssam /* 7229578Ssam * Handle start/stop characters. 7239578Ssam */ 7249578Ssam if (c == tp->t_stopc) { 7259578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7269578Ssam tp->t_state |= TS_TTSTOP; 7279578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7287502Sroot return; 7299578Ssam } 7309578Ssam if (c != tp->t_startc) 7319578Ssam return; 7329578Ssam goto endcase; 7339578Ssam } 7349578Ssam if (c == tp->t_startc) 7359578Ssam goto restartoutput; 7369578Ssam 7379578Ssam /* 7389578Ssam * Look for interrupt/quit chars. 7399578Ssam */ 7409578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7419578Ssam if ((tp->t_flags&NOFLSH) == 0) 74212752Ssam ttyflush(tp, FREAD|FWRITE); 7439578Ssam ttyecho(c, tp); 7449578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7459578Ssam goto endcase; 7469578Ssam } 7479578Ssam 7489578Ssam /* 7499578Ssam * Cbreak mode, don't process line editing 7509578Ssam * characters; check high water mark for wakeup. 7519578Ssam */ 7529578Ssam if (t_flags&CBREAK) { 7539578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7547502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7557502Sroot tp->t_line == NTTYDISC) 7567502Sroot (void) ttyoutput(CTRL(g), tp); 7577502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7587502Sroot ttwakeup(tp); 7597502Sroot ttyecho(c, tp); 7607502Sroot } 7619578Ssam goto endcase; 7629578Ssam } 7639578Ssam 7649578Ssam /* 7659578Ssam * From here on down cooked mode character 7669578Ssam * processing takes place. 7679578Ssam */ 7689578Ssam if ((tp->t_state&TS_QUOT) && 7699578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7709578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7719578Ssam c |= 0200; 7729578Ssam } 7739578Ssam if (c == tp->t_erase) { 7749578Ssam if (tp->t_rawq.c_cc) 7759578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7769578Ssam goto endcase; 7779578Ssam } 7789578Ssam if (c == tp->t_kill) { 7799578Ssam if (tp->t_flags&CRTKIL && 7809578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7819578Ssam while (tp->t_rawq.c_cc) 7829578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7839578Ssam } else { 7849578Ssam ttyecho(c, tp); 7859578Ssam ttyecho('\n', tp); 7869578Ssam while (getc(&tp->t_rawq) > 0) 7879578Ssam ; 7889578Ssam tp->t_rocount = 0; 7899578Ssam } 7909578Ssam tp->t_state &= ~TS_LOCAL; 7919578Ssam goto endcase; 7929578Ssam } 7939578Ssam 7949578Ssam /* 7959578Ssam * New line discipline, 7969578Ssam * check word erase/reprint line. 7979578Ssam */ 7989578Ssam if (tp->t_line == NTTYDISC) { 7999578Ssam if (c == tp->t_werasc) { 8009578Ssam if (tp->t_rawq.c_cc == 0) 8019578Ssam goto endcase; 8029578Ssam do { 8039578Ssam c = unputc(&tp->t_rawq); 8049578Ssam if (c != ' ' && c != '\t') 8059578Ssam goto erasenb; 8069578Ssam ttyrub(c, tp); 8079578Ssam } while (tp->t_rawq.c_cc); 8089578Ssam goto endcase; 8099578Ssam erasenb: 8109578Ssam do { 8119578Ssam ttyrub(c, tp); 8129578Ssam if (tp->t_rawq.c_cc == 0) 8139578Ssam goto endcase; 8149578Ssam c = unputc(&tp->t_rawq); 8159578Ssam } while (c != ' ' && c != '\t'); 8169578Ssam (void) putc(c, &tp->t_rawq); 8179578Ssam goto endcase; 8189578Ssam } 8199578Ssam if (c == tp->t_rprntc) { 8209578Ssam ttyretype(tp); 8219578Ssam goto endcase; 8229578Ssam } 8239578Ssam } 8249578Ssam 8259578Ssam /* 8269578Ssam * Check for input buffer overflow 8279578Ssam */ 82810391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 82910391Ssam if (tp->t_line == NTTYDISC) 83010391Ssam (void) ttyoutput(CTRL(g), tp); 8319578Ssam goto endcase; 83210391Ssam } 8339578Ssam 8349578Ssam /* 8359578Ssam * Put data char in q for user and 8369578Ssam * wakeup on seeing a line delimiter. 8379578Ssam */ 8389578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8399578Ssam if (ttbreakc(c, tp)) { 8409578Ssam tp->t_rocount = 0; 8419578Ssam catq(&tp->t_rawq, &tp->t_canq); 8427502Sroot ttwakeup(tp); 8439578Ssam } else if (tp->t_rocount++ == 0) 8449578Ssam tp->t_rocol = tp->t_col; 8459578Ssam tp->t_state &= ~TS_QUOT; 8469578Ssam if (c == '\\') 8479578Ssam tp->t_state |= TS_QUOT; 8489578Ssam if (tp->t_state&TS_ERASE) { 8499578Ssam tp->t_state &= ~TS_ERASE; 8509578Ssam (void) ttyoutput('/', tp); 8519578Ssam } 8529578Ssam i = tp->t_col; 8537502Sroot ttyecho(c, tp); 8549578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8559578Ssam i = MIN(2, tp->t_col - i); 8569578Ssam while (i > 0) { 8579578Ssam (void) ttyoutput('\b', tp); 8589578Ssam i--; 8599578Ssam } 8609578Ssam } 8617502Sroot } 8629578Ssam 8639578Ssam endcase: 8649578Ssam /* 8659578Ssam * If DEC-style start/stop is enabled don't restart 8669578Ssam * output until seeing the start character. 8679578Ssam */ 8689578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8699578Ssam tp->t_startc != tp->t_stopc) 8707502Sroot return; 8719578Ssam 8729578Ssam restartoutput: 8737502Sroot tp->t_state &= ~TS_TTSTOP; 8749578Ssam tp->t_flags &= ~FLUSHO; 8759578Ssam 8769578Ssam startoutput: 8777502Sroot ttstart(tp); 8787502Sroot } 8797502Sroot 8807502Sroot /* 8819578Ssam * Put character on TTY output queue, adding delays, 8827502Sroot * expanding tabs, and handling the CR/NL bit. 8839578Ssam * This is called both from the top half for output, 8849578Ssam * and from interrupt level for echoing. 8857502Sroot * The arguments are the character and the tty structure. 8867502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8877502Sroot * Must be recursive. 8887502Sroot */ 8897502Sroot ttyoutput(c, tp) 8907502Sroot register c; 8917502Sroot register struct tty *tp; 8927502Sroot { 8937502Sroot register char *colp; 8947502Sroot register ctype; 8957502Sroot 8969578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8979578Ssam if (tp->t_flags&FLUSHO) 8987502Sroot return (-1); 8997502Sroot if (putc(c, &tp->t_outq)) 9007625Ssam return (c); 9017502Sroot tk_nout++; 9027502Sroot return (-1); 9037502Sroot } 9049578Ssam 9057502Sroot /* 9069578Ssam * Ignore EOT in normal mode to avoid 9079578Ssam * hanging up certain terminals. 9087502Sroot */ 9097502Sroot c &= 0177; 9109578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9117502Sroot return (-1); 9127502Sroot /* 9137502Sroot * Turn tabs to spaces as required 9147502Sroot */ 9159578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9167502Sroot register int s; 9177502Sroot 9187502Sroot c = 8 - (tp->t_col&7); 9199578Ssam if ((tp->t_flags&FLUSHO) == 0) { 92017545Skarels s = spltty(); /* don't interrupt tabs */ 9217502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9227502Sroot tk_nout += c; 9237502Sroot splx(s); 9247502Sroot } 9257502Sroot tp->t_col += c; 9267502Sroot return (c ? -1 : '\t'); 9277502Sroot } 9287502Sroot tk_nout++; 9297502Sroot /* 9307502Sroot * for upper-case-only terminals, 9317502Sroot * generate escapes. 9327502Sroot */ 9337502Sroot if (tp->t_flags&LCASE) { 9347502Sroot colp = "({)}!|^~'`"; 9357625Ssam while (*colp++) 9367625Ssam if (c == *colp++) { 9377502Sroot if (ttyoutput('\\', tp) >= 0) 9387502Sroot return (c); 9397502Sroot c = colp[-2]; 9407502Sroot break; 9417502Sroot } 9429578Ssam if ('A' <= c && c <= 'Z') { 9437502Sroot if (ttyoutput('\\', tp) >= 0) 9447502Sroot return (c); 9459578Ssam } else if ('a' <= c && c <= 'z') 9467502Sroot c += 'A' - 'a'; 9477502Sroot } 9489578Ssam 9497502Sroot /* 9507502Sroot * turn <nl> to <cr><lf> if desired. 9517502Sroot */ 9529578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9537502Sroot if (ttyoutput('\r', tp) >= 0) 9547502Sroot return (c); 9559578Ssam if (c == '~' && tp->t_flags&TILDE) 9567502Sroot c = '`'; 9579578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9587502Sroot return (c); 9597502Sroot /* 9607502Sroot * Calculate delays. 9617502Sroot * The numbers here represent clock ticks 9627502Sroot * and are not necessarily optimal for all terminals. 9637502Sroot * The delays are indicated by characters above 0200. 9647502Sroot * In raw mode there are no delays and the 9657502Sroot * transmission path is 8 bits wide. 9669578Ssam * 9679578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9687502Sroot */ 9697502Sroot colp = &tp->t_col; 9707502Sroot ctype = partab[c]; 9717502Sroot c = 0; 9727502Sroot switch (ctype&077) { 9737502Sroot 9747502Sroot case ORDINARY: 9757502Sroot (*colp)++; 9767502Sroot 9777502Sroot case CONTROL: 9787502Sroot break; 9797502Sroot 9807502Sroot case BACKSPACE: 9817502Sroot if (*colp) 9827502Sroot (*colp)--; 9837502Sroot break; 9847502Sroot 98513821Ssam /* 98613821Ssam * This macro is close enough to the correct thing; 98713821Ssam * it should be replaced by real user settable delays 98813821Ssam * in any event... 98913821Ssam */ 99013821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9917502Sroot case NEWLINE: 9927502Sroot ctype = (tp->t_flags >> 8) & 03; 9937625Ssam if (ctype == 1) { /* tty 37 */ 99412752Ssam if (*colp > 0) 99513863Ssam c = max((((unsigned)*colp) >> 4) + 3, 99613863Ssam (unsigned)6); 9979578Ssam } else if (ctype == 2) /* vt05 */ 99813821Ssam c = mstohz(100); 9997502Sroot *colp = 0; 10007502Sroot break; 10017502Sroot 10027502Sroot case TAB: 10037502Sroot ctype = (tp->t_flags >> 10) & 03; 10047625Ssam if (ctype == 1) { /* tty 37 */ 10057502Sroot c = 1 - (*colp | ~07); 10067625Ssam if (c < 5) 10077502Sroot c = 0; 10087502Sroot } 10097502Sroot *colp |= 07; 10107502Sroot (*colp)++; 10117502Sroot break; 10127502Sroot 10137502Sroot case VTAB: 10149578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10157502Sroot c = 0177; 10167502Sroot break; 10177502Sroot 10187502Sroot case RETURN: 10197502Sroot ctype = (tp->t_flags >> 12) & 03; 10209578Ssam if (ctype == 1) /* tn 300 */ 102113821Ssam c = mstohz(83); 10229578Ssam else if (ctype == 2) /* ti 700 */ 102313821Ssam c = mstohz(166); 10249578Ssam else if (ctype == 3) { /* concept 100 */ 10257502Sroot int i; 10269578Ssam 10277502Sroot if ((i = *colp) >= 0) 10289578Ssam for (; i < 9; i++) 10297502Sroot (void) putc(0177, &tp->t_outq); 10307502Sroot } 10317502Sroot *colp = 0; 10327502Sroot } 10339578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10347502Sroot (void) putc(c|0200, &tp->t_outq); 10357502Sroot return (-1); 10367502Sroot } 103713821Ssam #undef mstohz 10387502Sroot 10397502Sroot /* 10407502Sroot * Called from device's read routine after it has 10417502Sroot * calculated the tty-structure given as argument. 10427502Sroot */ 10437722Swnj ttread(tp, uio) 10447625Ssam register struct tty *tp; 10457722Swnj struct uio *uio; 10467502Sroot { 10477502Sroot register struct clist *qp; 10489578Ssam register c, t_flags; 10499859Ssam int s, first, error = 0; 10507502Sroot 10517502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10528520Sroot return (EIO); 10537502Sroot loop: 10549578Ssam /* 10559578Ssam * Take any pending input first. 10569578Ssam */ 105717545Skarels s = spltty(); 10589578Ssam if (tp->t_flags&PENDIN) 10597502Sroot ttypend(tp); 10609859Ssam splx(s); 10619578Ssam 10629578Ssam /* 10639578Ssam * Hang process if it's in the background. 10649578Ssam */ 106515141Skarels #define bit(a) (1<<(a-1)) 10667502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 106715141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 106815141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10697502Sroot /* 10707502Sroot (u.u_procp->p_flag&SDETACH) || 10717502Sroot */ 10727502Sroot u.u_procp->p_flag&SVFORK) 10738520Sroot return (EIO); 10747502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10757502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10767502Sroot } 10779578Ssam t_flags = tp->t_flags; 107815141Skarels #undef bit 10799578Ssam 10809578Ssam /* 10819578Ssam * In raw mode take characters directly from the 10829578Ssam * raw queue w/o processing. Interlock against 10839578Ssam * device interrupts when interrogating rawq. 10849578Ssam */ 10859578Ssam if (t_flags&RAW) { 108617545Skarels s = spltty(); 10877502Sroot if (tp->t_rawq.c_cc <= 0) { 10889578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10897502Sroot (tp->t_state&TS_NBIO)) { 10909859Ssam splx(s); 109115094Skarels return (EWOULDBLOCK); 10927502Sroot } 10937502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10949859Ssam splx(s); 10957502Sroot goto loop; 10967502Sroot } 10979859Ssam splx(s); 109814938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 109914938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11009859Ssam goto checktandem; 11019578Ssam } 11029578Ssam 11039578Ssam /* 11049578Ssam * In cbreak mode use the rawq, otherwise 11059578Ssam * take characters from the canonicalized q. 11069578Ssam */ 11079578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11089578Ssam 11099578Ssam /* 11109578Ssam * No input, sleep on rawq awaiting hardware 11119578Ssam * receipt and notification. 11129578Ssam */ 111317545Skarels s = spltty(); 11149578Ssam if (qp->c_cc <= 0) { 11159578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11169578Ssam (tp->t_state&TS_NBIO)) { 11179859Ssam splx(s); 11189578Ssam return (EWOULDBLOCK); 11197502Sroot } 11209578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11219859Ssam splx(s); 11229578Ssam goto loop; 11239578Ssam } 11249859Ssam splx(s); 11259578Ssam 11269578Ssam /* 11279578Ssam * Input present, perform input mapping 11289578Ssam * and processing (we're not in raw mode). 11299578Ssam */ 11309578Ssam first = 1; 11319578Ssam while ((c = getc(qp)) >= 0) { 11329578Ssam if (t_flags&CRMOD && c == '\r') 11339578Ssam c = '\n'; 11349578Ssam /* 11359578Ssam * Hack lower case simulation on 11369578Ssam * upper case only terminals. 11379578Ssam */ 11389578Ssam if (t_flags&LCASE && c <= 0177) 11399578Ssam if (tp->t_state&TS_BKSL) { 11409578Ssam if (maptab[c]) 11419578Ssam c = maptab[c]; 11429578Ssam tp->t_state &= ~TS_BKSL; 11439578Ssam } else if (c >= 'A' && c <= 'Z') 11449578Ssam c += 'a' - 'A'; 11459578Ssam else if (c == '\\') { 11469578Ssam tp->t_state |= TS_BKSL; 11479578Ssam continue; 11487502Sroot } 11499578Ssam /* 11509578Ssam * Check for delayed suspend character. 11519578Ssam */ 11529578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11539578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11549578Ssam if (first) { 11559578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11569578Ssam goto loop; 11579578Ssam } 11589578Ssam break; 11597502Sroot } 11609578Ssam /* 11619578Ssam * Interpret EOF only in cooked mode. 11629578Ssam */ 11639578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11649578Ssam break; 11659578Ssam /* 11669578Ssam * Give user character. 11679578Ssam */ 116814938Smckusick error = ureadc(c & 0177, uio); 11699578Ssam if (error) 11709578Ssam break; 117114938Smckusick if (uio->uio_resid == 0) 11729578Ssam break; 11739578Ssam /* 11749578Ssam * In cooked mode check for a "break character" 11759578Ssam * marking the end of a "line of input". 11769578Ssam */ 11779578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11789578Ssam break; 11799578Ssam first = 0; 11807502Sroot } 11819578Ssam tp->t_state &= ~TS_BKSL; 11829578Ssam 11839859Ssam checktandem: 11849578Ssam /* 11859578Ssam * Look to unblock output now that (presumably) 11869578Ssam * the input queue has gone down. 11879578Ssam */ 11889859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11899578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11907502Sroot tp->t_state &= ~TS_TBLOCK; 11917502Sroot ttstart(tp); 11927502Sroot } 11938520Sroot return (error); 11947502Sroot } 11957502Sroot 11967502Sroot /* 11977502Sroot * Called from the device's write routine after it has 11987502Sroot * calculated the tty-structure given as argument. 11997502Sroot */ 12007822Sroot ttwrite(tp, uio) 12017625Ssam register struct tty *tp; 12029578Ssam register struct uio *uio; 12037502Sroot { 12047502Sroot register char *cp; 12059578Ssam register int cc, ce, c; 12069578Ssam int i, hiwat, cnt, error, s; 12077502Sroot char obuf[OBUFSIZ]; 12087502Sroot 12099578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 12108520Sroot return (EIO); 12119578Ssam hiwat = TTHIWAT(tp); 12129578Ssam cnt = uio->uio_resid; 12139578Ssam error = 0; 12147502Sroot loop: 12159578Ssam /* 12169578Ssam * Hang the process if it's in the background. 12179578Ssam */ 121815141Skarels #define bit(a) (1<<(a-1)) 12197502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12209578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 122115141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 122215141Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU)) 12237502Sroot /* 12247502Sroot && 12257502Sroot (u.u_procp->p_flag&SDETACH)==0) { 12267502Sroot */ 12277502Sroot ) { 12287502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12297502Sroot sleep((caddr_t)&lbolt, TTIPRI); 12307502Sroot } 123115141Skarels #undef bit 12329578Ssam 12339578Ssam /* 12349578Ssam * Process the user's data in at most OBUFSIZ 12359578Ssam * chunks. Perform lower case simulation and 12369578Ssam * similar hacks. Keep track of high water 12379578Ssam * mark, sleep on overflow awaiting device aid 12389578Ssam * in acquiring new space. 12399578Ssam */ 12407822Sroot while (uio->uio_resid > 0) { 12419578Ssam /* 12429578Ssam * Grab a hunk of data from the user. 12439578Ssam */ 12447822Sroot cc = uio->uio_iov->iov_len; 12457822Sroot if (cc == 0) { 12467822Sroot uio->uio_iovcnt--; 12477822Sroot uio->uio_iov++; 12487822Sroot if (uio->uio_iovcnt < 0) 12497822Sroot panic("ttwrite"); 12507822Sroot continue; 12517822Sroot } 12527822Sroot if (cc > OBUFSIZ) 12537822Sroot cc = OBUFSIZ; 12547502Sroot cp = obuf; 125512752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12568520Sroot if (error) 12577502Sroot break; 12587502Sroot if (tp->t_outq.c_cc > hiwat) 12597502Sroot goto ovhiwat; 12609578Ssam if (tp->t_flags&FLUSHO) 12617502Sroot continue; 12629578Ssam /* 12639578Ssam * If we're mapping lower case or kludging tildes, 12649578Ssam * then we've got to look at each character, so 12659578Ssam * just feed the stuff to ttyoutput... 12669578Ssam */ 12679578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12689578Ssam while (cc > 0) { 12697502Sroot c = *cp++; 12707502Sroot tp->t_rocount = 0; 12717625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12727502Sroot /* out of clists, wait a bit */ 12737502Sroot ttstart(tp); 12747502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12757502Sroot tp->t_rocount = 0; 12767502Sroot } 12777502Sroot --cc; 12787502Sroot if (tp->t_outq.c_cc > hiwat) 12797502Sroot goto ovhiwat; 12807502Sroot } 12817502Sroot continue; 12827502Sroot } 12839578Ssam /* 12849578Ssam * If nothing fancy need be done, grab those characters we 12859578Ssam * can handle without any of ttyoutput's processing and 12869578Ssam * just transfer them to the output q. For those chars 12879578Ssam * which require special processing (as indicated by the 12889578Ssam * bits in partab), call ttyoutput. After processing 12899578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12909578Ssam * immediately. 12919578Ssam */ 12929578Ssam while (cc > 0) { 12939578Ssam if (tp->t_flags & (RAW|LITOUT)) 12947502Sroot ce = cc; 12957502Sroot else { 129612752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 129712752Ssam (caddr_t)partab, 077); 12989578Ssam /* 12999578Ssam * If ce is zero, then we're processing 13009578Ssam * a special character through ttyoutput. 13019578Ssam */ 13029578Ssam if (ce == 0) { 13037502Sroot tp->t_rocount = 0; 13047502Sroot if (ttyoutput(*cp, tp) >= 0) { 13059578Ssam /* no c-lists, wait a bit */ 13067502Sroot ttstart(tp); 13077502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13087502Sroot continue; 13097502Sroot } 13109578Ssam cp++, cc--; 13119578Ssam if (tp->t_flags&FLUSHO || 13129578Ssam tp->t_outq.c_cc > hiwat) 13137502Sroot goto ovhiwat; 13149578Ssam continue; 13157502Sroot } 13167502Sroot } 13179578Ssam /* 13189578Ssam * A bunch of normal characters have been found, 13199578Ssam * transfer them en masse to the output queue and 13209578Ssam * continue processing at the top of the loop. 13219578Ssam * If there are any further characters in this 13229578Ssam * <= OBUFSIZ chunk, the first should be a character 13239578Ssam * requiring special handling by ttyoutput. 13249578Ssam */ 13257502Sroot tp->t_rocount = 0; 13269578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13279578Ssam ce -= i; 13289578Ssam tp->t_col += ce; 13299578Ssam cp += ce, cc -= ce, tk_nout += ce; 13309578Ssam if (i > 0) { 13319578Ssam /* out of c-lists, wait a bit */ 13327502Sroot ttstart(tp); 13337502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13347502Sroot } 13359578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13367502Sroot goto ovhiwat; 13377502Sroot } 13387502Sroot } 13397502Sroot ttstart(tp); 13408520Sroot return (error); 13417502Sroot 13427502Sroot ovhiwat: 134317545Skarels s = spltty(); 13449578Ssam if (cc != 0) { 13459578Ssam uio->uio_iov->iov_base -= cc; 13469578Ssam uio->uio_iov->iov_len += cc; 13479578Ssam uio->uio_resid += cc; 13489578Ssam uio->uio_offset -= cc; 13499578Ssam } 13509578Ssam /* 13519578Ssam * This can only occur if FLUSHO 13529578Ssam * is also set in t_flags. 13539578Ssam */ 13547502Sroot if (tp->t_outq.c_cc <= hiwat) { 13559578Ssam splx(s); 13567502Sroot goto loop; 13577502Sroot } 13587502Sroot ttstart(tp); 13599578Ssam if (tp->t_state&TS_NBIO) { 136017545Skarels splx(s); 13617822Sroot if (uio->uio_resid == cnt) 13628520Sroot return (EWOULDBLOCK); 13638520Sroot return (0); 13647502Sroot } 13657502Sroot tp->t_state |= TS_ASLEEP; 13667502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13679578Ssam splx(s); 13687502Sroot goto loop; 13697502Sroot } 13707502Sroot 13717502Sroot /* 13727502Sroot * Rubout one character from the rawq of tp 13737502Sroot * as cleanly as possible. 13747502Sroot */ 13757502Sroot ttyrub(c, tp) 13767625Ssam register c; 13777625Ssam register struct tty *tp; 13787502Sroot { 13797502Sroot register char *cp; 13807502Sroot register int savecol; 13817502Sroot int s; 13827502Sroot char *nextc(); 13837502Sroot 13849578Ssam if ((tp->t_flags&ECHO) == 0) 13857502Sroot return; 13869578Ssam tp->t_flags &= ~FLUSHO; 13877502Sroot c &= 0377; 13889578Ssam if (tp->t_flags&CRTBS) { 13897502Sroot if (tp->t_rocount == 0) { 13907502Sroot /* 13917502Sroot * Screwed by ttwrite; retype 13927502Sroot */ 13937502Sroot ttyretype(tp); 13947502Sroot return; 13957502Sroot } 13969578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13977502Sroot ttyrubo(tp, 2); 13989578Ssam else switch (partab[c&=0177]&0177) { 13997502Sroot 14007502Sroot case ORDINARY: 14017502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14027502Sroot ttyrubo(tp, 2); 14037502Sroot else 14047502Sroot ttyrubo(tp, 1); 14057502Sroot break; 14067502Sroot 14077502Sroot case VTAB: 14087502Sroot case BACKSPACE: 14097502Sroot case CONTROL: 14107502Sroot case RETURN: 14119578Ssam if (tp->t_flags&CTLECH) 14127502Sroot ttyrubo(tp, 2); 14137502Sroot break; 14147502Sroot 14157502Sroot case TAB: 14167502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14177502Sroot ttyretype(tp); 14187502Sroot return; 14197502Sroot } 142017545Skarels s = spltty(); 14217502Sroot savecol = tp->t_col; 14229578Ssam tp->t_state |= TS_CNTTB; 14239578Ssam tp->t_flags |= FLUSHO; 14247502Sroot tp->t_col = tp->t_rocol; 14259578Ssam cp = tp->t_rawq.c_cf; 14269578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14277502Sroot ttyecho(*cp, tp); 14289578Ssam tp->t_flags &= ~FLUSHO; 14299578Ssam tp->t_state &= ~TS_CNTTB; 14307502Sroot splx(s); 14317502Sroot /* 14327502Sroot * savecol will now be length of the tab 14337502Sroot */ 14347502Sroot savecol -= tp->t_col; 14357502Sroot tp->t_col += savecol; 14367502Sroot if (savecol > 8) 14377502Sroot savecol = 8; /* overflow screw */ 14387502Sroot while (--savecol >= 0) 14397502Sroot (void) ttyoutput('\b', tp); 14407502Sroot break; 14417502Sroot 14427502Sroot default: 14437502Sroot panic("ttyrub"); 14447502Sroot } 14459578Ssam } else if (tp->t_flags&PRTERA) { 14469578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14477502Sroot (void) ttyoutput('\\', tp); 14489578Ssam tp->t_state |= TS_ERASE; 14497502Sroot } 14507502Sroot ttyecho(c, tp); 14517502Sroot } else 14527502Sroot ttyecho(tp->t_erase, tp); 14537502Sroot tp->t_rocount--; 14547502Sroot } 14557502Sroot 14567502Sroot /* 14577502Sroot * Crt back over cnt chars perhaps 14587502Sroot * erasing them. 14597502Sroot */ 14607502Sroot ttyrubo(tp, cnt) 14617625Ssam register struct tty *tp; 14627625Ssam int cnt; 14637502Sroot { 14649578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14657502Sroot 14667502Sroot while (--cnt >= 0) 14679578Ssam ttyout(rubostring, tp); 14687502Sroot } 14697502Sroot 14707502Sroot /* 14717502Sroot * Reprint the rawq line. 14727502Sroot * We assume c_cc has already been checked. 14737502Sroot */ 14747502Sroot ttyretype(tp) 14757625Ssam register struct tty *tp; 14767502Sroot { 14777502Sroot register char *cp; 14787502Sroot char *nextc(); 14797502Sroot int s; 14807502Sroot 14819578Ssam if (tp->t_rprntc != 0377) 14829578Ssam ttyecho(tp->t_rprntc, tp); 14837502Sroot (void) ttyoutput('\n', tp); 148417545Skarels s = spltty(); 14857502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14867502Sroot ttyecho(*cp, tp); 14877502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14887502Sroot ttyecho(*cp, tp); 14899578Ssam tp->t_state &= ~TS_ERASE; 14907502Sroot splx(s); 14917502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14927502Sroot tp->t_rocol = 0; 14937502Sroot } 14947502Sroot 14957502Sroot /* 14967502Sroot * Echo a typed character to the terminal 14977502Sroot */ 14987502Sroot ttyecho(c, tp) 14997625Ssam register c; 15007625Ssam register struct tty *tp; 15017502Sroot { 15027502Sroot 15039578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15049578Ssam tp->t_flags &= ~FLUSHO; 15057502Sroot if ((tp->t_flags&ECHO) == 0) 15067502Sroot return; 15077502Sroot c &= 0377; 15087502Sroot if (tp->t_flags&RAW) { 15097502Sroot (void) ttyoutput(c, tp); 15107502Sroot return; 15117502Sroot } 15127502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15137502Sroot c = '\n'; 15149578Ssam if (tp->t_flags&CTLECH) { 15157502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15167502Sroot (void) ttyoutput('^', tp); 15177502Sroot c &= 0177; 15187502Sroot if (c == 0177) 15197502Sroot c = '?'; 15207502Sroot else if (tp->t_flags&LCASE) 15217502Sroot c += 'a' - 1; 15227502Sroot else 15237502Sroot c += 'A' - 1; 15247502Sroot } 15257502Sroot } 15267502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 15277502Sroot c += 'a' - 'A'; 15289578Ssam (void) ttyoutput(c&0177, tp); 15297502Sroot } 15307502Sroot 15317502Sroot /* 15327502Sroot * Is c a break char for tp? 15337502Sroot */ 15347502Sroot ttbreakc(c, tp) 15357625Ssam register c; 15367625Ssam register struct tty *tp; 15377502Sroot { 15389578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15397502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15407502Sroot } 15417502Sroot 15427502Sroot /* 15437502Sroot * send string cp to tp 15447502Sroot */ 15457502Sroot ttyout(cp, tp) 15467625Ssam register char *cp; 15477625Ssam register struct tty *tp; 15487502Sroot { 15497502Sroot register char c; 15507502Sroot 15517502Sroot while (c = *cp++) 15527502Sroot (void) ttyoutput(c, tp); 15537502Sroot } 15547502Sroot 15557502Sroot ttwakeup(tp) 15567502Sroot struct tty *tp; 15577502Sroot { 15587502Sroot 15597502Sroot if (tp->t_rsel) { 15607502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15617502Sroot tp->t_state &= ~TS_RCOLL; 15627502Sroot tp->t_rsel = 0; 15637502Sroot } 156412752Ssam if (tp->t_state & TS_ASYNC) 156512752Ssam gsignal(tp->t_pgrp, SIGIO); 15667502Sroot wakeup((caddr_t)&tp->t_rawq); 15677502Sroot } 15687502Sroot 156913533Ssam #if !defined(vax) 15709578Ssam scanc(size, cp, table, mask) 15719578Ssam register int size; 15729578Ssam register char *cp, table[]; 15739578Ssam register int mask; 15747502Sroot { 15759578Ssam register int i = 0; 15767502Sroot 15779578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15789578Ssam i++; 157915100Skarels return (size - i); 15807502Sroot } 15819578Ssam #endif 1582