1*18650Sbloom /* tty.c 6.15 85/04/17 */ 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: 25817598Sbloom 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); 29410851Ssam if (error) { 29510851Ssam if (tp->t_line) 29610851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29710851Ssam splx(s); 2988556Sroot return (error); 29910851Ssam } 3008556Sroot tp->t_line = t; 301*18650Sbloom splx(s); 30239Sbill break; 3037625Ssam } 30439Sbill 3058556Sroot /* prevent more opens on channel */ 3065614Swnj case TIOCEXCL: 3075614Swnj tp->t_state |= TS_XCLUDE; 3085614Swnj break; 3095614Swnj 3105614Swnj case TIOCNXCL: 3115614Swnj tp->t_state &= ~TS_XCLUDE; 3125614Swnj break; 3135614Swnj 3148556Sroot /* hang up line on last close */ 31539Sbill case TIOCHPCL: 3165408Swnj tp->t_state |= TS_HUPCLS; 31739Sbill break; 31839Sbill 3193942Sbugs case TIOCFLUSH: { 3207625Ssam register int flags = *(int *)data; 3217625Ssam 3227625Ssam if (flags == 0) 3233942Sbugs flags = FREAD|FWRITE; 3247625Ssam else 3257625Ssam flags &= FREAD|FWRITE; 32612752Ssam ttyflush(tp, flags); 32739Sbill break; 3283944Sbugs } 32939Sbill 3308556Sroot /* return number of characters immediately available */ 3317625Ssam case FIONREAD: 3327625Ssam *(off_t *)data = ttnread(tp); 333174Sbill break; 334174Sbill 33513077Ssam case TIOCOUTQ: 33613077Ssam *(int *)data = tp->t_outq.c_cc; 33713077Ssam break; 33813077Ssam 3398589Sroot case TIOCSTOP: 34017545Skarels s = spltty(); 3419578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3425573Swnj tp->t_state |= TS_TTSTOP; 3435573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3445573Swnj } 3457625Ssam splx(s); 3465573Swnj break; 3475573Swnj 3488589Sroot case TIOCSTART: 34917545Skarels s = spltty(); 3509578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3515573Swnj tp->t_state &= ~TS_TTSTOP; 3529578Ssam tp->t_flags &= ~FLUSHO; 3535573Swnj ttstart(tp); 3545573Swnj } 3557625Ssam splx(s); 3565573Swnj break; 3575573Swnj 3589325Ssam /* 3599325Ssam * Simulate typing of a character at the terminal. 3609325Ssam */ 3619325Ssam case TIOCSTI: 36217183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36317183Smckusick return (EPERM); 3649325Ssam if (u.u_uid && u.u_ttyp != tp) 3659325Ssam return (EACCES); 3669578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3679325Ssam break; 3689325Ssam 36912752Ssam case TIOCSETP: 37012752Ssam case TIOCSETN: { 37112752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37212752Ssam 37312752Ssam tp->t_erase = sg->sg_erase; 37412752Ssam tp->t_kill = sg->sg_kill; 37512752Ssam tp->t_ispeed = sg->sg_ispeed; 37612752Ssam tp->t_ospeed = sg->sg_ospeed; 37712752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37817545Skarels s = spltty(); 37912752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38012752Ssam ttywait(tp); 38112752Ssam ttyflush(tp, FREAD); 38212752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38312752Ssam if (newflags&CBREAK) { 38412752Ssam struct clist tq; 38512752Ssam 38612752Ssam catq(&tp->t_rawq, &tp->t_canq); 38712752Ssam tq = tp->t_rawq; 38812752Ssam tp->t_rawq = tp->t_canq; 38912752Ssam tp->t_canq = tq; 39012752Ssam } else { 39112752Ssam tp->t_flags |= PENDIN; 39213801Ssam newflags |= PENDIN; 39312752Ssam ttwakeup(tp); 39412752Ssam } 39512752Ssam } 39612752Ssam tp->t_flags = newflags; 39712752Ssam if (tp->t_flags&RAW) { 39812752Ssam tp->t_state &= ~TS_TTSTOP; 39912752Ssam ttstart(tp); 40012752Ssam } 40112752Ssam splx(s); 40212752Ssam break; 40312752Ssam } 40412752Ssam 40512752Ssam /* send current parameters to user */ 40612752Ssam case TIOCGETP: { 40712752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40812752Ssam 40912752Ssam sg->sg_ispeed = tp->t_ispeed; 41012752Ssam sg->sg_ospeed = tp->t_ospeed; 41112752Ssam sg->sg_erase = tp->t_erase; 41212752Ssam sg->sg_kill = tp->t_kill; 41312752Ssam sg->sg_flags = tp->t_flags; 41412752Ssam break; 41512752Ssam } 41612752Ssam 41712752Ssam case FIONBIO: 41812752Ssam if (*(int *)data) 41912752Ssam tp->t_state |= TS_NBIO; 42012752Ssam else 42112752Ssam tp->t_state &= ~TS_NBIO; 42212752Ssam break; 42312752Ssam 42412752Ssam case FIOASYNC: 42512752Ssam if (*(int *)data) 42612752Ssam tp->t_state |= TS_ASYNC; 42712752Ssam else 42812752Ssam tp->t_state &= ~TS_ASYNC; 42912752Ssam break; 43012752Ssam 43113077Ssam case TIOCGETC: 43213077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43313077Ssam break; 43413077Ssam 43513077Ssam case TIOCSETC: 43613077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43713077Ssam break; 43813077Ssam 43912752Ssam /* set/get local special characters */ 44012752Ssam case TIOCSLTC: 44112752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44212752Ssam break; 44312752Ssam 44412752Ssam case TIOCGLTC: 44512752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44612752Ssam break; 44712752Ssam 44812752Ssam /* 44912752Ssam * Modify local mode word. 45012752Ssam */ 45112752Ssam case TIOCLBIS: 45212752Ssam tp->t_flags |= *(int *)data << 16; 45312752Ssam break; 45412752Ssam 45512752Ssam case TIOCLBIC: 45612752Ssam tp->t_flags &= ~(*(int *)data << 16); 45712752Ssam break; 45812752Ssam 45912752Ssam case TIOCLSET: 46012752Ssam tp->t_flags &= 0xffff; 46112752Ssam tp->t_flags |= *(int *)data << 16; 46212752Ssam break; 46312752Ssam 46412752Ssam case TIOCLGET: 46515720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46612752Ssam break; 46712752Ssam 46817545Skarels /* 46917932Skarels * Allow SPGRP only if tty is open for reading. 47017598Sbloom * Quick check: if we can find a process in the new pgrp, 47117598Sbloom * this user must own that process. 47217598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47317545Skarels */ 474*18650Sbloom case TIOCSPGRP: { 47517545Skarels struct proc *p; 47617545Skarels int pgrp = *(int *)data; 47717545Skarels 47817545Skarels if (u.u_uid && (flag & FREAD) == 0) 47917545Skarels return (EPERM); 48017598Sbloom p = pfind(pgrp); 48117598Sbloom if (p && p->p_pgrp == pgrp && 48217598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48317598Sbloom return (EPERM); 48417545Skarels tp->t_pgrp = pgrp; 48512752Ssam break; 486*18650Sbloom } 48712752Ssam 48812752Ssam case TIOCGPGRP: 48912752Ssam *(int *)data = tp->t_pgrp; 49012752Ssam break; 49112752Ssam 49217598Sbloom case TIOCSWINSZ: 493*18650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 494*18650Sbloom sizeof (struct winsize))) { 49517598Sbloom tp->t_winsize = *(struct winsize *)data; 49617598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 49717598Sbloom } 49817598Sbloom break; 49917598Sbloom 50017598Sbloom case TIOCGWINSZ: 50117598Sbloom *(struct winsize *)data = tp->t_winsize; 50217598Sbloom break; 50317598Sbloom 50439Sbill default: 5058556Sroot return (-1); 50639Sbill } 5078556Sroot return (0); 50839Sbill } 5094484Swnj 5104484Swnj ttnread(tp) 5114484Swnj struct tty *tp; 5124484Swnj { 5134484Swnj int nread = 0; 5144484Swnj 5159578Ssam if (tp->t_flags & PENDIN) 5164484Swnj ttypend(tp); 5174484Swnj nread = tp->t_canq.c_cc; 5184484Swnj if (tp->t_flags & (RAW|CBREAK)) 5194484Swnj nread += tp->t_rawq.c_cc; 5204484Swnj return (nread); 5214484Swnj } 5224484Swnj 5235408Swnj ttselect(dev, rw) 5244484Swnj dev_t dev; 5255408Swnj int rw; 5264484Swnj { 5274484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5284484Swnj int nread; 52917545Skarels int s = spltty(); 5304484Swnj 5315408Swnj switch (rw) { 5324484Swnj 5334484Swnj case FREAD: 5344484Swnj nread = ttnread(tp); 5354484Swnj if (nread > 0) 5365408Swnj goto win; 5374938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5385408Swnj tp->t_state |= TS_RCOLL; 5394484Swnj else 5404484Swnj tp->t_rsel = u.u_procp; 5415408Swnj break; 5424484Swnj 5435408Swnj case FWRITE: 5445408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5455408Swnj goto win; 5465408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5475408Swnj tp->t_state |= TS_WCOLL; 5485408Swnj else 5495408Swnj tp->t_wsel = u.u_procp; 5505408Swnj break; 5514484Swnj } 5525408Swnj splx(s); 5535408Swnj return (0); 5545408Swnj win: 5555408Swnj splx(s); 5565408Swnj return (1); 5574484Swnj } 5587436Skre 5597502Sroot /* 5609578Ssam * Establish a process group for distribution of 5617502Sroot * quits and interrupts from the tty. 5627502Sroot */ 5637502Sroot ttyopen(dev, tp) 5647625Ssam dev_t dev; 5657625Ssam register struct tty *tp; 5667502Sroot { 5677502Sroot register struct proc *pp; 5687502Sroot 5697502Sroot pp = u.u_procp; 5707502Sroot tp->t_dev = dev; 5717625Ssam if (pp->p_pgrp == 0) { 5727502Sroot u.u_ttyp = tp; 5737502Sroot u.u_ttyd = dev; 5747502Sroot if (tp->t_pgrp == 0) 5757502Sroot tp->t_pgrp = pp->p_pid; 5767502Sroot pp->p_pgrp = tp->t_pgrp; 5777502Sroot } 5787502Sroot tp->t_state &= ~TS_WOPEN; 57917545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 58017545Skarels tp->t_state |= TS_ISOPEN; 58117598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58217545Skarels if (tp->t_line != NTTYDISC) 58317545Skarels ttywflush(tp); 58417545Skarels } 5858556Sroot return (0); 5867502Sroot } 5877502Sroot 5887502Sroot /* 5897502Sroot * clean tp on last close 5907502Sroot */ 5917502Sroot ttyclose(tp) 5927625Ssam register struct tty *tp; 5937502Sroot { 5947502Sroot 5957502Sroot if (tp->t_line) { 59612752Ssam ttywflush(tp); 5977502Sroot tp->t_line = 0; 5987502Sroot return; 5997502Sroot } 6007502Sroot tp->t_pgrp = 0; 60112752Ssam ttywflush(tp); 6027502Sroot tp->t_state = 0; 6037502Sroot } 6047502Sroot 6057502Sroot /* 6067502Sroot * reinput pending characters after state switch 60717545Skarels * call at spltty(). 6087502Sroot */ 6097502Sroot ttypend(tp) 6107625Ssam register struct tty *tp; 6117502Sroot { 6127502Sroot struct clist tq; 6137502Sroot register c; 6147502Sroot 6159578Ssam tp->t_flags &= ~PENDIN; 6169578Ssam tp->t_state |= TS_TYPEN; 6177502Sroot tq = tp->t_rawq; 6187502Sroot tp->t_rawq.c_cc = 0; 6197502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6207502Sroot while ((c = getc(&tq)) >= 0) 6217502Sroot ttyinput(c, tp); 6229578Ssam tp->t_state &= ~TS_TYPEN; 6237502Sroot } 6247502Sroot 6257502Sroot /* 6269578Ssam * Place a character on raw TTY input queue, 6279578Ssam * putting in delimiters and waking up top 6289578Ssam * half as needed. Also echo if required. 6299578Ssam * The arguments are the character and the 6309578Ssam * appropriate tty structure. 6317502Sroot */ 6327502Sroot ttyinput(c, tp) 6337625Ssam register c; 6347625Ssam register struct tty *tp; 6357502Sroot { 6369578Ssam register int t_flags = tp->t_flags; 6377502Sroot int i; 6387502Sroot 6399578Ssam /* 6409578Ssam * If input is pending take it first. 6419578Ssam */ 6429578Ssam if (t_flags&PENDIN) 6437502Sroot ttypend(tp); 6447502Sroot tk_nin++; 6457502Sroot c &= 0377; 6469578Ssam 6479578Ssam /* 6489578Ssam * In tandem mode, check high water mark. 6499578Ssam */ 6507502Sroot if (t_flags&TANDEM) 6517502Sroot ttyblock(tp); 6529578Ssam 6539578Ssam if (t_flags&RAW) { 6549578Ssam /* 6559578Ssam * Raw mode, just put character 6569578Ssam * in input q w/o interpretation. 6579578Ssam */ 6589578Ssam if (tp->t_rawq.c_cc > TTYHOG) 65912752Ssam ttyflush(tp, FREAD|FWRITE); 6609578Ssam else { 6619578Ssam if (putc(c, &tp->t_rawq) >= 0) 6629578Ssam ttwakeup(tp); 6639578Ssam ttyecho(c, tp); 6647502Sroot } 6659578Ssam goto endcase; 6669578Ssam } 6679578Ssam 6689578Ssam /* 6699578Ssam * Ignore any high bit added during 6709578Ssam * previous ttyinput processing. 6719578Ssam */ 6729578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6739578Ssam c &= 0177; 6749578Ssam /* 6759578Ssam * Check for literal nexting very first 6769578Ssam */ 6779578Ssam if (tp->t_state&TS_LNCH) { 6789578Ssam c |= 0200; 6799578Ssam tp->t_state &= ~TS_LNCH; 6809578Ssam } 6819578Ssam 6829578Ssam /* 6839578Ssam * Scan for special characters. This code 6849578Ssam * is really just a big case statement with 6859578Ssam * non-constant cases. The bottom of the 6869578Ssam * case statement is labeled ``endcase'', so goto 6879578Ssam * it after a case match, or similar. 6889578Ssam */ 6899578Ssam if (tp->t_line == NTTYDISC) { 6909578Ssam if (c == tp->t_lnextc) { 6917502Sroot if (tp->t_flags&ECHO) 6927502Sroot ttyout("^\b", tp); 6939578Ssam tp->t_state |= TS_LNCH; 6949578Ssam goto endcase; 6959578Ssam } 6969578Ssam if (c == tp->t_flushc) { 6979578Ssam if (tp->t_flags&FLUSHO) 6989578Ssam tp->t_flags &= ~FLUSHO; 6997502Sroot else { 70012752Ssam ttyflush(tp, FWRITE); 7017502Sroot ttyecho(c, tp); 7029578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7037502Sroot ttyretype(tp); 7049578Ssam tp->t_flags |= FLUSHO; 7057502Sroot } 7069578Ssam goto startoutput; 7079578Ssam } 7089578Ssam if (c == tp->t_suspc) { 7099578Ssam if ((tp->t_flags&NOFLSH) == 0) 71012752Ssam ttyflush(tp, FREAD); 7119578Ssam ttyecho(c, tp); 7129578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7139578Ssam goto endcase; 7149578Ssam } 7159578Ssam } 7169578Ssam 7179578Ssam /* 7189578Ssam * Handle start/stop characters. 7199578Ssam */ 7209578Ssam if (c == tp->t_stopc) { 7219578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7229578Ssam tp->t_state |= TS_TTSTOP; 7239578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7247502Sroot return; 7259578Ssam } 7269578Ssam if (c != tp->t_startc) 7279578Ssam return; 7289578Ssam goto endcase; 7299578Ssam } 7309578Ssam if (c == tp->t_startc) 7319578Ssam goto restartoutput; 7329578Ssam 7339578Ssam /* 7349578Ssam * Look for interrupt/quit chars. 7359578Ssam */ 7369578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7379578Ssam if ((tp->t_flags&NOFLSH) == 0) 73812752Ssam ttyflush(tp, FREAD|FWRITE); 7399578Ssam ttyecho(c, tp); 7409578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7419578Ssam goto endcase; 7429578Ssam } 7439578Ssam 7449578Ssam /* 7459578Ssam * Cbreak mode, don't process line editing 7469578Ssam * characters; check high water mark for wakeup. 7479578Ssam */ 7489578Ssam if (t_flags&CBREAK) { 7499578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7507502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7517502Sroot tp->t_line == NTTYDISC) 7527502Sroot (void) ttyoutput(CTRL(g), tp); 7537502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7547502Sroot ttwakeup(tp); 7557502Sroot ttyecho(c, tp); 7567502Sroot } 7579578Ssam goto endcase; 7589578Ssam } 7599578Ssam 7609578Ssam /* 7619578Ssam * From here on down cooked mode character 7629578Ssam * processing takes place. 7639578Ssam */ 7649578Ssam if ((tp->t_state&TS_QUOT) && 7659578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7669578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7679578Ssam c |= 0200; 7689578Ssam } 7699578Ssam if (c == tp->t_erase) { 7709578Ssam if (tp->t_rawq.c_cc) 7719578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7729578Ssam goto endcase; 7739578Ssam } 7749578Ssam if (c == tp->t_kill) { 7759578Ssam if (tp->t_flags&CRTKIL && 7769578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7779578Ssam while (tp->t_rawq.c_cc) 7789578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7799578Ssam } else { 7809578Ssam ttyecho(c, tp); 7819578Ssam ttyecho('\n', tp); 7829578Ssam while (getc(&tp->t_rawq) > 0) 7839578Ssam ; 7849578Ssam tp->t_rocount = 0; 7859578Ssam } 7869578Ssam tp->t_state &= ~TS_LOCAL; 7879578Ssam goto endcase; 7889578Ssam } 7899578Ssam 7909578Ssam /* 7919578Ssam * New line discipline, 7929578Ssam * check word erase/reprint line. 7939578Ssam */ 7949578Ssam if (tp->t_line == NTTYDISC) { 7959578Ssam if (c == tp->t_werasc) { 7969578Ssam if (tp->t_rawq.c_cc == 0) 7979578Ssam goto endcase; 7989578Ssam do { 7999578Ssam c = unputc(&tp->t_rawq); 8009578Ssam if (c != ' ' && c != '\t') 8019578Ssam goto erasenb; 8029578Ssam ttyrub(c, tp); 8039578Ssam } while (tp->t_rawq.c_cc); 8049578Ssam goto endcase; 8059578Ssam erasenb: 8069578Ssam do { 8079578Ssam ttyrub(c, tp); 8089578Ssam if (tp->t_rawq.c_cc == 0) 8099578Ssam goto endcase; 8109578Ssam c = unputc(&tp->t_rawq); 8119578Ssam } while (c != ' ' && c != '\t'); 8129578Ssam (void) putc(c, &tp->t_rawq); 8139578Ssam goto endcase; 8149578Ssam } 8159578Ssam if (c == tp->t_rprntc) { 8169578Ssam ttyretype(tp); 8179578Ssam goto endcase; 8189578Ssam } 8199578Ssam } 8209578Ssam 8219578Ssam /* 8229578Ssam * Check for input buffer overflow 8239578Ssam */ 82410391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 82510391Ssam if (tp->t_line == NTTYDISC) 82610391Ssam (void) ttyoutput(CTRL(g), tp); 8279578Ssam goto endcase; 82810391Ssam } 8299578Ssam 8309578Ssam /* 8319578Ssam * Put data char in q for user and 8329578Ssam * wakeup on seeing a line delimiter. 8339578Ssam */ 8349578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8359578Ssam if (ttbreakc(c, tp)) { 8369578Ssam tp->t_rocount = 0; 8379578Ssam catq(&tp->t_rawq, &tp->t_canq); 8387502Sroot ttwakeup(tp); 8399578Ssam } else if (tp->t_rocount++ == 0) 8409578Ssam tp->t_rocol = tp->t_col; 8419578Ssam tp->t_state &= ~TS_QUOT; 8429578Ssam if (c == '\\') 8439578Ssam tp->t_state |= TS_QUOT; 8449578Ssam if (tp->t_state&TS_ERASE) { 8459578Ssam tp->t_state &= ~TS_ERASE; 8469578Ssam (void) ttyoutput('/', tp); 8479578Ssam } 8489578Ssam i = tp->t_col; 8497502Sroot ttyecho(c, tp); 8509578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8519578Ssam i = MIN(2, tp->t_col - i); 8529578Ssam while (i > 0) { 8539578Ssam (void) ttyoutput('\b', tp); 8549578Ssam i--; 8559578Ssam } 8569578Ssam } 8577502Sroot } 8589578Ssam endcase: 8599578Ssam /* 8609578Ssam * If DEC-style start/stop is enabled don't restart 8619578Ssam * output until seeing the start character. 8629578Ssam */ 8639578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8649578Ssam tp->t_startc != tp->t_stopc) 8657502Sroot return; 8669578Ssam restartoutput: 8677502Sroot tp->t_state &= ~TS_TTSTOP; 8689578Ssam tp->t_flags &= ~FLUSHO; 8699578Ssam startoutput: 8707502Sroot ttstart(tp); 8717502Sroot } 8727502Sroot 8737502Sroot /* 8749578Ssam * Put character on TTY output queue, adding delays, 8757502Sroot * expanding tabs, and handling the CR/NL bit. 8769578Ssam * This is called both from the top half for output, 8779578Ssam * and from interrupt level for echoing. 8787502Sroot * The arguments are the character and the tty structure. 8797502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8807502Sroot * Must be recursive. 8817502Sroot */ 8827502Sroot ttyoutput(c, tp) 8837502Sroot register c; 8847502Sroot register struct tty *tp; 8857502Sroot { 8867502Sroot register char *colp; 8877502Sroot register ctype; 8887502Sroot 8899578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8909578Ssam if (tp->t_flags&FLUSHO) 8917502Sroot return (-1); 8927502Sroot if (putc(c, &tp->t_outq)) 8937625Ssam return (c); 8947502Sroot tk_nout++; 8957502Sroot return (-1); 8967502Sroot } 8979578Ssam 8987502Sroot /* 8999578Ssam * Ignore EOT in normal mode to avoid 9009578Ssam * hanging up certain terminals. 9017502Sroot */ 9027502Sroot c &= 0177; 9039578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9047502Sroot return (-1); 9057502Sroot /* 9067502Sroot * Turn tabs to spaces as required 9077502Sroot */ 9089578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9097502Sroot register int s; 9107502Sroot 9117502Sroot c = 8 - (tp->t_col&7); 9129578Ssam if ((tp->t_flags&FLUSHO) == 0) { 91317545Skarels s = spltty(); /* don't interrupt tabs */ 9147502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9157502Sroot tk_nout += c; 9167502Sroot splx(s); 9177502Sroot } 9187502Sroot tp->t_col += c; 9197502Sroot return (c ? -1 : '\t'); 9207502Sroot } 9217502Sroot tk_nout++; 9227502Sroot /* 9237502Sroot * for upper-case-only terminals, 9247502Sroot * generate escapes. 9257502Sroot */ 9267502Sroot if (tp->t_flags&LCASE) { 9277502Sroot colp = "({)}!|^~'`"; 9287625Ssam while (*colp++) 9297625Ssam if (c == *colp++) { 9307502Sroot if (ttyoutput('\\', tp) >= 0) 9317502Sroot return (c); 9327502Sroot c = colp[-2]; 9337502Sroot break; 9347502Sroot } 9359578Ssam if ('A' <= c && c <= 'Z') { 9367502Sroot if (ttyoutput('\\', tp) >= 0) 9377502Sroot return (c); 9389578Ssam } else if ('a' <= c && c <= 'z') 9397502Sroot c += 'A' - 'a'; 9407502Sroot } 9419578Ssam 9427502Sroot /* 9437502Sroot * turn <nl> to <cr><lf> if desired. 9447502Sroot */ 9459578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9467502Sroot if (ttyoutput('\r', tp) >= 0) 9477502Sroot return (c); 9489578Ssam if (c == '~' && tp->t_flags&TILDE) 9497502Sroot c = '`'; 9509578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9517502Sroot return (c); 9527502Sroot /* 9537502Sroot * Calculate delays. 9547502Sroot * The numbers here represent clock ticks 9557502Sroot * and are not necessarily optimal for all terminals. 9567502Sroot * The delays are indicated by characters above 0200. 9577502Sroot * In raw mode there are no delays and the 9587502Sroot * transmission path is 8 bits wide. 9599578Ssam * 9609578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9617502Sroot */ 9627502Sroot colp = &tp->t_col; 9637502Sroot ctype = partab[c]; 9647502Sroot c = 0; 9657502Sroot switch (ctype&077) { 9667502Sroot 9677502Sroot case ORDINARY: 9687502Sroot (*colp)++; 9697502Sroot 9707502Sroot case CONTROL: 9717502Sroot break; 9727502Sroot 9737502Sroot case BACKSPACE: 9747502Sroot if (*colp) 9757502Sroot (*colp)--; 9767502Sroot break; 9777502Sroot 97813821Ssam /* 97913821Ssam * This macro is close enough to the correct thing; 98013821Ssam * it should be replaced by real user settable delays 98113821Ssam * in any event... 98213821Ssam */ 98313821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9847502Sroot case NEWLINE: 9857502Sroot ctype = (tp->t_flags >> 8) & 03; 9867625Ssam if (ctype == 1) { /* tty 37 */ 98712752Ssam if (*colp > 0) 98813863Ssam c = max((((unsigned)*colp) >> 4) + 3, 98913863Ssam (unsigned)6); 9909578Ssam } else if (ctype == 2) /* vt05 */ 99113821Ssam c = mstohz(100); 9927502Sroot *colp = 0; 9937502Sroot break; 9947502Sroot 9957502Sroot case TAB: 9967502Sroot ctype = (tp->t_flags >> 10) & 03; 9977625Ssam if (ctype == 1) { /* tty 37 */ 9987502Sroot c = 1 - (*colp | ~07); 9997625Ssam if (c < 5) 10007502Sroot c = 0; 10017502Sroot } 10027502Sroot *colp |= 07; 10037502Sroot (*colp)++; 10047502Sroot break; 10057502Sroot 10067502Sroot case VTAB: 10079578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10087502Sroot c = 0177; 10097502Sroot break; 10107502Sroot 10117502Sroot case RETURN: 10127502Sroot ctype = (tp->t_flags >> 12) & 03; 10139578Ssam if (ctype == 1) /* tn 300 */ 101413821Ssam c = mstohz(83); 10159578Ssam else if (ctype == 2) /* ti 700 */ 101613821Ssam c = mstohz(166); 10179578Ssam else if (ctype == 3) { /* concept 100 */ 10187502Sroot int i; 10199578Ssam 10207502Sroot if ((i = *colp) >= 0) 10219578Ssam for (; i < 9; i++) 10227502Sroot (void) putc(0177, &tp->t_outq); 10237502Sroot } 10247502Sroot *colp = 0; 10257502Sroot } 10269578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10277502Sroot (void) putc(c|0200, &tp->t_outq); 10287502Sroot return (-1); 10297502Sroot } 103013821Ssam #undef mstohz 10317502Sroot 10327502Sroot /* 10337502Sroot * Called from device's read routine after it has 10347502Sroot * calculated the tty-structure given as argument. 10357502Sroot */ 10367722Swnj ttread(tp, uio) 10377625Ssam register struct tty *tp; 10387722Swnj struct uio *uio; 10397502Sroot { 10407502Sroot register struct clist *qp; 10419578Ssam register c, t_flags; 10429859Ssam int s, first, error = 0; 10437502Sroot 10447502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10458520Sroot return (EIO); 10467502Sroot loop: 10479578Ssam /* 10489578Ssam * Take any pending input first. 10499578Ssam */ 105017545Skarels s = spltty(); 10519578Ssam if (tp->t_flags&PENDIN) 10527502Sroot ttypend(tp); 10539859Ssam splx(s); 10549578Ssam 10559578Ssam /* 10569578Ssam * Hang process if it's in the background. 10579578Ssam */ 105815141Skarels #define bit(a) (1<<(a-1)) 10597502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 106015141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 106115141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10627502Sroot /* 10637502Sroot (u.u_procp->p_flag&SDETACH) || 10647502Sroot */ 10657502Sroot u.u_procp->p_flag&SVFORK) 10668520Sroot return (EIO); 10677502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10687502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10697502Sroot } 10709578Ssam t_flags = tp->t_flags; 107115141Skarels #undef bit 10729578Ssam 10739578Ssam /* 10749578Ssam * In raw mode take characters directly from the 10759578Ssam * raw queue w/o processing. Interlock against 10769578Ssam * device interrupts when interrogating rawq. 10779578Ssam */ 10789578Ssam if (t_flags&RAW) { 107917545Skarels s = spltty(); 10807502Sroot if (tp->t_rawq.c_cc <= 0) { 10819578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10827502Sroot (tp->t_state&TS_NBIO)) { 10839859Ssam splx(s); 108415094Skarels return (EWOULDBLOCK); 10857502Sroot } 10867502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10879859Ssam splx(s); 10887502Sroot goto loop; 10897502Sroot } 10909859Ssam splx(s); 109114938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 109214938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10939859Ssam goto checktandem; 10949578Ssam } 10959578Ssam 10969578Ssam /* 10979578Ssam * In cbreak mode use the rawq, otherwise 10989578Ssam * take characters from the canonicalized q. 10999578Ssam */ 11009578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11019578Ssam 11029578Ssam /* 11039578Ssam * No input, sleep on rawq awaiting hardware 11049578Ssam * receipt and notification. 11059578Ssam */ 110617545Skarels s = spltty(); 11079578Ssam if (qp->c_cc <= 0) { 11089578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11099578Ssam (tp->t_state&TS_NBIO)) { 11109859Ssam splx(s); 11119578Ssam return (EWOULDBLOCK); 11127502Sroot } 11139578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11149859Ssam splx(s); 11159578Ssam goto loop; 11169578Ssam } 11179859Ssam splx(s); 11189578Ssam 11199578Ssam /* 11209578Ssam * Input present, perform input mapping 11219578Ssam * and processing (we're not in raw mode). 11229578Ssam */ 11239578Ssam first = 1; 11249578Ssam while ((c = getc(qp)) >= 0) { 11259578Ssam if (t_flags&CRMOD && c == '\r') 11269578Ssam c = '\n'; 11279578Ssam /* 11289578Ssam * Hack lower case simulation on 11299578Ssam * upper case only terminals. 11309578Ssam */ 11319578Ssam if (t_flags&LCASE && c <= 0177) 11329578Ssam if (tp->t_state&TS_BKSL) { 11339578Ssam if (maptab[c]) 11349578Ssam c = maptab[c]; 11359578Ssam tp->t_state &= ~TS_BKSL; 11369578Ssam } else if (c >= 'A' && c <= 'Z') 11379578Ssam c += 'a' - 'A'; 11389578Ssam else if (c == '\\') { 11399578Ssam tp->t_state |= TS_BKSL; 11409578Ssam continue; 11417502Sroot } 11429578Ssam /* 11439578Ssam * Check for delayed suspend character. 11449578Ssam */ 11459578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11469578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11479578Ssam if (first) { 11489578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11499578Ssam goto loop; 11509578Ssam } 11519578Ssam break; 11527502Sroot } 11539578Ssam /* 11549578Ssam * Interpret EOF only in cooked mode. 11559578Ssam */ 11569578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11579578Ssam break; 11589578Ssam /* 11599578Ssam * Give user character. 11609578Ssam */ 116114938Smckusick error = ureadc(c & 0177, uio); 11629578Ssam if (error) 11639578Ssam break; 116414938Smckusick if (uio->uio_resid == 0) 11659578Ssam break; 11669578Ssam /* 11679578Ssam * In cooked mode check for a "break character" 11689578Ssam * marking the end of a "line of input". 11699578Ssam */ 11709578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11719578Ssam break; 11729578Ssam first = 0; 11737502Sroot } 11749578Ssam tp->t_state &= ~TS_BKSL; 11759578Ssam 11769859Ssam checktandem: 11779578Ssam /* 11789578Ssam * Look to unblock output now that (presumably) 11799578Ssam * the input queue has gone down. 11809578Ssam */ 11819859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11829578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11837502Sroot tp->t_state &= ~TS_TBLOCK; 11847502Sroot ttstart(tp); 11857502Sroot } 11868520Sroot return (error); 11877502Sroot } 11887502Sroot 11897502Sroot /* 11907502Sroot * Called from the device's write routine after it has 11917502Sroot * calculated the tty-structure given as argument. 11927502Sroot */ 11937822Sroot ttwrite(tp, uio) 11947625Ssam register struct tty *tp; 11959578Ssam register struct uio *uio; 11967502Sroot { 11977502Sroot register char *cp; 11989578Ssam register int cc, ce, c; 11999578Ssam int i, hiwat, cnt, error, s; 12007502Sroot char obuf[OBUFSIZ]; 12017502Sroot 12029578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 12038520Sroot return (EIO); 12049578Ssam hiwat = TTHIWAT(tp); 12059578Ssam cnt = uio->uio_resid; 12069578Ssam error = 0; 12077502Sroot loop: 12089578Ssam /* 12099578Ssam * Hang the process if it's in the background. 12109578Ssam */ 121115141Skarels #define bit(a) (1<<(a-1)) 12127502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12139578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 121415141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 121515141Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU)) 12167502Sroot /* 12177502Sroot && 12187502Sroot (u.u_procp->p_flag&SDETACH)==0) { 12197502Sroot */ 12207502Sroot ) { 12217502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12227502Sroot sleep((caddr_t)&lbolt, TTIPRI); 12237502Sroot } 122415141Skarels #undef bit 12259578Ssam 12269578Ssam /* 12279578Ssam * Process the user's data in at most OBUFSIZ 12289578Ssam * chunks. Perform lower case simulation and 12299578Ssam * similar hacks. Keep track of high water 12309578Ssam * mark, sleep on overflow awaiting device aid 12319578Ssam * in acquiring new space. 12329578Ssam */ 12337822Sroot while (uio->uio_resid > 0) { 12349578Ssam /* 12359578Ssam * Grab a hunk of data from the user. 12369578Ssam */ 12377822Sroot cc = uio->uio_iov->iov_len; 12387822Sroot if (cc == 0) { 12397822Sroot uio->uio_iovcnt--; 12407822Sroot uio->uio_iov++; 12417822Sroot if (uio->uio_iovcnt < 0) 12427822Sroot panic("ttwrite"); 12437822Sroot continue; 12447822Sroot } 12457822Sroot if (cc > OBUFSIZ) 12467822Sroot cc = OBUFSIZ; 12477502Sroot cp = obuf; 124812752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12498520Sroot if (error) 12507502Sroot break; 12517502Sroot if (tp->t_outq.c_cc > hiwat) 12527502Sroot goto ovhiwat; 12539578Ssam if (tp->t_flags&FLUSHO) 12547502Sroot continue; 12559578Ssam /* 12569578Ssam * If we're mapping lower case or kludging tildes, 12579578Ssam * then we've got to look at each character, so 12589578Ssam * just feed the stuff to ttyoutput... 12599578Ssam */ 12609578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12619578Ssam while (cc > 0) { 12627502Sroot c = *cp++; 12637502Sroot tp->t_rocount = 0; 12647625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12657502Sroot /* out of clists, wait a bit */ 12667502Sroot ttstart(tp); 12677502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12687502Sroot tp->t_rocount = 0; 12697502Sroot } 12707502Sroot --cc; 12717502Sroot if (tp->t_outq.c_cc > hiwat) 12727502Sroot goto ovhiwat; 12737502Sroot } 12747502Sroot continue; 12757502Sroot } 12769578Ssam /* 12779578Ssam * If nothing fancy need be done, grab those characters we 12789578Ssam * can handle without any of ttyoutput's processing and 12799578Ssam * just transfer them to the output q. For those chars 12809578Ssam * which require special processing (as indicated by the 12819578Ssam * bits in partab), call ttyoutput. After processing 12829578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12839578Ssam * immediately. 12849578Ssam */ 12859578Ssam while (cc > 0) { 12869578Ssam if (tp->t_flags & (RAW|LITOUT)) 12877502Sroot ce = cc; 12887502Sroot else { 128912752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 129012752Ssam (caddr_t)partab, 077); 12919578Ssam /* 12929578Ssam * If ce is zero, then we're processing 12939578Ssam * a special character through ttyoutput. 12949578Ssam */ 12959578Ssam if (ce == 0) { 12967502Sroot tp->t_rocount = 0; 12977502Sroot if (ttyoutput(*cp, tp) >= 0) { 12989578Ssam /* no c-lists, wait a bit */ 12997502Sroot ttstart(tp); 13007502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13017502Sroot continue; 13027502Sroot } 13039578Ssam cp++, cc--; 13049578Ssam if (tp->t_flags&FLUSHO || 13059578Ssam tp->t_outq.c_cc > hiwat) 13067502Sroot goto ovhiwat; 13079578Ssam continue; 13087502Sroot } 13097502Sroot } 13109578Ssam /* 13119578Ssam * A bunch of normal characters have been found, 13129578Ssam * transfer them en masse to the output queue and 13139578Ssam * continue processing at the top of the loop. 13149578Ssam * If there are any further characters in this 13159578Ssam * <= OBUFSIZ chunk, the first should be a character 13169578Ssam * requiring special handling by ttyoutput. 13179578Ssam */ 13187502Sroot tp->t_rocount = 0; 13199578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13209578Ssam ce -= i; 13219578Ssam tp->t_col += ce; 13229578Ssam cp += ce, cc -= ce, tk_nout += ce; 13239578Ssam if (i > 0) { 13249578Ssam /* out of c-lists, wait a bit */ 13257502Sroot ttstart(tp); 13267502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13277502Sroot } 13289578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13297502Sroot goto ovhiwat; 13307502Sroot } 13317502Sroot } 13327502Sroot ttstart(tp); 13338520Sroot return (error); 13347502Sroot 13357502Sroot ovhiwat: 133617545Skarels s = spltty(); 13379578Ssam if (cc != 0) { 13389578Ssam uio->uio_iov->iov_base -= cc; 13399578Ssam uio->uio_iov->iov_len += cc; 13409578Ssam uio->uio_resid += cc; 13419578Ssam uio->uio_offset -= cc; 13429578Ssam } 13439578Ssam /* 13449578Ssam * This can only occur if FLUSHO 13459578Ssam * is also set in t_flags. 13469578Ssam */ 13477502Sroot if (tp->t_outq.c_cc <= hiwat) { 13489578Ssam splx(s); 13497502Sroot goto loop; 13507502Sroot } 13517502Sroot ttstart(tp); 13529578Ssam if (tp->t_state&TS_NBIO) { 135317545Skarels splx(s); 13547822Sroot if (uio->uio_resid == cnt) 13558520Sroot return (EWOULDBLOCK); 13568520Sroot return (0); 13577502Sroot } 13587502Sroot tp->t_state |= TS_ASLEEP; 13597502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13609578Ssam splx(s); 13617502Sroot goto loop; 13627502Sroot } 13637502Sroot 13647502Sroot /* 13657502Sroot * Rubout one character from the rawq of tp 13667502Sroot * as cleanly as possible. 13677502Sroot */ 13687502Sroot ttyrub(c, tp) 13697625Ssam register c; 13707625Ssam register struct tty *tp; 13717502Sroot { 13727502Sroot register char *cp; 13737502Sroot register int savecol; 13747502Sroot int s; 13757502Sroot char *nextc(); 13767502Sroot 13779578Ssam if ((tp->t_flags&ECHO) == 0) 13787502Sroot return; 13799578Ssam tp->t_flags &= ~FLUSHO; 13807502Sroot c &= 0377; 13819578Ssam if (tp->t_flags&CRTBS) { 13827502Sroot if (tp->t_rocount == 0) { 13837502Sroot /* 13847502Sroot * Screwed by ttwrite; retype 13857502Sroot */ 13867502Sroot ttyretype(tp); 13877502Sroot return; 13887502Sroot } 13899578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13907502Sroot ttyrubo(tp, 2); 13919578Ssam else switch (partab[c&=0177]&0177) { 13927502Sroot 13937502Sroot case ORDINARY: 13947502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 13957502Sroot ttyrubo(tp, 2); 13967502Sroot else 13977502Sroot ttyrubo(tp, 1); 13987502Sroot break; 13997502Sroot 14007502Sroot case VTAB: 14017502Sroot case BACKSPACE: 14027502Sroot case CONTROL: 14037502Sroot case RETURN: 14049578Ssam if (tp->t_flags&CTLECH) 14057502Sroot ttyrubo(tp, 2); 14067502Sroot break; 14077502Sroot 14087502Sroot case TAB: 14097502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14107502Sroot ttyretype(tp); 14117502Sroot return; 14127502Sroot } 141317545Skarels s = spltty(); 14147502Sroot savecol = tp->t_col; 14159578Ssam tp->t_state |= TS_CNTTB; 14169578Ssam tp->t_flags |= FLUSHO; 14177502Sroot tp->t_col = tp->t_rocol; 14189578Ssam cp = tp->t_rawq.c_cf; 14199578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14207502Sroot ttyecho(*cp, tp); 14219578Ssam tp->t_flags &= ~FLUSHO; 14229578Ssam tp->t_state &= ~TS_CNTTB; 14237502Sroot splx(s); 14247502Sroot /* 14257502Sroot * savecol will now be length of the tab 14267502Sroot */ 14277502Sroot savecol -= tp->t_col; 14287502Sroot tp->t_col += savecol; 14297502Sroot if (savecol > 8) 14307502Sroot savecol = 8; /* overflow screw */ 14317502Sroot while (--savecol >= 0) 14327502Sroot (void) ttyoutput('\b', tp); 14337502Sroot break; 14347502Sroot 14357502Sroot default: 14367502Sroot panic("ttyrub"); 14377502Sroot } 14389578Ssam } else if (tp->t_flags&PRTERA) { 14399578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14407502Sroot (void) ttyoutput('\\', tp); 14419578Ssam tp->t_state |= TS_ERASE; 14427502Sroot } 14437502Sroot ttyecho(c, tp); 14447502Sroot } else 14457502Sroot ttyecho(tp->t_erase, tp); 14467502Sroot tp->t_rocount--; 14477502Sroot } 14487502Sroot 14497502Sroot /* 14507502Sroot * Crt back over cnt chars perhaps 14517502Sroot * erasing them. 14527502Sroot */ 14537502Sroot ttyrubo(tp, cnt) 14547625Ssam register struct tty *tp; 14557625Ssam int cnt; 14567502Sroot { 14579578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14587502Sroot 14597502Sroot while (--cnt >= 0) 14609578Ssam ttyout(rubostring, tp); 14617502Sroot } 14627502Sroot 14637502Sroot /* 14647502Sroot * Reprint the rawq line. 14657502Sroot * We assume c_cc has already been checked. 14667502Sroot */ 14677502Sroot ttyretype(tp) 14687625Ssam register struct tty *tp; 14697502Sroot { 14707502Sroot register char *cp; 14717502Sroot char *nextc(); 14727502Sroot int s; 14737502Sroot 14749578Ssam if (tp->t_rprntc != 0377) 14759578Ssam ttyecho(tp->t_rprntc, tp); 14767502Sroot (void) ttyoutput('\n', tp); 147717545Skarels s = spltty(); 14787502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14797502Sroot ttyecho(*cp, tp); 14807502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14817502Sroot ttyecho(*cp, tp); 14829578Ssam tp->t_state &= ~TS_ERASE; 14837502Sroot splx(s); 14847502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14857502Sroot tp->t_rocol = 0; 14867502Sroot } 14877502Sroot 14887502Sroot /* 14897502Sroot * Echo a typed character to the terminal 14907502Sroot */ 14917502Sroot ttyecho(c, tp) 14927625Ssam register c; 14937625Ssam register struct tty *tp; 14947502Sroot { 14957502Sroot 14969578Ssam if ((tp->t_state&TS_CNTTB) == 0) 14979578Ssam tp->t_flags &= ~FLUSHO; 14987502Sroot if ((tp->t_flags&ECHO) == 0) 14997502Sroot return; 15007502Sroot c &= 0377; 15017502Sroot if (tp->t_flags&RAW) { 15027502Sroot (void) ttyoutput(c, tp); 15037502Sroot return; 15047502Sroot } 15057502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15067502Sroot c = '\n'; 15079578Ssam if (tp->t_flags&CTLECH) { 15087502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15097502Sroot (void) ttyoutput('^', tp); 15107502Sroot c &= 0177; 15117502Sroot if (c == 0177) 15127502Sroot c = '?'; 15137502Sroot else if (tp->t_flags&LCASE) 15147502Sroot c += 'a' - 1; 15157502Sroot else 15167502Sroot c += 'A' - 1; 15177502Sroot } 15187502Sroot } 15197502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 15207502Sroot c += 'a' - 'A'; 15219578Ssam (void) ttyoutput(c&0177, tp); 15227502Sroot } 15237502Sroot 15247502Sroot /* 15257502Sroot * Is c a break char for tp? 15267502Sroot */ 15277502Sroot ttbreakc(c, tp) 15287625Ssam register c; 15297625Ssam register struct tty *tp; 15307502Sroot { 15319578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15327502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15337502Sroot } 15347502Sroot 15357502Sroot /* 15367502Sroot * send string cp to tp 15377502Sroot */ 15387502Sroot ttyout(cp, tp) 15397625Ssam register char *cp; 15407625Ssam register struct tty *tp; 15417502Sroot { 15427502Sroot register char c; 15437502Sroot 15447502Sroot while (c = *cp++) 15457502Sroot (void) ttyoutput(c, tp); 15467502Sroot } 15477502Sroot 15487502Sroot ttwakeup(tp) 15497502Sroot struct tty *tp; 15507502Sroot { 15517502Sroot 15527502Sroot if (tp->t_rsel) { 15537502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15547502Sroot tp->t_state &= ~TS_RCOLL; 15557502Sroot tp->t_rsel = 0; 15567502Sroot } 155712752Ssam if (tp->t_state & TS_ASYNC) 155812752Ssam gsignal(tp->t_pgrp, SIGIO); 15597502Sroot wakeup((caddr_t)&tp->t_rawq); 15607502Sroot } 15617502Sroot 156213533Ssam #if !defined(vax) 15639578Ssam scanc(size, cp, table, mask) 15649578Ssam register int size; 15659578Ssam register char *cp, table[]; 15669578Ssam register int mask; 15677502Sroot { 15689578Ssam register int i = 0; 15697502Sroot 15709578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15719578Ssam i++; 157215100Skarels return (size - i); 15737502Sroot } 15749578Ssam #endif 1575