1*17932Skarels /* tty.c 6.14 85/02/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); 2948556Sroot splx(s); 29510851Ssam if (error) { 29617545Skarels s = spltty(); 29710851Ssam if (tp->t_line) 29810851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 29910851Ssam splx(s); 3008556Sroot return (error); 30110851Ssam } 3028556Sroot tp->t_line = t; 30339Sbill break; 3047625Ssam } 30539Sbill 3068556Sroot /* prevent more opens on channel */ 3075614Swnj case TIOCEXCL: 3085614Swnj tp->t_state |= TS_XCLUDE; 3095614Swnj break; 3105614Swnj 3115614Swnj case TIOCNXCL: 3125614Swnj tp->t_state &= ~TS_XCLUDE; 3135614Swnj break; 3145614Swnj 3158556Sroot /* hang up line on last close */ 31639Sbill case TIOCHPCL: 3175408Swnj tp->t_state |= TS_HUPCLS; 31839Sbill break; 31939Sbill 3203942Sbugs case TIOCFLUSH: { 3217625Ssam register int flags = *(int *)data; 3227625Ssam 3237625Ssam if (flags == 0) 3243942Sbugs flags = FREAD|FWRITE; 3257625Ssam else 3267625Ssam flags &= FREAD|FWRITE; 32712752Ssam ttyflush(tp, flags); 32839Sbill break; 3293944Sbugs } 33039Sbill 3318556Sroot /* return number of characters immediately available */ 3327625Ssam case FIONREAD: 3337625Ssam *(off_t *)data = ttnread(tp); 334174Sbill break; 335174Sbill 33613077Ssam case TIOCOUTQ: 33713077Ssam *(int *)data = tp->t_outq.c_cc; 33813077Ssam break; 33913077Ssam 3408589Sroot case TIOCSTOP: 34117545Skarels s = spltty(); 3429578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3435573Swnj tp->t_state |= TS_TTSTOP; 3445573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3455573Swnj } 3467625Ssam splx(s); 3475573Swnj break; 3485573Swnj 3498589Sroot case TIOCSTART: 35017545Skarels s = spltty(); 3519578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3525573Swnj tp->t_state &= ~TS_TTSTOP; 3539578Ssam tp->t_flags &= ~FLUSHO; 3545573Swnj ttstart(tp); 3555573Swnj } 3567625Ssam splx(s); 3575573Swnj break; 3585573Swnj 3599325Ssam /* 3609325Ssam * Simulate typing of a character at the terminal. 3619325Ssam */ 3629325Ssam case TIOCSTI: 36317183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36417183Smckusick return (EPERM); 3659325Ssam if (u.u_uid && u.u_ttyp != tp) 3669325Ssam return (EACCES); 3679578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3689325Ssam break; 3699325Ssam 37012752Ssam case TIOCSETP: 37112752Ssam case TIOCSETN: { 37212752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37312752Ssam 37412752Ssam tp->t_erase = sg->sg_erase; 37512752Ssam tp->t_kill = sg->sg_kill; 37612752Ssam tp->t_ispeed = sg->sg_ispeed; 37712752Ssam tp->t_ospeed = sg->sg_ospeed; 37812752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37917545Skarels s = spltty(); 38012752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38112752Ssam ttywait(tp); 38212752Ssam ttyflush(tp, FREAD); 38312752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38412752Ssam if (newflags&CBREAK) { 38512752Ssam struct clist tq; 38612752Ssam 38712752Ssam catq(&tp->t_rawq, &tp->t_canq); 38812752Ssam tq = tp->t_rawq; 38912752Ssam tp->t_rawq = tp->t_canq; 39012752Ssam tp->t_canq = tq; 39112752Ssam } else { 39212752Ssam tp->t_flags |= PENDIN; 39313801Ssam newflags |= PENDIN; 39412752Ssam ttwakeup(tp); 39512752Ssam } 39612752Ssam } 39712752Ssam tp->t_flags = newflags; 39812752Ssam if (tp->t_flags&RAW) { 39912752Ssam tp->t_state &= ~TS_TTSTOP; 40012752Ssam ttstart(tp); 40112752Ssam } 40212752Ssam splx(s); 40312752Ssam break; 40412752Ssam } 40512752Ssam 40612752Ssam /* send current parameters to user */ 40712752Ssam case TIOCGETP: { 40812752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40912752Ssam 41012752Ssam sg->sg_ispeed = tp->t_ispeed; 41112752Ssam sg->sg_ospeed = tp->t_ospeed; 41212752Ssam sg->sg_erase = tp->t_erase; 41312752Ssam sg->sg_kill = tp->t_kill; 41412752Ssam sg->sg_flags = tp->t_flags; 41512752Ssam break; 41612752Ssam } 41712752Ssam 41812752Ssam case FIONBIO: 41912752Ssam if (*(int *)data) 42012752Ssam tp->t_state |= TS_NBIO; 42112752Ssam else 42212752Ssam tp->t_state &= ~TS_NBIO; 42312752Ssam break; 42412752Ssam 42512752Ssam case FIOASYNC: 42612752Ssam if (*(int *)data) 42712752Ssam tp->t_state |= TS_ASYNC; 42812752Ssam else 42912752Ssam tp->t_state &= ~TS_ASYNC; 43012752Ssam break; 43112752Ssam 43213077Ssam case TIOCGETC: 43313077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43413077Ssam break; 43513077Ssam 43613077Ssam case TIOCSETC: 43713077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43813077Ssam break; 43913077Ssam 44012752Ssam /* set/get local special characters */ 44112752Ssam case TIOCSLTC: 44212752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44312752Ssam break; 44412752Ssam 44512752Ssam case TIOCGLTC: 44612752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44712752Ssam break; 44812752Ssam 44912752Ssam /* 45012752Ssam * Modify local mode word. 45112752Ssam */ 45212752Ssam case TIOCLBIS: 45312752Ssam tp->t_flags |= *(int *)data << 16; 45412752Ssam break; 45512752Ssam 45612752Ssam case TIOCLBIC: 45712752Ssam tp->t_flags &= ~(*(int *)data << 16); 45812752Ssam break; 45912752Ssam 46012752Ssam case TIOCLSET: 46112752Ssam tp->t_flags &= 0xffff; 46212752Ssam tp->t_flags |= *(int *)data << 16; 46312752Ssam break; 46412752Ssam 46512752Ssam case TIOCLGET: 46615720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46712752Ssam break; 46812752Ssam 46917545Skarels /* 470*17932Skarels * Allow SPGRP only if tty is open for reading. 47117598Sbloom * Quick check: if we can find a process in the new pgrp, 47217598Sbloom * this user must own that process. 47317598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47417545Skarels */ 47512752Ssam case TIOCSPGRP: 47617545Skarels { 47717545Skarels struct proc *p; 47817545Skarels int pgrp = *(int *)data; 47917545Skarels 48017545Skarels if (u.u_uid && (flag & FREAD) == 0) 48117545Skarels return (EPERM); 48217598Sbloom p = pfind(pgrp); 48317598Sbloom if (p && p->p_pgrp == pgrp && 48417598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48517598Sbloom return (EPERM); 48617545Skarels tp->t_pgrp = pgrp; 48712752Ssam break; 48817545Skarels } 48912752Ssam 49012752Ssam case TIOCGPGRP: 49112752Ssam *(int *)data = tp->t_pgrp; 49212752Ssam break; 49312752Ssam 49417598Sbloom case TIOCSWINSZ: 49517598Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 49617598Sbloom sizeof(struct winsize))) { 49717598Sbloom tp->t_winsize = *(struct winsize *)data; 49817598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 49917598Sbloom } 50017598Sbloom break; 50117598Sbloom 50217598Sbloom case TIOCGWINSZ: 50317598Sbloom *(struct winsize *)data = tp->t_winsize; 50417598Sbloom break; 50517598Sbloom 50639Sbill default: 5078556Sroot return (-1); 50839Sbill } 5098556Sroot return (0); 51039Sbill } 5114484Swnj 5124484Swnj ttnread(tp) 5134484Swnj struct tty *tp; 5144484Swnj { 5154484Swnj int nread = 0; 5164484Swnj 5179578Ssam if (tp->t_flags & PENDIN) 5184484Swnj ttypend(tp); 5194484Swnj nread = tp->t_canq.c_cc; 5204484Swnj if (tp->t_flags & (RAW|CBREAK)) 5214484Swnj nread += tp->t_rawq.c_cc; 5224484Swnj return (nread); 5234484Swnj } 5244484Swnj 5255408Swnj ttselect(dev, rw) 5264484Swnj dev_t dev; 5275408Swnj int rw; 5284484Swnj { 5294484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5304484Swnj int nread; 53117545Skarels int s = spltty(); 5324484Swnj 5335408Swnj switch (rw) { 5344484Swnj 5354484Swnj case FREAD: 5364484Swnj nread = ttnread(tp); 5374484Swnj if (nread > 0) 5385408Swnj goto win; 5394938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5405408Swnj tp->t_state |= TS_RCOLL; 5414484Swnj else 5424484Swnj tp->t_rsel = u.u_procp; 5435408Swnj break; 5444484Swnj 5455408Swnj case FWRITE: 5465408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5475408Swnj goto win; 5485408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5495408Swnj tp->t_state |= TS_WCOLL; 5505408Swnj else 5515408Swnj tp->t_wsel = u.u_procp; 5525408Swnj break; 5534484Swnj } 5545408Swnj splx(s); 5555408Swnj return (0); 5565408Swnj win: 5575408Swnj splx(s); 5585408Swnj return (1); 5594484Swnj } 5607436Skre 5617502Sroot /* 5629578Ssam * Establish a process group for distribution of 5637502Sroot * quits and interrupts from the tty. 5647502Sroot */ 5657502Sroot ttyopen(dev, tp) 5667625Ssam dev_t dev; 5677625Ssam register struct tty *tp; 5687502Sroot { 5697502Sroot register struct proc *pp; 5707502Sroot 5717502Sroot pp = u.u_procp; 5727502Sroot tp->t_dev = dev; 5737625Ssam if (pp->p_pgrp == 0) { 5747502Sroot u.u_ttyp = tp; 5757502Sroot u.u_ttyd = dev; 5767502Sroot if (tp->t_pgrp == 0) 5777502Sroot tp->t_pgrp = pp->p_pid; 5787502Sroot pp->p_pgrp = tp->t_pgrp; 5797502Sroot } 5807502Sroot tp->t_state &= ~TS_WOPEN; 58117545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 58217545Skarels tp->t_state |= TS_ISOPEN; 58317598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58417545Skarels if (tp->t_line != NTTYDISC) 58517545Skarels ttywflush(tp); 58617545Skarels } 5878556Sroot return (0); 5887502Sroot } 5897502Sroot 5907502Sroot /* 5917502Sroot * clean tp on last close 5927502Sroot */ 5937502Sroot ttyclose(tp) 5947625Ssam register struct tty *tp; 5957502Sroot { 5967502Sroot 5977502Sroot if (tp->t_line) { 59812752Ssam ttywflush(tp); 5997502Sroot tp->t_line = 0; 6007502Sroot return; 6017502Sroot } 6027502Sroot tp->t_pgrp = 0; 60312752Ssam ttywflush(tp); 6047502Sroot tp->t_state = 0; 6057502Sroot } 6067502Sroot 6077502Sroot /* 6087502Sroot * reinput pending characters after state switch 60917545Skarels * call at spltty(). 6107502Sroot */ 6117502Sroot ttypend(tp) 6127625Ssam register struct tty *tp; 6137502Sroot { 6147502Sroot struct clist tq; 6157502Sroot register c; 6167502Sroot 6179578Ssam tp->t_flags &= ~PENDIN; 6189578Ssam tp->t_state |= TS_TYPEN; 6197502Sroot tq = tp->t_rawq; 6207502Sroot tp->t_rawq.c_cc = 0; 6217502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6227502Sroot while ((c = getc(&tq)) >= 0) 6237502Sroot ttyinput(c, tp); 6249578Ssam tp->t_state &= ~TS_TYPEN; 6257502Sroot } 6267502Sroot 6277502Sroot /* 6289578Ssam * Place a character on raw TTY input queue, 6299578Ssam * putting in delimiters and waking up top 6309578Ssam * half as needed. Also echo if required. 6319578Ssam * The arguments are the character and the 6329578Ssam * appropriate tty structure. 6337502Sroot */ 6347502Sroot ttyinput(c, tp) 6357625Ssam register c; 6367625Ssam register struct tty *tp; 6377502Sroot { 6389578Ssam register int t_flags = tp->t_flags; 6397502Sroot int i; 6407502Sroot 6419578Ssam /* 6429578Ssam * If input is pending take it first. 6439578Ssam */ 6449578Ssam if (t_flags&PENDIN) 6457502Sroot ttypend(tp); 6467502Sroot tk_nin++; 6477502Sroot c &= 0377; 6489578Ssam 6499578Ssam /* 6509578Ssam * In tandem mode, check high water mark. 6519578Ssam */ 6527502Sroot if (t_flags&TANDEM) 6537502Sroot ttyblock(tp); 6549578Ssam 6559578Ssam if (t_flags&RAW) { 6569578Ssam /* 6579578Ssam * Raw mode, just put character 6589578Ssam * in input q w/o interpretation. 6599578Ssam */ 6609578Ssam if (tp->t_rawq.c_cc > TTYHOG) 66112752Ssam ttyflush(tp, FREAD|FWRITE); 6629578Ssam else { 6639578Ssam if (putc(c, &tp->t_rawq) >= 0) 6649578Ssam ttwakeup(tp); 6659578Ssam ttyecho(c, tp); 6667502Sroot } 6679578Ssam goto endcase; 6689578Ssam } 6699578Ssam 6709578Ssam /* 6719578Ssam * Ignore any high bit added during 6729578Ssam * previous ttyinput processing. 6739578Ssam */ 6749578Ssam if ((tp->t_state&TS_TYPEN) == 0) 6759578Ssam c &= 0177; 6769578Ssam /* 6779578Ssam * Check for literal nexting very first 6789578Ssam */ 6799578Ssam if (tp->t_state&TS_LNCH) { 6809578Ssam c |= 0200; 6819578Ssam tp->t_state &= ~TS_LNCH; 6829578Ssam } 6839578Ssam 6849578Ssam /* 6859578Ssam * Scan for special characters. This code 6869578Ssam * is really just a big case statement with 6879578Ssam * non-constant cases. The bottom of the 6889578Ssam * case statement is labeled ``endcase'', so goto 6899578Ssam * it after a case match, or similar. 6909578Ssam */ 6919578Ssam if (tp->t_line == NTTYDISC) { 6929578Ssam if (c == tp->t_lnextc) { 6937502Sroot if (tp->t_flags&ECHO) 6947502Sroot ttyout("^\b", tp); 6959578Ssam tp->t_state |= TS_LNCH; 6969578Ssam goto endcase; 6979578Ssam } 6989578Ssam if (c == tp->t_flushc) { 6999578Ssam if (tp->t_flags&FLUSHO) 7009578Ssam tp->t_flags &= ~FLUSHO; 7017502Sroot else { 70212752Ssam ttyflush(tp, FWRITE); 7037502Sroot ttyecho(c, tp); 7049578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7057502Sroot ttyretype(tp); 7069578Ssam tp->t_flags |= FLUSHO; 7077502Sroot } 7089578Ssam goto startoutput; 7099578Ssam } 7109578Ssam if (c == tp->t_suspc) { 7119578Ssam if ((tp->t_flags&NOFLSH) == 0) 71212752Ssam ttyflush(tp, FREAD); 7139578Ssam ttyecho(c, tp); 7149578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7159578Ssam goto endcase; 7169578Ssam } 7179578Ssam } 7189578Ssam 7199578Ssam /* 7209578Ssam * Handle start/stop characters. 7219578Ssam */ 7229578Ssam if (c == tp->t_stopc) { 7239578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7249578Ssam tp->t_state |= TS_TTSTOP; 7259578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7267502Sroot return; 7279578Ssam } 7289578Ssam if (c != tp->t_startc) 7299578Ssam return; 7309578Ssam goto endcase; 7319578Ssam } 7329578Ssam if (c == tp->t_startc) 7339578Ssam goto restartoutput; 7349578Ssam 7359578Ssam /* 7369578Ssam * Look for interrupt/quit chars. 7379578Ssam */ 7389578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 7399578Ssam if ((tp->t_flags&NOFLSH) == 0) 74012752Ssam ttyflush(tp, FREAD|FWRITE); 7419578Ssam ttyecho(c, tp); 7429578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7439578Ssam goto endcase; 7449578Ssam } 7459578Ssam 7469578Ssam /* 7479578Ssam * Cbreak mode, don't process line editing 7489578Ssam * characters; check high water mark for wakeup. 7499578Ssam */ 7509578Ssam if (t_flags&CBREAK) { 7519578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7527502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7537502Sroot tp->t_line == NTTYDISC) 7547502Sroot (void) ttyoutput(CTRL(g), tp); 7557502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7567502Sroot ttwakeup(tp); 7577502Sroot ttyecho(c, tp); 7587502Sroot } 7599578Ssam goto endcase; 7609578Ssam } 7619578Ssam 7629578Ssam /* 7639578Ssam * From here on down cooked mode character 7649578Ssam * processing takes place. 7659578Ssam */ 7669578Ssam if ((tp->t_state&TS_QUOT) && 7679578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7689578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7699578Ssam c |= 0200; 7709578Ssam } 7719578Ssam if (c == tp->t_erase) { 7729578Ssam if (tp->t_rawq.c_cc) 7739578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7749578Ssam goto endcase; 7759578Ssam } 7769578Ssam if (c == tp->t_kill) { 7779578Ssam if (tp->t_flags&CRTKIL && 7789578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7799578Ssam while (tp->t_rawq.c_cc) 7809578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7819578Ssam } else { 7829578Ssam ttyecho(c, tp); 7839578Ssam ttyecho('\n', tp); 7849578Ssam while (getc(&tp->t_rawq) > 0) 7859578Ssam ; 7869578Ssam tp->t_rocount = 0; 7879578Ssam } 7889578Ssam tp->t_state &= ~TS_LOCAL; 7899578Ssam goto endcase; 7909578Ssam } 7919578Ssam 7929578Ssam /* 7939578Ssam * New line discipline, 7949578Ssam * check word erase/reprint line. 7959578Ssam */ 7969578Ssam if (tp->t_line == NTTYDISC) { 7979578Ssam if (c == tp->t_werasc) { 7989578Ssam if (tp->t_rawq.c_cc == 0) 7999578Ssam goto endcase; 8009578Ssam do { 8019578Ssam c = unputc(&tp->t_rawq); 8029578Ssam if (c != ' ' && c != '\t') 8039578Ssam goto erasenb; 8049578Ssam ttyrub(c, tp); 8059578Ssam } while (tp->t_rawq.c_cc); 8069578Ssam goto endcase; 8079578Ssam erasenb: 8089578Ssam do { 8099578Ssam ttyrub(c, tp); 8109578Ssam if (tp->t_rawq.c_cc == 0) 8119578Ssam goto endcase; 8129578Ssam c = unputc(&tp->t_rawq); 8139578Ssam } while (c != ' ' && c != '\t'); 8149578Ssam (void) putc(c, &tp->t_rawq); 8159578Ssam goto endcase; 8169578Ssam } 8179578Ssam if (c == tp->t_rprntc) { 8189578Ssam ttyretype(tp); 8199578Ssam goto endcase; 8209578Ssam } 8219578Ssam } 8229578Ssam 8239578Ssam /* 8249578Ssam * Check for input buffer overflow 8259578Ssam */ 82610391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 82710391Ssam if (tp->t_line == NTTYDISC) 82810391Ssam (void) ttyoutput(CTRL(g), tp); 8299578Ssam goto endcase; 83010391Ssam } 8319578Ssam 8329578Ssam /* 8339578Ssam * Put data char in q for user and 8349578Ssam * wakeup on seeing a line delimiter. 8359578Ssam */ 8369578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8379578Ssam if (ttbreakc(c, tp)) { 8389578Ssam tp->t_rocount = 0; 8399578Ssam catq(&tp->t_rawq, &tp->t_canq); 8407502Sroot ttwakeup(tp); 8419578Ssam } else if (tp->t_rocount++ == 0) 8429578Ssam tp->t_rocol = tp->t_col; 8439578Ssam tp->t_state &= ~TS_QUOT; 8449578Ssam if (c == '\\') 8459578Ssam tp->t_state |= TS_QUOT; 8469578Ssam if (tp->t_state&TS_ERASE) { 8479578Ssam tp->t_state &= ~TS_ERASE; 8489578Ssam (void) ttyoutput('/', tp); 8499578Ssam } 8509578Ssam i = tp->t_col; 8517502Sroot ttyecho(c, tp); 8529578Ssam if (c == tp->t_eofc && tp->t_flags&ECHO) { 8539578Ssam i = MIN(2, tp->t_col - i); 8549578Ssam while (i > 0) { 8559578Ssam (void) ttyoutput('\b', tp); 8569578Ssam i--; 8579578Ssam } 8589578Ssam } 8597502Sroot } 8609578Ssam 8619578Ssam endcase: 8629578Ssam /* 8639578Ssam * If DEC-style start/stop is enabled don't restart 8649578Ssam * output until seeing the start character. 8659578Ssam */ 8669578Ssam if (tp->t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8679578Ssam tp->t_startc != tp->t_stopc) 8687502Sroot return; 8699578Ssam 8709578Ssam restartoutput: 8717502Sroot tp->t_state &= ~TS_TTSTOP; 8729578Ssam tp->t_flags &= ~FLUSHO; 8739578Ssam 8749578Ssam startoutput: 8757502Sroot ttstart(tp); 8767502Sroot } 8777502Sroot 8787502Sroot /* 8799578Ssam * Put character on TTY output queue, adding delays, 8807502Sroot * expanding tabs, and handling the CR/NL bit. 8819578Ssam * This is called both from the top half for output, 8829578Ssam * and from interrupt level for echoing. 8837502Sroot * The arguments are the character and the tty structure. 8847502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8857502Sroot * Must be recursive. 8867502Sroot */ 8877502Sroot ttyoutput(c, tp) 8887502Sroot register c; 8897502Sroot register struct tty *tp; 8907502Sroot { 8917502Sroot register char *colp; 8927502Sroot register ctype; 8937502Sroot 8949578Ssam if (tp->t_flags & (RAW|LITOUT)) { 8959578Ssam if (tp->t_flags&FLUSHO) 8967502Sroot return (-1); 8977502Sroot if (putc(c, &tp->t_outq)) 8987625Ssam return (c); 8997502Sroot tk_nout++; 9007502Sroot return (-1); 9017502Sroot } 9029578Ssam 9037502Sroot /* 9049578Ssam * Ignore EOT in normal mode to avoid 9059578Ssam * hanging up certain terminals. 9067502Sroot */ 9077502Sroot c &= 0177; 9089578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9097502Sroot return (-1); 9107502Sroot /* 9117502Sroot * Turn tabs to spaces as required 9127502Sroot */ 9139578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9147502Sroot register int s; 9157502Sroot 9167502Sroot c = 8 - (tp->t_col&7); 9179578Ssam if ((tp->t_flags&FLUSHO) == 0) { 91817545Skarels s = spltty(); /* don't interrupt tabs */ 9197502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9207502Sroot tk_nout += c; 9217502Sroot splx(s); 9227502Sroot } 9237502Sroot tp->t_col += c; 9247502Sroot return (c ? -1 : '\t'); 9257502Sroot } 9267502Sroot tk_nout++; 9277502Sroot /* 9287502Sroot * for upper-case-only terminals, 9297502Sroot * generate escapes. 9307502Sroot */ 9317502Sroot if (tp->t_flags&LCASE) { 9327502Sroot colp = "({)}!|^~'`"; 9337625Ssam while (*colp++) 9347625Ssam if (c == *colp++) { 9357502Sroot if (ttyoutput('\\', tp) >= 0) 9367502Sroot return (c); 9377502Sroot c = colp[-2]; 9387502Sroot break; 9397502Sroot } 9409578Ssam if ('A' <= c && c <= 'Z') { 9417502Sroot if (ttyoutput('\\', tp) >= 0) 9427502Sroot return (c); 9439578Ssam } else if ('a' <= c && c <= 'z') 9447502Sroot c += 'A' - 'a'; 9457502Sroot } 9469578Ssam 9477502Sroot /* 9487502Sroot * turn <nl> to <cr><lf> if desired. 9497502Sroot */ 9509578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9517502Sroot if (ttyoutput('\r', tp) >= 0) 9527502Sroot return (c); 9539578Ssam if (c == '~' && tp->t_flags&TILDE) 9547502Sroot c = '`'; 9559578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9567502Sroot return (c); 9577502Sroot /* 9587502Sroot * Calculate delays. 9597502Sroot * The numbers here represent clock ticks 9607502Sroot * and are not necessarily optimal for all terminals. 9617502Sroot * The delays are indicated by characters above 0200. 9627502Sroot * In raw mode there are no delays and the 9637502Sroot * transmission path is 8 bits wide. 9649578Ssam * 9659578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9667502Sroot */ 9677502Sroot colp = &tp->t_col; 9687502Sroot ctype = partab[c]; 9697502Sroot c = 0; 9707502Sroot switch (ctype&077) { 9717502Sroot 9727502Sroot case ORDINARY: 9737502Sroot (*colp)++; 9747502Sroot 9757502Sroot case CONTROL: 9767502Sroot break; 9777502Sroot 9787502Sroot case BACKSPACE: 9797502Sroot if (*colp) 9807502Sroot (*colp)--; 9817502Sroot break; 9827502Sroot 98313821Ssam /* 98413821Ssam * This macro is close enough to the correct thing; 98513821Ssam * it should be replaced by real user settable delays 98613821Ssam * in any event... 98713821Ssam */ 98813821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 9897502Sroot case NEWLINE: 9907502Sroot ctype = (tp->t_flags >> 8) & 03; 9917625Ssam if (ctype == 1) { /* tty 37 */ 99212752Ssam if (*colp > 0) 99313863Ssam c = max((((unsigned)*colp) >> 4) + 3, 99413863Ssam (unsigned)6); 9959578Ssam } else if (ctype == 2) /* vt05 */ 99613821Ssam c = mstohz(100); 9977502Sroot *colp = 0; 9987502Sroot break; 9997502Sroot 10007502Sroot case TAB: 10017502Sroot ctype = (tp->t_flags >> 10) & 03; 10027625Ssam if (ctype == 1) { /* tty 37 */ 10037502Sroot c = 1 - (*colp | ~07); 10047625Ssam if (c < 5) 10057502Sroot c = 0; 10067502Sroot } 10077502Sroot *colp |= 07; 10087502Sroot (*colp)++; 10097502Sroot break; 10107502Sroot 10117502Sroot case VTAB: 10129578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10137502Sroot c = 0177; 10147502Sroot break; 10157502Sroot 10167502Sroot case RETURN: 10177502Sroot ctype = (tp->t_flags >> 12) & 03; 10189578Ssam if (ctype == 1) /* tn 300 */ 101913821Ssam c = mstohz(83); 10209578Ssam else if (ctype == 2) /* ti 700 */ 102113821Ssam c = mstohz(166); 10229578Ssam else if (ctype == 3) { /* concept 100 */ 10237502Sroot int i; 10249578Ssam 10257502Sroot if ((i = *colp) >= 0) 10269578Ssam for (; i < 9; i++) 10277502Sroot (void) putc(0177, &tp->t_outq); 10287502Sroot } 10297502Sroot *colp = 0; 10307502Sroot } 10319578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10327502Sroot (void) putc(c|0200, &tp->t_outq); 10337502Sroot return (-1); 10347502Sroot } 103513821Ssam #undef mstohz 10367502Sroot 10377502Sroot /* 10387502Sroot * Called from device's read routine after it has 10397502Sroot * calculated the tty-structure given as argument. 10407502Sroot */ 10417722Swnj ttread(tp, uio) 10427625Ssam register struct tty *tp; 10437722Swnj struct uio *uio; 10447502Sroot { 10457502Sroot register struct clist *qp; 10469578Ssam register c, t_flags; 10479859Ssam int s, first, error = 0; 10487502Sroot 10497502Sroot if ((tp->t_state&TS_CARR_ON)==0) 10508520Sroot return (EIO); 10517502Sroot loop: 10529578Ssam /* 10539578Ssam * Take any pending input first. 10549578Ssam */ 105517545Skarels s = spltty(); 10569578Ssam if (tp->t_flags&PENDIN) 10577502Sroot ttypend(tp); 10589859Ssam splx(s); 10599578Ssam 10609578Ssam /* 10619578Ssam * Hang process if it's in the background. 10629578Ssam */ 106315141Skarels #define bit(a) (1<<(a-1)) 10647502Sroot while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 106515141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 106615141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10677502Sroot /* 10687502Sroot (u.u_procp->p_flag&SDETACH) || 10697502Sroot */ 10707502Sroot u.u_procp->p_flag&SVFORK) 10718520Sroot return (EIO); 10727502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10737502Sroot sleep((caddr_t)&lbolt, TTIPRI); 10747502Sroot } 10759578Ssam t_flags = tp->t_flags; 107615141Skarels #undef bit 10779578Ssam 10789578Ssam /* 10799578Ssam * In raw mode take characters directly from the 10809578Ssam * raw queue w/o processing. Interlock against 10819578Ssam * device interrupts when interrogating rawq. 10829578Ssam */ 10839578Ssam if (t_flags&RAW) { 108417545Skarels s = spltty(); 10857502Sroot if (tp->t_rawq.c_cc <= 0) { 10869578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10877502Sroot (tp->t_state&TS_NBIO)) { 10889859Ssam splx(s); 108915094Skarels return (EWOULDBLOCK); 10907502Sroot } 10917502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 10929859Ssam splx(s); 10937502Sroot goto loop; 10947502Sroot } 10959859Ssam splx(s); 109614938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 109714938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 10989859Ssam goto checktandem; 10999578Ssam } 11009578Ssam 11019578Ssam /* 11029578Ssam * In cbreak mode use the rawq, otherwise 11039578Ssam * take characters from the canonicalized q. 11049578Ssam */ 11059578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11069578Ssam 11079578Ssam /* 11089578Ssam * No input, sleep on rawq awaiting hardware 11099578Ssam * receipt and notification. 11109578Ssam */ 111117545Skarels s = spltty(); 11129578Ssam if (qp->c_cc <= 0) { 11139578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11149578Ssam (tp->t_state&TS_NBIO)) { 11159859Ssam splx(s); 11169578Ssam return (EWOULDBLOCK); 11177502Sroot } 11189578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11199859Ssam splx(s); 11209578Ssam goto loop; 11219578Ssam } 11229859Ssam splx(s); 11239578Ssam 11249578Ssam /* 11259578Ssam * Input present, perform input mapping 11269578Ssam * and processing (we're not in raw mode). 11279578Ssam */ 11289578Ssam first = 1; 11299578Ssam while ((c = getc(qp)) >= 0) { 11309578Ssam if (t_flags&CRMOD && c == '\r') 11319578Ssam c = '\n'; 11329578Ssam /* 11339578Ssam * Hack lower case simulation on 11349578Ssam * upper case only terminals. 11359578Ssam */ 11369578Ssam if (t_flags&LCASE && c <= 0177) 11379578Ssam if (tp->t_state&TS_BKSL) { 11389578Ssam if (maptab[c]) 11399578Ssam c = maptab[c]; 11409578Ssam tp->t_state &= ~TS_BKSL; 11419578Ssam } else if (c >= 'A' && c <= 'Z') 11429578Ssam c += 'a' - 'A'; 11439578Ssam else if (c == '\\') { 11449578Ssam tp->t_state |= TS_BKSL; 11459578Ssam continue; 11467502Sroot } 11479578Ssam /* 11489578Ssam * Check for delayed suspend character. 11499578Ssam */ 11509578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11519578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11529578Ssam if (first) { 11539578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11549578Ssam goto loop; 11559578Ssam } 11569578Ssam break; 11577502Sroot } 11589578Ssam /* 11599578Ssam * Interpret EOF only in cooked mode. 11609578Ssam */ 11619578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11629578Ssam break; 11639578Ssam /* 11649578Ssam * Give user character. 11659578Ssam */ 116614938Smckusick error = ureadc(c & 0177, uio); 11679578Ssam if (error) 11689578Ssam break; 116914938Smckusick if (uio->uio_resid == 0) 11709578Ssam break; 11719578Ssam /* 11729578Ssam * In cooked mode check for a "break character" 11739578Ssam * marking the end of a "line of input". 11749578Ssam */ 11759578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11769578Ssam break; 11779578Ssam first = 0; 11787502Sroot } 11799578Ssam tp->t_state &= ~TS_BKSL; 11809578Ssam 11819859Ssam checktandem: 11829578Ssam /* 11839578Ssam * Look to unblock output now that (presumably) 11849578Ssam * the input queue has gone down. 11859578Ssam */ 11869859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11879578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11887502Sroot tp->t_state &= ~TS_TBLOCK; 11897502Sroot ttstart(tp); 11907502Sroot } 11918520Sroot return (error); 11927502Sroot } 11937502Sroot 11947502Sroot /* 11957502Sroot * Called from the device's write routine after it has 11967502Sroot * calculated the tty-structure given as argument. 11977502Sroot */ 11987822Sroot ttwrite(tp, uio) 11997625Ssam register struct tty *tp; 12009578Ssam register struct uio *uio; 12017502Sroot { 12027502Sroot register char *cp; 12039578Ssam register int cc, ce, c; 12049578Ssam int i, hiwat, cnt, error, s; 12057502Sroot char obuf[OBUFSIZ]; 12067502Sroot 12079578Ssam if ((tp->t_state&TS_CARR_ON) == 0) 12088520Sroot return (EIO); 12099578Ssam hiwat = TTHIWAT(tp); 12109578Ssam cnt = uio->uio_resid; 12119578Ssam error = 0; 12127502Sroot loop: 12139578Ssam /* 12149578Ssam * Hang the process if it's in the background. 12159578Ssam */ 121615141Skarels #define bit(a) (1<<(a-1)) 12177502Sroot while (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12189578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 121915141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 122015141Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU)) 12217502Sroot /* 12227502Sroot && 12237502Sroot (u.u_procp->p_flag&SDETACH)==0) { 12247502Sroot */ 12257502Sroot ) { 12267502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12277502Sroot sleep((caddr_t)&lbolt, TTIPRI); 12287502Sroot } 122915141Skarels #undef bit 12309578Ssam 12319578Ssam /* 12329578Ssam * Process the user's data in at most OBUFSIZ 12339578Ssam * chunks. Perform lower case simulation and 12349578Ssam * similar hacks. Keep track of high water 12359578Ssam * mark, sleep on overflow awaiting device aid 12369578Ssam * in acquiring new space. 12379578Ssam */ 12387822Sroot while (uio->uio_resid > 0) { 12399578Ssam /* 12409578Ssam * Grab a hunk of data from the user. 12419578Ssam */ 12427822Sroot cc = uio->uio_iov->iov_len; 12437822Sroot if (cc == 0) { 12447822Sroot uio->uio_iovcnt--; 12457822Sroot uio->uio_iov++; 12467822Sroot if (uio->uio_iovcnt < 0) 12477822Sroot panic("ttwrite"); 12487822Sroot continue; 12497822Sroot } 12507822Sroot if (cc > OBUFSIZ) 12517822Sroot cc = OBUFSIZ; 12527502Sroot cp = obuf; 125312752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12548520Sroot if (error) 12557502Sroot break; 12567502Sroot if (tp->t_outq.c_cc > hiwat) 12577502Sroot goto ovhiwat; 12589578Ssam if (tp->t_flags&FLUSHO) 12597502Sroot continue; 12609578Ssam /* 12619578Ssam * If we're mapping lower case or kludging tildes, 12629578Ssam * then we've got to look at each character, so 12639578Ssam * just feed the stuff to ttyoutput... 12649578Ssam */ 12659578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12669578Ssam while (cc > 0) { 12677502Sroot c = *cp++; 12687502Sroot tp->t_rocount = 0; 12697625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12707502Sroot /* out of clists, wait a bit */ 12717502Sroot ttstart(tp); 12727502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12737502Sroot tp->t_rocount = 0; 12747502Sroot } 12757502Sroot --cc; 12767502Sroot if (tp->t_outq.c_cc > hiwat) 12777502Sroot goto ovhiwat; 12787502Sroot } 12797502Sroot continue; 12807502Sroot } 12819578Ssam /* 12829578Ssam * If nothing fancy need be done, grab those characters we 12839578Ssam * can handle without any of ttyoutput's processing and 12849578Ssam * just transfer them to the output q. For those chars 12859578Ssam * which require special processing (as indicated by the 12869578Ssam * bits in partab), call ttyoutput. After processing 12879578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12889578Ssam * immediately. 12899578Ssam */ 12909578Ssam while (cc > 0) { 12919578Ssam if (tp->t_flags & (RAW|LITOUT)) 12927502Sroot ce = cc; 12937502Sroot else { 129412752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 129512752Ssam (caddr_t)partab, 077); 12969578Ssam /* 12979578Ssam * If ce is zero, then we're processing 12989578Ssam * a special character through ttyoutput. 12999578Ssam */ 13009578Ssam if (ce == 0) { 13017502Sroot tp->t_rocount = 0; 13027502Sroot if (ttyoutput(*cp, tp) >= 0) { 13039578Ssam /* no c-lists, wait a bit */ 13047502Sroot ttstart(tp); 13057502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13067502Sroot continue; 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); 13327502Sroot } 13339578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13347502Sroot goto ovhiwat; 13357502Sroot } 13367502Sroot } 13377502Sroot ttstart(tp); 13388520Sroot return (error); 13397502Sroot 13407502Sroot ovhiwat: 134117545Skarels s = spltty(); 13429578Ssam if (cc != 0) { 13439578Ssam uio->uio_iov->iov_base -= cc; 13449578Ssam uio->uio_iov->iov_len += cc; 13459578Ssam uio->uio_resid += cc; 13469578Ssam uio->uio_offset -= cc; 13479578Ssam } 13489578Ssam /* 13499578Ssam * This can only occur if FLUSHO 13509578Ssam * is also set in t_flags. 13519578Ssam */ 13527502Sroot if (tp->t_outq.c_cc <= hiwat) { 13539578Ssam splx(s); 13547502Sroot goto loop; 13557502Sroot } 13567502Sroot ttstart(tp); 13579578Ssam if (tp->t_state&TS_NBIO) { 135817545Skarels splx(s); 13597822Sroot if (uio->uio_resid == cnt) 13608520Sroot return (EWOULDBLOCK); 13618520Sroot return (0); 13627502Sroot } 13637502Sroot tp->t_state |= TS_ASLEEP; 13647502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13659578Ssam splx(s); 13667502Sroot goto loop; 13677502Sroot } 13687502Sroot 13697502Sroot /* 13707502Sroot * Rubout one character from the rawq of tp 13717502Sroot * as cleanly as possible. 13727502Sroot */ 13737502Sroot ttyrub(c, tp) 13747625Ssam register c; 13757625Ssam register struct tty *tp; 13767502Sroot { 13777502Sroot register char *cp; 13787502Sroot register int savecol; 13797502Sroot int s; 13807502Sroot char *nextc(); 13817502Sroot 13829578Ssam if ((tp->t_flags&ECHO) == 0) 13837502Sroot return; 13849578Ssam tp->t_flags &= ~FLUSHO; 13857502Sroot c &= 0377; 13869578Ssam if (tp->t_flags&CRTBS) { 13877502Sroot if (tp->t_rocount == 0) { 13887502Sroot /* 13897502Sroot * Screwed by ttwrite; retype 13907502Sroot */ 13917502Sroot ttyretype(tp); 13927502Sroot return; 13937502Sroot } 13949578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 13957502Sroot ttyrubo(tp, 2); 13969578Ssam else switch (partab[c&=0177]&0177) { 13977502Sroot 13987502Sroot case ORDINARY: 13997502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14007502Sroot ttyrubo(tp, 2); 14017502Sroot else 14027502Sroot ttyrubo(tp, 1); 14037502Sroot break; 14047502Sroot 14057502Sroot case VTAB: 14067502Sroot case BACKSPACE: 14077502Sroot case CONTROL: 14087502Sroot case RETURN: 14099578Ssam if (tp->t_flags&CTLECH) 14107502Sroot ttyrubo(tp, 2); 14117502Sroot break; 14127502Sroot 14137502Sroot case TAB: 14147502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14157502Sroot ttyretype(tp); 14167502Sroot return; 14177502Sroot } 141817545Skarels s = spltty(); 14197502Sroot savecol = tp->t_col; 14209578Ssam tp->t_state |= TS_CNTTB; 14219578Ssam tp->t_flags |= FLUSHO; 14227502Sroot tp->t_col = tp->t_rocol; 14239578Ssam cp = tp->t_rawq.c_cf; 14249578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14257502Sroot ttyecho(*cp, tp); 14269578Ssam tp->t_flags &= ~FLUSHO; 14279578Ssam tp->t_state &= ~TS_CNTTB; 14287502Sroot splx(s); 14297502Sroot /* 14307502Sroot * savecol will now be length of the tab 14317502Sroot */ 14327502Sroot savecol -= tp->t_col; 14337502Sroot tp->t_col += savecol; 14347502Sroot if (savecol > 8) 14357502Sroot savecol = 8; /* overflow screw */ 14367502Sroot while (--savecol >= 0) 14377502Sroot (void) ttyoutput('\b', tp); 14387502Sroot break; 14397502Sroot 14407502Sroot default: 14417502Sroot panic("ttyrub"); 14427502Sroot } 14439578Ssam } else if (tp->t_flags&PRTERA) { 14449578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14457502Sroot (void) ttyoutput('\\', tp); 14469578Ssam tp->t_state |= TS_ERASE; 14477502Sroot } 14487502Sroot ttyecho(c, tp); 14497502Sroot } else 14507502Sroot ttyecho(tp->t_erase, tp); 14517502Sroot tp->t_rocount--; 14527502Sroot } 14537502Sroot 14547502Sroot /* 14557502Sroot * Crt back over cnt chars perhaps 14567502Sroot * erasing them. 14577502Sroot */ 14587502Sroot ttyrubo(tp, cnt) 14597625Ssam register struct tty *tp; 14607625Ssam int cnt; 14617502Sroot { 14629578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14637502Sroot 14647502Sroot while (--cnt >= 0) 14659578Ssam ttyout(rubostring, tp); 14667502Sroot } 14677502Sroot 14687502Sroot /* 14697502Sroot * Reprint the rawq line. 14707502Sroot * We assume c_cc has already been checked. 14717502Sroot */ 14727502Sroot ttyretype(tp) 14737625Ssam register struct tty *tp; 14747502Sroot { 14757502Sroot register char *cp; 14767502Sroot char *nextc(); 14777502Sroot int s; 14787502Sroot 14799578Ssam if (tp->t_rprntc != 0377) 14809578Ssam ttyecho(tp->t_rprntc, tp); 14817502Sroot (void) ttyoutput('\n', tp); 148217545Skarels s = spltty(); 14837502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14847502Sroot ttyecho(*cp, tp); 14857502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14867502Sroot ttyecho(*cp, tp); 14879578Ssam tp->t_state &= ~TS_ERASE; 14887502Sroot splx(s); 14897502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14907502Sroot tp->t_rocol = 0; 14917502Sroot } 14927502Sroot 14937502Sroot /* 14947502Sroot * Echo a typed character to the terminal 14957502Sroot */ 14967502Sroot ttyecho(c, tp) 14977625Ssam register c; 14987625Ssam register struct tty *tp; 14997502Sroot { 15007502Sroot 15019578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15029578Ssam tp->t_flags &= ~FLUSHO; 15037502Sroot if ((tp->t_flags&ECHO) == 0) 15047502Sroot return; 15057502Sroot c &= 0377; 15067502Sroot if (tp->t_flags&RAW) { 15077502Sroot (void) ttyoutput(c, tp); 15087502Sroot return; 15097502Sroot } 15107502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15117502Sroot c = '\n'; 15129578Ssam if (tp->t_flags&CTLECH) { 15137502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15147502Sroot (void) ttyoutput('^', tp); 15157502Sroot c &= 0177; 15167502Sroot if (c == 0177) 15177502Sroot c = '?'; 15187502Sroot else if (tp->t_flags&LCASE) 15197502Sroot c += 'a' - 1; 15207502Sroot else 15217502Sroot c += 'A' - 1; 15227502Sroot } 15237502Sroot } 15247502Sroot if ((tp->t_flags&LCASE) && (c >= 'A' && c <= 'Z')) 15257502Sroot c += 'a' - 'A'; 15269578Ssam (void) ttyoutput(c&0177, tp); 15277502Sroot } 15287502Sroot 15297502Sroot /* 15307502Sroot * Is c a break char for tp? 15317502Sroot */ 15327502Sroot ttbreakc(c, tp) 15337625Ssam register c; 15347625Ssam register struct tty *tp; 15357502Sroot { 15369578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15377502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15387502Sroot } 15397502Sroot 15407502Sroot /* 15417502Sroot * send string cp to tp 15427502Sroot */ 15437502Sroot ttyout(cp, tp) 15447625Ssam register char *cp; 15457625Ssam register struct tty *tp; 15467502Sroot { 15477502Sroot register char c; 15487502Sroot 15497502Sroot while (c = *cp++) 15507502Sroot (void) ttyoutput(c, tp); 15517502Sroot } 15527502Sroot 15537502Sroot ttwakeup(tp) 15547502Sroot struct tty *tp; 15557502Sroot { 15567502Sroot 15577502Sroot if (tp->t_rsel) { 15587502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15597502Sroot tp->t_state &= ~TS_RCOLL; 15607502Sroot tp->t_rsel = 0; 15617502Sroot } 156212752Ssam if (tp->t_state & TS_ASYNC) 156312752Ssam gsignal(tp->t_pgrp, SIGIO); 15647502Sroot wakeup((caddr_t)&tp->t_rawq); 15657502Sroot } 15667502Sroot 156713533Ssam #if !defined(vax) 15689578Ssam scanc(size, cp, table, mask) 15699578Ssam register int size; 15709578Ssam register char *cp, table[]; 15719578Ssam register int mask; 15727502Sroot { 15739578Ssam register int i = 0; 15747502Sroot 15759578Ssam while ((table[*(u_char *)(cp + i)]&mask) == 0 && i < size) 15769578Ssam i++; 157715100Skarels return (size - i); 15787502Sroot } 15799578Ssam #endif 1580