1*23165Sbloom /* tty.c 6.18 85/06/08 */ 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; 30118650Sbloom 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 */ 47418650Sbloom 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; 48618650Sbloom } 48712752Ssam 48812752Ssam case TIOCGPGRP: 48912752Ssam *(int *)data = tp->t_pgrp; 49012752Ssam break; 49112752Ssam 49217598Sbloom case TIOCSWINSZ: 49318650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 49418650Sbloom 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); 53521776Sbloom if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 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) { 69121776Sbloom if (t_flags&ECHO) 6927502Sroot ttyout("^\b", tp); 6939578Ssam tp->t_state |= TS_LNCH; 6949578Ssam goto endcase; 6959578Ssam } 6969578Ssam if (c == tp->t_flushc) { 69721776Sbloom if (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) { 70921776Sbloom if ((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) { 73721776Sbloom if ((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 744*23165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 745*23165Sbloom if (tp->t_state&TS_BKSL) { 746*23165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 747*23165Sbloom if (maptab[c]) 748*23165Sbloom c = maptab[c]; 749*23165Sbloom c |= 0200; 750*23165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 751*23165Sbloom } else if (c >= 'A' && c <= 'Z') 752*23165Sbloom c += 'a' - 'A'; 753*23165Sbloom else if (c == '\\') 754*23165Sbloom tp->t_state |= TS_BKSL; 755*23165Sbloom } 756*23165Sbloom 7579578Ssam /* 7589578Ssam * Cbreak mode, don't process line editing 7599578Ssam * characters; check high water mark for wakeup. 7609578Ssam */ 7619578Ssam if (t_flags&CBREAK) { 7629578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7637502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7647502Sroot tp->t_line == NTTYDISC) 7657502Sroot (void) ttyoutput(CTRL(g), tp); 7667502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7677502Sroot ttwakeup(tp); 7687502Sroot ttyecho(c, tp); 7697502Sroot } 7709578Ssam goto endcase; 7719578Ssam } 7729578Ssam 7739578Ssam /* 7749578Ssam * From here on down cooked mode character 7759578Ssam * processing takes place. 7769578Ssam */ 7779578Ssam if ((tp->t_state&TS_QUOT) && 7789578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7799578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7809578Ssam c |= 0200; 7819578Ssam } 7829578Ssam if (c == tp->t_erase) { 7839578Ssam if (tp->t_rawq.c_cc) 7849578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7859578Ssam goto endcase; 7869578Ssam } 7879578Ssam if (c == tp->t_kill) { 78821776Sbloom if (t_flags&CRTKIL && 7899578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7909578Ssam while (tp->t_rawq.c_cc) 7919578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7929578Ssam } else { 7939578Ssam ttyecho(c, tp); 7949578Ssam ttyecho('\n', tp); 7959578Ssam while (getc(&tp->t_rawq) > 0) 7969578Ssam ; 7979578Ssam tp->t_rocount = 0; 7989578Ssam } 7999578Ssam tp->t_state &= ~TS_LOCAL; 8009578Ssam goto endcase; 8019578Ssam } 8029578Ssam 8039578Ssam /* 8049578Ssam * New line discipline, 8059578Ssam * check word erase/reprint line. 8069578Ssam */ 8079578Ssam if (tp->t_line == NTTYDISC) { 8089578Ssam if (c == tp->t_werasc) { 8099578Ssam if (tp->t_rawq.c_cc == 0) 8109578Ssam goto endcase; 8119578Ssam do { 8129578Ssam c = unputc(&tp->t_rawq); 8139578Ssam if (c != ' ' && c != '\t') 8149578Ssam goto erasenb; 8159578Ssam ttyrub(c, tp); 8169578Ssam } while (tp->t_rawq.c_cc); 8179578Ssam goto endcase; 8189578Ssam erasenb: 8199578Ssam do { 8209578Ssam ttyrub(c, tp); 8219578Ssam if (tp->t_rawq.c_cc == 0) 8229578Ssam goto endcase; 8239578Ssam c = unputc(&tp->t_rawq); 8249578Ssam } while (c != ' ' && c != '\t'); 8259578Ssam (void) putc(c, &tp->t_rawq); 8269578Ssam goto endcase; 8279578Ssam } 8289578Ssam if (c == tp->t_rprntc) { 8299578Ssam ttyretype(tp); 8309578Ssam goto endcase; 8319578Ssam } 8329578Ssam } 8339578Ssam 8349578Ssam /* 8359578Ssam * Check for input buffer overflow 8369578Ssam */ 83710391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 83810391Ssam if (tp->t_line == NTTYDISC) 83910391Ssam (void) ttyoutput(CTRL(g), tp); 8409578Ssam goto endcase; 84110391Ssam } 8429578Ssam 8439578Ssam /* 8449578Ssam * Put data char in q for user and 8459578Ssam * wakeup on seeing a line delimiter. 8469578Ssam */ 8479578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8489578Ssam if (ttbreakc(c, tp)) { 8499578Ssam tp->t_rocount = 0; 8509578Ssam catq(&tp->t_rawq, &tp->t_canq); 8517502Sroot ttwakeup(tp); 8529578Ssam } else if (tp->t_rocount++ == 0) 8539578Ssam tp->t_rocol = tp->t_col; 8549578Ssam tp->t_state &= ~TS_QUOT; 8559578Ssam if (c == '\\') 8569578Ssam tp->t_state |= TS_QUOT; 8579578Ssam if (tp->t_state&TS_ERASE) { 8589578Ssam tp->t_state &= ~TS_ERASE; 8599578Ssam (void) ttyoutput('/', tp); 8609578Ssam } 8619578Ssam i = tp->t_col; 8627502Sroot ttyecho(c, tp); 86321776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 8649578Ssam i = MIN(2, tp->t_col - i); 8659578Ssam while (i > 0) { 8669578Ssam (void) ttyoutput('\b', tp); 8679578Ssam i--; 8689578Ssam } 8699578Ssam } 8707502Sroot } 8719578Ssam endcase: 8729578Ssam /* 8739578Ssam * If DEC-style start/stop is enabled don't restart 8749578Ssam * output until seeing the start character. 8759578Ssam */ 87621776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8779578Ssam tp->t_startc != tp->t_stopc) 8787502Sroot return; 8799578Ssam restartoutput: 8807502Sroot tp->t_state &= ~TS_TTSTOP; 8819578Ssam tp->t_flags &= ~FLUSHO; 8829578Ssam startoutput: 8837502Sroot ttstart(tp); 8847502Sroot } 8857502Sroot 8867502Sroot /* 8879578Ssam * Put character on TTY output queue, adding delays, 8887502Sroot * expanding tabs, and handling the CR/NL bit. 8899578Ssam * This is called both from the top half for output, 8909578Ssam * and from interrupt level for echoing. 8917502Sroot * The arguments are the character and the tty structure. 8927502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8937502Sroot * Must be recursive. 8947502Sroot */ 8957502Sroot ttyoutput(c, tp) 8967502Sroot register c; 8977502Sroot register struct tty *tp; 8987502Sroot { 8997502Sroot register char *colp; 9007502Sroot register ctype; 9017502Sroot 9029578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9039578Ssam if (tp->t_flags&FLUSHO) 9047502Sroot return (-1); 9057502Sroot if (putc(c, &tp->t_outq)) 9067625Ssam return (c); 9077502Sroot tk_nout++; 9087502Sroot return (-1); 9097502Sroot } 9109578Ssam 9117502Sroot /* 9129578Ssam * Ignore EOT in normal mode to avoid 9139578Ssam * hanging up certain terminals. 9147502Sroot */ 9157502Sroot c &= 0177; 9169578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9177502Sroot return (-1); 9187502Sroot /* 9197502Sroot * Turn tabs to spaces as required 9207502Sroot */ 9219578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9227502Sroot register int s; 9237502Sroot 9247502Sroot c = 8 - (tp->t_col&7); 9259578Ssam if ((tp->t_flags&FLUSHO) == 0) { 92617545Skarels s = spltty(); /* don't interrupt tabs */ 9277502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9287502Sroot tk_nout += c; 9297502Sroot splx(s); 9307502Sroot } 9317502Sroot tp->t_col += c; 9327502Sroot return (c ? -1 : '\t'); 9337502Sroot } 9347502Sroot tk_nout++; 9357502Sroot /* 9367502Sroot * for upper-case-only terminals, 9377502Sroot * generate escapes. 9387502Sroot */ 9397502Sroot if (tp->t_flags&LCASE) { 9407502Sroot colp = "({)}!|^~'`"; 9417625Ssam while (*colp++) 9427625Ssam if (c == *colp++) { 9437502Sroot if (ttyoutput('\\', tp) >= 0) 9447502Sroot return (c); 9457502Sroot c = colp[-2]; 9467502Sroot break; 9477502Sroot } 9489578Ssam if ('A' <= c && c <= 'Z') { 9497502Sroot if (ttyoutput('\\', tp) >= 0) 9507502Sroot return (c); 9519578Ssam } else if ('a' <= c && c <= 'z') 9527502Sroot c += 'A' - 'a'; 9537502Sroot } 9549578Ssam 9557502Sroot /* 9567502Sroot * turn <nl> to <cr><lf> if desired. 9577502Sroot */ 9589578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9597502Sroot if (ttyoutput('\r', tp) >= 0) 9607502Sroot return (c); 9619578Ssam if (c == '~' && tp->t_flags&TILDE) 9627502Sroot c = '`'; 9639578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9647502Sroot return (c); 9657502Sroot /* 9667502Sroot * Calculate delays. 9677502Sroot * The numbers here represent clock ticks 9687502Sroot * and are not necessarily optimal for all terminals. 9697502Sroot * The delays are indicated by characters above 0200. 9707502Sroot * In raw mode there are no delays and the 9717502Sroot * transmission path is 8 bits wide. 9729578Ssam * 9739578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9747502Sroot */ 9757502Sroot colp = &tp->t_col; 9767502Sroot ctype = partab[c]; 9777502Sroot c = 0; 9787502Sroot switch (ctype&077) { 9797502Sroot 9807502Sroot case ORDINARY: 9817502Sroot (*colp)++; 9827502Sroot 9837502Sroot case CONTROL: 9847502Sroot break; 9857502Sroot 9867502Sroot case BACKSPACE: 9877502Sroot if (*colp) 9887502Sroot (*colp)--; 9897502Sroot break; 9907502Sroot 99113821Ssam /* 99213821Ssam * This macro is close enough to the correct thing; 99313821Ssam * it should be replaced by real user settable delays 99413821Ssam * in any event... 99513821Ssam */ 99613821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9977502Sroot case NEWLINE: 9987502Sroot ctype = (tp->t_flags >> 8) & 03; 9997625Ssam if (ctype == 1) { /* tty 37 */ 100012752Ssam if (*colp > 0) 100113863Ssam c = max((((unsigned)*colp) >> 4) + 3, 100213863Ssam (unsigned)6); 10039578Ssam } else if (ctype == 2) /* vt05 */ 100413821Ssam c = mstohz(100); 10057502Sroot *colp = 0; 10067502Sroot break; 10077502Sroot 10087502Sroot case TAB: 10097502Sroot ctype = (tp->t_flags >> 10) & 03; 10107625Ssam if (ctype == 1) { /* tty 37 */ 10117502Sroot c = 1 - (*colp | ~07); 10127625Ssam if (c < 5) 10137502Sroot c = 0; 10147502Sroot } 10157502Sroot *colp |= 07; 10167502Sroot (*colp)++; 10177502Sroot break; 10187502Sroot 10197502Sroot case VTAB: 10209578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10217502Sroot c = 0177; 10227502Sroot break; 10237502Sroot 10247502Sroot case RETURN: 10257502Sroot ctype = (tp->t_flags >> 12) & 03; 10269578Ssam if (ctype == 1) /* tn 300 */ 102713821Ssam c = mstohz(83); 10289578Ssam else if (ctype == 2) /* ti 700 */ 102913821Ssam c = mstohz(166); 10309578Ssam else if (ctype == 3) { /* concept 100 */ 10317502Sroot int i; 10329578Ssam 10337502Sroot if ((i = *colp) >= 0) 10349578Ssam for (; i < 9; i++) 10357502Sroot (void) putc(0177, &tp->t_outq); 10367502Sroot } 10377502Sroot *colp = 0; 10387502Sroot } 10399578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10407502Sroot (void) putc(c|0200, &tp->t_outq); 10417502Sroot return (-1); 10427502Sroot } 104313821Ssam #undef mstohz 10447502Sroot 10457502Sroot /* 10467502Sroot * Called from device's read routine after it has 10477502Sroot * calculated the tty-structure given as argument. 10487502Sroot */ 10497722Swnj ttread(tp, uio) 10507625Ssam register struct tty *tp; 10517722Swnj struct uio *uio; 10527502Sroot { 10537502Sroot register struct clist *qp; 10549578Ssam register c, t_flags; 10559859Ssam int s, first, error = 0; 10567502Sroot 10577502Sroot loop: 10589578Ssam /* 10599578Ssam * Take any pending input first. 10609578Ssam */ 106117545Skarels s = spltty(); 10629578Ssam if (tp->t_flags&PENDIN) 10637502Sroot ttypend(tp); 10649859Ssam splx(s); 10659578Ssam 1066*23165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 1067*23165Sbloom return (EIO); 1068*23165Sbloom 10699578Ssam /* 10709578Ssam * Hang process if it's in the background. 10719578Ssam */ 107215141Skarels #define bit(a) (1<<(a-1)) 1073*23165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 107415141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 107515141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10767502Sroot u.u_procp->p_flag&SVFORK) 10778520Sroot return (EIO); 10787502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10797502Sroot sleep((caddr_t)&lbolt, TTIPRI); 1080*23165Sbloom goto loop; 10817502Sroot } 10829578Ssam t_flags = tp->t_flags; 108315141Skarels #undef bit 10849578Ssam 10859578Ssam /* 10869578Ssam * In raw mode take characters directly from the 10879578Ssam * raw queue w/o processing. Interlock against 10889578Ssam * device interrupts when interrogating rawq. 10899578Ssam */ 10909578Ssam if (t_flags&RAW) { 109117545Skarels s = spltty(); 10927502Sroot if (tp->t_rawq.c_cc <= 0) { 10939578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10947502Sroot (tp->t_state&TS_NBIO)) { 10959859Ssam splx(s); 109615094Skarels return (EWOULDBLOCK); 10977502Sroot } 10987502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10999859Ssam splx(s); 11007502Sroot goto loop; 11017502Sroot } 11029859Ssam splx(s); 110314938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 110414938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11059859Ssam goto checktandem; 11069578Ssam } 11079578Ssam 11089578Ssam /* 11099578Ssam * In cbreak mode use the rawq, otherwise 11109578Ssam * take characters from the canonicalized q. 11119578Ssam */ 11129578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11139578Ssam 11149578Ssam /* 11159578Ssam * No input, sleep on rawq awaiting hardware 11169578Ssam * receipt and notification. 11179578Ssam */ 111817545Skarels s = spltty(); 11199578Ssam if (qp->c_cc <= 0) { 11209578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11219578Ssam (tp->t_state&TS_NBIO)) { 11229859Ssam splx(s); 11239578Ssam return (EWOULDBLOCK); 11247502Sroot } 11259578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11269859Ssam splx(s); 11279578Ssam goto loop; 11289578Ssam } 11299859Ssam splx(s); 11309578Ssam 11319578Ssam /* 11329578Ssam * Input present, perform input mapping 11339578Ssam * and processing (we're not in raw mode). 11349578Ssam */ 11359578Ssam first = 1; 11369578Ssam while ((c = getc(qp)) >= 0) { 11379578Ssam if (t_flags&CRMOD && c == '\r') 11389578Ssam c = '\n'; 11399578Ssam /* 11409578Ssam * Check for delayed suspend character. 11419578Ssam */ 11429578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11439578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11449578Ssam if (first) { 11459578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11469578Ssam goto loop; 11479578Ssam } 11489578Ssam break; 11497502Sroot } 11509578Ssam /* 11519578Ssam * Interpret EOF only in cooked mode. 11529578Ssam */ 11539578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11549578Ssam break; 11559578Ssam /* 11569578Ssam * Give user character. 11579578Ssam */ 115814938Smckusick error = ureadc(c & 0177, uio); 11599578Ssam if (error) 11609578Ssam break; 116114938Smckusick if (uio->uio_resid == 0) 11629578Ssam break; 11639578Ssam /* 11649578Ssam * In cooked mode check for a "break character" 11659578Ssam * marking the end of a "line of input". 11669578Ssam */ 11679578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11689578Ssam break; 11699578Ssam first = 0; 11707502Sroot } 11719578Ssam 11729859Ssam checktandem: 11739578Ssam /* 11749578Ssam * Look to unblock output now that (presumably) 11759578Ssam * the input queue has gone down. 11769578Ssam */ 11779859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11789578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11797502Sroot tp->t_state &= ~TS_TBLOCK; 11807502Sroot ttstart(tp); 11817502Sroot } 11828520Sroot return (error); 11837502Sroot } 11847502Sroot 11857502Sroot /* 11867502Sroot * Called from the device's write routine after it has 11877502Sroot * calculated the tty-structure given as argument. 11887502Sroot */ 11897822Sroot ttwrite(tp, uio) 11907625Ssam register struct tty *tp; 11919578Ssam register struct uio *uio; 11927502Sroot { 11937502Sroot register char *cp; 11949578Ssam register int cc, ce, c; 11959578Ssam int i, hiwat, cnt, error, s; 11967502Sroot char obuf[OBUFSIZ]; 11977502Sroot 11989578Ssam hiwat = TTHIWAT(tp); 11999578Ssam cnt = uio->uio_resid; 12009578Ssam error = 0; 12017502Sroot loop: 120221776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 120321776Sbloom return (EIO); 12049578Ssam /* 12059578Ssam * Hang the process if it's in the background. 12069578Ssam */ 120715141Skarels #define bit(a) (1<<(a-1)) 120821776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12099578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 121015141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 121121776Sbloom !(u.u_procp->p_sigmask & bit(SIGTTOU))) { 12127502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12137502Sroot sleep((caddr_t)&lbolt, TTIPRI); 121421776Sbloom goto loop; 12157502Sroot } 121615141Skarels #undef bit 12179578Ssam 12189578Ssam /* 12199578Ssam * Process the user's data in at most OBUFSIZ 12209578Ssam * chunks. Perform lower case simulation and 12219578Ssam * similar hacks. Keep track of high water 12229578Ssam * mark, sleep on overflow awaiting device aid 12239578Ssam * in acquiring new space. 12249578Ssam */ 12257822Sroot while (uio->uio_resid > 0) { 12269578Ssam /* 12279578Ssam * Grab a hunk of data from the user. 12289578Ssam */ 12297822Sroot cc = uio->uio_iov->iov_len; 12307822Sroot if (cc == 0) { 12317822Sroot uio->uio_iovcnt--; 12327822Sroot uio->uio_iov++; 123321776Sbloom if (uio->uio_iovcnt <= 0) 12347822Sroot panic("ttwrite"); 12357822Sroot continue; 12367822Sroot } 12377822Sroot if (cc > OBUFSIZ) 12387822Sroot cc = OBUFSIZ; 12397502Sroot cp = obuf; 124012752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12418520Sroot if (error) 12427502Sroot break; 12437502Sroot if (tp->t_outq.c_cc > hiwat) 12447502Sroot goto ovhiwat; 12459578Ssam if (tp->t_flags&FLUSHO) 12467502Sroot continue; 12479578Ssam /* 12489578Ssam * If we're mapping lower case or kludging tildes, 12499578Ssam * then we've got to look at each character, so 12509578Ssam * just feed the stuff to ttyoutput... 12519578Ssam */ 12529578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12539578Ssam while (cc > 0) { 12547502Sroot c = *cp++; 12557502Sroot tp->t_rocount = 0; 12567625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12577502Sroot /* out of clists, wait a bit */ 12587502Sroot ttstart(tp); 12597502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12607502Sroot tp->t_rocount = 0; 126121776Sbloom if (cc != 0) { 126221776Sbloom uio->uio_iov->iov_base -= cc; 126321776Sbloom uio->uio_iov->iov_len += cc; 126421776Sbloom uio->uio_resid += cc; 126521776Sbloom uio->uio_offset -= cc; 126621776Sbloom } 126721776Sbloom goto loop; 12687502Sroot } 12697502Sroot --cc; 12707502Sroot if (tp->t_outq.c_cc > hiwat) 12717502Sroot goto ovhiwat; 12727502Sroot } 12737502Sroot continue; 12747502Sroot } 12759578Ssam /* 12769578Ssam * If nothing fancy need be done, grab those characters we 12779578Ssam * can handle without any of ttyoutput's processing and 12789578Ssam * just transfer them to the output q. For those chars 12799578Ssam * which require special processing (as indicated by the 12809578Ssam * bits in partab), call ttyoutput. After processing 12819578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12829578Ssam * immediately. 12839578Ssam */ 12849578Ssam while (cc > 0) { 12859578Ssam if (tp->t_flags & (RAW|LITOUT)) 12867502Sroot ce = cc; 12877502Sroot else { 128812752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 128912752Ssam (caddr_t)partab, 077); 12909578Ssam /* 12919578Ssam * If ce is zero, then we're processing 12929578Ssam * a special character through ttyoutput. 12939578Ssam */ 12949578Ssam if (ce == 0) { 12957502Sroot tp->t_rocount = 0; 12967502Sroot if (ttyoutput(*cp, tp) >= 0) { 129721776Sbloom /* no c-lists, wait a bit */ 129821776Sbloom ttstart(tp); 129921776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 130021776Sbloom if (cc != 0) { 130121776Sbloom uio->uio_iov->iov_base -= cc; 130221776Sbloom uio->uio_iov->iov_len += cc; 130321776Sbloom uio->uio_resid += cc; 130421776Sbloom uio->uio_offset -= cc; 130521776Sbloom } 130621776Sbloom goto loop; 13077502Sroot } 13089578Ssam cp++, cc--; 13099578Ssam if (tp->t_flags&FLUSHO || 13109578Ssam tp->t_outq.c_cc > hiwat) 13117502Sroot goto ovhiwat; 13129578Ssam continue; 13137502Sroot } 13147502Sroot } 13159578Ssam /* 13169578Ssam * A bunch of normal characters have been found, 13179578Ssam * transfer them en masse to the output queue and 13189578Ssam * continue processing at the top of the loop. 13199578Ssam * If there are any further characters in this 13209578Ssam * <= OBUFSIZ chunk, the first should be a character 13219578Ssam * requiring special handling by ttyoutput. 13229578Ssam */ 13237502Sroot tp->t_rocount = 0; 13249578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13259578Ssam ce -= i; 13269578Ssam tp->t_col += ce; 13279578Ssam cp += ce, cc -= ce, tk_nout += ce; 13289578Ssam if (i > 0) { 13299578Ssam /* out of c-lists, wait a bit */ 13307502Sroot ttstart(tp); 13317502Sroot sleep((caddr_t)&lbolt, TTOPRI); 133221776Sbloom uio->uio_iov->iov_base -= cc; 133321776Sbloom uio->uio_iov->iov_len += cc; 133421776Sbloom uio->uio_resid += cc; 133521776Sbloom uio->uio_offset -= cc; 133621776Sbloom goto loop; 13377502Sroot } 13389578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13397502Sroot goto ovhiwat; 13407502Sroot } 13417502Sroot } 13427502Sroot ttstart(tp); 13438520Sroot return (error); 13447502Sroot 13457502Sroot ovhiwat: 134617545Skarels s = spltty(); 13479578Ssam if (cc != 0) { 13489578Ssam uio->uio_iov->iov_base -= cc; 13499578Ssam uio->uio_iov->iov_len += cc; 13509578Ssam uio->uio_resid += cc; 13519578Ssam uio->uio_offset -= cc; 13529578Ssam } 13539578Ssam /* 13549578Ssam * This can only occur if FLUSHO 13559578Ssam * is also set in t_flags. 13569578Ssam */ 13577502Sroot if (tp->t_outq.c_cc <= hiwat) { 13589578Ssam splx(s); 13597502Sroot goto loop; 13607502Sroot } 13617502Sroot ttstart(tp); 13629578Ssam if (tp->t_state&TS_NBIO) { 136317545Skarels splx(s); 13647822Sroot if (uio->uio_resid == cnt) 13658520Sroot return (EWOULDBLOCK); 13668520Sroot return (0); 13677502Sroot } 13687502Sroot tp->t_state |= TS_ASLEEP; 13697502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13709578Ssam splx(s); 13717502Sroot goto loop; 13727502Sroot } 13737502Sroot 13747502Sroot /* 13757502Sroot * Rubout one character from the rawq of tp 13767502Sroot * as cleanly as possible. 13777502Sroot */ 13787502Sroot ttyrub(c, tp) 13797625Ssam register c; 13807625Ssam register struct tty *tp; 13817502Sroot { 13827502Sroot register char *cp; 13837502Sroot register int savecol; 13847502Sroot int s; 13857502Sroot char *nextc(); 13867502Sroot 13879578Ssam if ((tp->t_flags&ECHO) == 0) 13887502Sroot return; 13899578Ssam tp->t_flags &= ~FLUSHO; 13907502Sroot c &= 0377; 13919578Ssam if (tp->t_flags&CRTBS) { 13927502Sroot if (tp->t_rocount == 0) { 13937502Sroot /* 13947502Sroot * Screwed by ttwrite; retype 13957502Sroot */ 13967502Sroot ttyretype(tp); 13977502Sroot return; 13987502Sroot } 13999578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14007502Sroot ttyrubo(tp, 2); 14019578Ssam else switch (partab[c&=0177]&0177) { 14027502Sroot 14037502Sroot case ORDINARY: 14047502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14057502Sroot ttyrubo(tp, 2); 14067502Sroot else 14077502Sroot ttyrubo(tp, 1); 14087502Sroot break; 14097502Sroot 14107502Sroot case VTAB: 14117502Sroot case BACKSPACE: 14127502Sroot case CONTROL: 14137502Sroot case RETURN: 14149578Ssam if (tp->t_flags&CTLECH) 14157502Sroot ttyrubo(tp, 2); 14167502Sroot break; 14177502Sroot 14187502Sroot case TAB: 14197502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14207502Sroot ttyretype(tp); 14217502Sroot return; 14227502Sroot } 142317545Skarels s = spltty(); 14247502Sroot savecol = tp->t_col; 14259578Ssam tp->t_state |= TS_CNTTB; 14269578Ssam tp->t_flags |= FLUSHO; 14277502Sroot tp->t_col = tp->t_rocol; 14289578Ssam cp = tp->t_rawq.c_cf; 14299578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14307502Sroot ttyecho(*cp, tp); 14319578Ssam tp->t_flags &= ~FLUSHO; 14329578Ssam tp->t_state &= ~TS_CNTTB; 14337502Sroot splx(s); 14347502Sroot /* 14357502Sroot * savecol will now be length of the tab 14367502Sroot */ 14377502Sroot savecol -= tp->t_col; 14387502Sroot tp->t_col += savecol; 14397502Sroot if (savecol > 8) 14407502Sroot savecol = 8; /* overflow screw */ 14417502Sroot while (--savecol >= 0) 14427502Sroot (void) ttyoutput('\b', tp); 14437502Sroot break; 14447502Sroot 14457502Sroot default: 14467502Sroot panic("ttyrub"); 14477502Sroot } 14489578Ssam } else if (tp->t_flags&PRTERA) { 14499578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14507502Sroot (void) ttyoutput('\\', tp); 14519578Ssam tp->t_state |= TS_ERASE; 14527502Sroot } 14537502Sroot ttyecho(c, tp); 14547502Sroot } else 14557502Sroot ttyecho(tp->t_erase, tp); 14567502Sroot tp->t_rocount--; 14577502Sroot } 14587502Sroot 14597502Sroot /* 14607502Sroot * Crt back over cnt chars perhaps 14617502Sroot * erasing them. 14627502Sroot */ 14637502Sroot ttyrubo(tp, cnt) 14647625Ssam register struct tty *tp; 14657625Ssam int cnt; 14667502Sroot { 14679578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14687502Sroot 14697502Sroot while (--cnt >= 0) 14709578Ssam ttyout(rubostring, tp); 14717502Sroot } 14727502Sroot 14737502Sroot /* 14747502Sroot * Reprint the rawq line. 14757502Sroot * We assume c_cc has already been checked. 14767502Sroot */ 14777502Sroot ttyretype(tp) 14787625Ssam register struct tty *tp; 14797502Sroot { 14807502Sroot register char *cp; 14817502Sroot char *nextc(); 14827502Sroot int s; 14837502Sroot 14849578Ssam if (tp->t_rprntc != 0377) 14859578Ssam ttyecho(tp->t_rprntc, tp); 14867502Sroot (void) ttyoutput('\n', tp); 148717545Skarels s = spltty(); 14887502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14897502Sroot ttyecho(*cp, tp); 14907502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14917502Sroot ttyecho(*cp, tp); 14929578Ssam tp->t_state &= ~TS_ERASE; 14937502Sroot splx(s); 14947502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14957502Sroot tp->t_rocol = 0; 14967502Sroot } 14977502Sroot 14987502Sroot /* 14997502Sroot * Echo a typed character to the terminal 15007502Sroot */ 15017502Sroot ttyecho(c, tp) 15027625Ssam register c; 15037625Ssam register struct tty *tp; 15047502Sroot { 15057502Sroot 15069578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15079578Ssam tp->t_flags &= ~FLUSHO; 15087502Sroot if ((tp->t_flags&ECHO) == 0) 15097502Sroot return; 15107502Sroot c &= 0377; 15117502Sroot if (tp->t_flags&RAW) { 15127502Sroot (void) ttyoutput(c, tp); 15137502Sroot return; 15147502Sroot } 15157502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15167502Sroot c = '\n'; 15179578Ssam if (tp->t_flags&CTLECH) { 15187502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15197502Sroot (void) ttyoutput('^', tp); 15207502Sroot c &= 0177; 15217502Sroot if (c == 0177) 15227502Sroot c = '?'; 15237502Sroot else if (tp->t_flags&LCASE) 15247502Sroot c += 'a' - 1; 15257502Sroot else 15267502Sroot c += 'A' - 1; 15277502Sroot } 15287502Sroot } 15299578Ssam (void) ttyoutput(c&0177, tp); 15307502Sroot } 15317502Sroot 15327502Sroot /* 15337502Sroot * Is c a break char for tp? 15347502Sroot */ 15357502Sroot ttbreakc(c, tp) 15367625Ssam register c; 15377625Ssam register struct tty *tp; 15387502Sroot { 15399578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15407502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15417502Sroot } 15427502Sroot 15437502Sroot /* 15447502Sroot * send string cp to tp 15457502Sroot */ 15467502Sroot ttyout(cp, tp) 15477625Ssam register char *cp; 15487625Ssam register struct tty *tp; 15497502Sroot { 15507502Sroot register char c; 15517502Sroot 15527502Sroot while (c = *cp++) 15537502Sroot (void) ttyoutput(c, tp); 15547502Sroot } 15557502Sroot 15567502Sroot ttwakeup(tp) 15577502Sroot struct tty *tp; 15587502Sroot { 15597502Sroot 15607502Sroot if (tp->t_rsel) { 15617502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15627502Sroot tp->t_state &= ~TS_RCOLL; 15637502Sroot tp->t_rsel = 0; 15647502Sroot } 156512752Ssam if (tp->t_state & TS_ASYNC) 156612752Ssam gsignal(tp->t_pgrp, SIGIO); 15677502Sroot wakeup((caddr_t)&tp->t_rawq); 15687502Sroot } 1569