123387Smckusick /* 223387Smckusick * Copyright (c) 1982 Regents of the University of California. 323387Smckusick * All rights reserved. The Berkeley software License Agreement 423387Smckusick * specifies the terms and conditions for redistribution. 523387Smckusick * 6*24273Slepreau * @(#)tty.c 6.20 (Berkeley) 08/13/85 723387Smckusick */ 839Sbill 99760Ssam #include "../machine/reg.h" 109760Ssam 1117095Sbloom #include "param.h" 1217095Sbloom #include "systm.h" 1317095Sbloom #include "dir.h" 1417095Sbloom #include "user.h" 1517095Sbloom #include "ioctl.h" 1617095Sbloom #include "tty.h" 1717095Sbloom #include "proc.h" 1817095Sbloom #include "inode.h" 1917095Sbloom #include "file.h" 2017095Sbloom #include "conf.h" 2117095Sbloom #include "buf.h" 2217095Sbloom #include "dk.h" 2317095Sbloom #include "uio.h" 2417095Sbloom #include "kernel.h" 2539Sbill 267436Skre /* 277436Skre * Table giving parity for characters and indicating 287436Skre * character classes to tty driver. In particular, 297436Skre * if the low 6 bits are 0, then the character needs 307436Skre * no special processing on output. 317436Skre */ 3239Sbill 337436Skre char partab[] = { 347436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 357436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 367436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 377436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 387436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 397436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 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,0200, 447436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 457436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 467436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 477436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 487436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 497436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 507436Skre 517436Skre /* 527436Skre * 7 bit ascii ends with the last character above, 537436Skre * but we contine through all 256 codes for the sake 547436Skre * of the tty output routines which use special vax 557436Skre * instructions which need a 256 character trt table. 567436Skre */ 577436Skre 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 0007,0007,0007,0007,0007,0007,0007,0007, 697436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 707436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 717436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 727436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 737436Skre 0007,0007,0007,0007,0007,0007,0007,0007 747436Skre }; 757436Skre 76146Sbill /* 7739Sbill * Input mapping table-- if an entry is non-zero, when the 7839Sbill * corresponding character is typed preceded by "\" the escape 7939Sbill * sequence is replaced by the table value. Mostly used for 8039Sbill * upper-case only terminals. 8139Sbill */ 8239Sbill char maptab[] ={ 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,'`', 8839Sbill '{','}',000,000,000,000,000,000, 8939Sbill 000,000,000,000,000,000,000,000, 9039Sbill 000,000,000,000,000,000,000,000, 9139Sbill 000,000,000,000,000,000,000,000, 9239Sbill 000,000,000,000,000,000,000,000, 9339Sbill 000,000,000,000,000,000,000,000, 9439Sbill 000,000,000,000,000,000,'~',000, 9539Sbill 000,'A','B','C','D','E','F','G', 9639Sbill 'H','I','J','K','L','M','N','O', 9739Sbill 'P','Q','R','S','T','U','V','W', 9839Sbill 'X','Y','Z',000,000,000,000,000, 9939Sbill }; 10039Sbill 101925Sbill short tthiwat[16] = 1028954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 103925Sbill short ttlowat[16] = 104925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 105925Sbill 1069578Ssam struct ttychars ttydefaults = { 1079578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1089578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1099578Ssam }; 11039Sbill 11139Sbill ttychars(tp) 1129578Ssam struct tty *tp; 11339Sbill { 114174Sbill 1159578Ssam tp->t_chars = ttydefaults; 11639Sbill } 11739Sbill 11839Sbill /* 119903Sbill * Wait for output to drain, then flush input waiting. 12039Sbill */ 12112752Ssam ttywflush(tp) 1225408Swnj register struct tty *tp; 12339Sbill { 12439Sbill 12512752Ssam ttywait(tp); 12612752Ssam ttyflush(tp, FREAD); 12712752Ssam } 12812752Ssam 12912752Ssam ttywait(tp) 13012752Ssam register struct tty *tp; 13112752Ssam { 13217545Skarels register int s = spltty(); 13312752Ssam 13413809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 13513809Ssam tp->t_state&TS_CARR_ON && tp->t_oproc) { /* kludge for pty */ 136903Sbill (*tp->t_oproc)(tp); 1375408Swnj tp->t_state |= TS_ASLEEP; 138903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 139903Sbill } 1409859Ssam splx(s); 14139Sbill } 14239Sbill 14339Sbill /* 1449578Ssam * Flush all TTY queues 14539Sbill */ 14612752Ssam ttyflush(tp, rw) 1477625Ssam register struct tty *tp; 14839Sbill { 149903Sbill register s; 150903Sbill 15117545Skarels s = spltty(); 152903Sbill if (rw & FREAD) { 153903Sbill while (getc(&tp->t_canq) >= 0) 154903Sbill ; 155903Sbill wakeup((caddr_t)&tp->t_rawq); 156903Sbill } 157903Sbill if (rw & FWRITE) { 158903Sbill wakeup((caddr_t)&tp->t_outq); 1595408Swnj tp->t_state &= ~TS_TTSTOP; 1605426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 161903Sbill while (getc(&tp->t_outq) >= 0) 162903Sbill ; 163903Sbill } 164903Sbill if (rw & FREAD) { 165903Sbill while (getc(&tp->t_rawq) >= 0) 166903Sbill ; 1679578Ssam tp->t_rocount = 0; 168903Sbill tp->t_rocol = 0; 1699578Ssam tp->t_state &= ~TS_LOCAL; 170903Sbill } 171903Sbill splx(s); 17239Sbill } 17339Sbill 174903Sbill /* 175903Sbill * Send stop character on input overflow. 176903Sbill */ 177903Sbill ttyblock(tp) 1787625Ssam register struct tty *tp; 17939Sbill { 180903Sbill register x; 1819578Ssam 182903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 183903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 18412752Ssam ttyflush(tp, FREAD|FWRITE); 1855408Swnj tp->t_state &= ~TS_TBLOCK; 186903Sbill } 18715118Skarels /* 18815118Skarels * Block further input iff: 18915118Skarels * Current input > threshold AND input is available to user program 19015118Skarels */ 19116055Skarels if (x >= TTYHOG/2 && 19216055Skarels ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) { 19315118Skarels if (putc(tp->t_stopc, &tp->t_outq)==0) { 19415118Skarels tp->t_state |= TS_TBLOCK; 19515118Skarels ttstart(tp); 19615118Skarels } 197903Sbill } 19839Sbill } 19939Sbill 20039Sbill /* 201903Sbill * Restart typewriter output following a delay 202903Sbill * timeout. 203903Sbill * The name of the routine is passed to the timeout 204903Sbill * subroutine and it is called during a clock interrupt. 205121Sbill */ 206903Sbill ttrstrt(tp) 2077625Ssam register struct tty *tp; 208121Sbill { 209121Sbill 2109578Ssam if (tp == 0) 2119578Ssam panic("ttrstrt"); 2125408Swnj tp->t_state &= ~TS_TIMEOUT; 213903Sbill ttstart(tp); 214121Sbill } 215121Sbill 216121Sbill /* 217903Sbill * Start output on the typewriter. It is used from the top half 218903Sbill * after some characters have been put on the output queue, 219903Sbill * from the interrupt routine to transmit the next 220903Sbill * character, and after a timeout has finished. 22139Sbill */ 222903Sbill ttstart(tp) 2237625Ssam register struct tty *tp; 22439Sbill { 225903Sbill register s; 22639Sbill 22717545Skarels s = spltty(); 2289578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2295622Swnj tp->t_oproc) /* kludge for pty */ 230903Sbill (*tp->t_oproc)(tp); 231903Sbill splx(s); 23239Sbill } 23339Sbill 23439Sbill /* 235903Sbill * Common code for tty ioctls. 23639Sbill */ 2371780Sbill /*ARGSUSED*/ 2387625Ssam ttioctl(tp, com, data, flag) 2397625Ssam register struct tty *tp; 2407625Ssam caddr_t data; 24139Sbill { 2428520Sroot int dev = tp->t_dev; 24339Sbill extern int nldisp; 2448556Sroot int s; 24512752Ssam register int newflags; 24639Sbill 247903Sbill /* 248903Sbill * If the ioctl involves modification, 24917545Skarels * hang if in the background. 250903Sbill */ 2517625Ssam switch (com) { 25239Sbill 253915Sbill case TIOCSETD: 254915Sbill case TIOCSETP: 255915Sbill case TIOCSETN: 256903Sbill case TIOCFLUSH: 257903Sbill case TIOCSETC: 258903Sbill case TIOCSLTC: 259903Sbill case TIOCSPGRP: 260903Sbill case TIOCLBIS: 261903Sbill case TIOCLBIC: 262903Sbill case TIOCLSET: 2639325Ssam case TIOCSTI: 26417598Sbloom case TIOCSWINSZ: 26515078Skarels #define bit(a) (1<<(a-1)) 266903Sbill while (tp->t_line == NTTYDISC && 267903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 268903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 26915078Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 27015078Skarels !(u.u_procp->p_sigmask & bit(SIGTTOU))) { 271903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 272903Sbill sleep((caddr_t)&lbolt, TTOPRI); 273903Sbill } 274903Sbill break; 275903Sbill } 27615078Skarels #undef bit 277903Sbill 2789578Ssam /* 2799578Ssam * Process the ioctl. 2809578Ssam */ 2817625Ssam switch (com) { 282903Sbill 2838556Sroot /* get discipline number */ 28439Sbill case TIOCGETD: 2857625Ssam *(int *)data = tp->t_line; 28639Sbill break; 28739Sbill 2888556Sroot /* set line discipline */ 2897625Ssam case TIOCSETD: { 2907625Ssam register int t = *(int *)data; 2919578Ssam int error = 0; 2927625Ssam 29315078Skarels if ((unsigned) t >= nldisp) 29410851Ssam return (ENXIO); 29517545Skarels s = spltty(); 29639Sbill if (tp->t_line) 29739Sbill (*linesw[tp->t_line].l_close)(tp); 29839Sbill if (t) 2998556Sroot error = (*linesw[t].l_open)(dev, tp); 30010851Ssam if (error) { 30110851Ssam if (tp->t_line) 30210851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 30310851Ssam splx(s); 3048556Sroot return (error); 30510851Ssam } 3068556Sroot tp->t_line = t; 30718650Sbloom splx(s); 30839Sbill break; 3097625Ssam } 31039Sbill 3118556Sroot /* prevent more opens on channel */ 3125614Swnj case TIOCEXCL: 3135614Swnj tp->t_state |= TS_XCLUDE; 3145614Swnj break; 3155614Swnj 3165614Swnj case TIOCNXCL: 3175614Swnj tp->t_state &= ~TS_XCLUDE; 3185614Swnj break; 3195614Swnj 3208556Sroot /* hang up line on last close */ 32139Sbill case TIOCHPCL: 3225408Swnj tp->t_state |= TS_HUPCLS; 32339Sbill break; 32439Sbill 3253942Sbugs case TIOCFLUSH: { 3267625Ssam register int flags = *(int *)data; 3277625Ssam 3287625Ssam if (flags == 0) 3293942Sbugs flags = FREAD|FWRITE; 3307625Ssam else 3317625Ssam flags &= FREAD|FWRITE; 33212752Ssam ttyflush(tp, flags); 33339Sbill break; 3343944Sbugs } 33539Sbill 3368556Sroot /* return number of characters immediately available */ 3377625Ssam case FIONREAD: 3387625Ssam *(off_t *)data = ttnread(tp); 339174Sbill break; 340174Sbill 34113077Ssam case TIOCOUTQ: 34213077Ssam *(int *)data = tp->t_outq.c_cc; 34313077Ssam break; 34413077Ssam 3458589Sroot case TIOCSTOP: 34617545Skarels s = spltty(); 3479578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3485573Swnj tp->t_state |= TS_TTSTOP; 3495573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3505573Swnj } 3517625Ssam splx(s); 3525573Swnj break; 3535573Swnj 3548589Sroot case TIOCSTART: 35517545Skarels s = spltty(); 3569578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3575573Swnj tp->t_state &= ~TS_TTSTOP; 3589578Ssam tp->t_flags &= ~FLUSHO; 3595573Swnj ttstart(tp); 3605573Swnj } 3617625Ssam splx(s); 3625573Swnj break; 3635573Swnj 3649325Ssam /* 3659325Ssam * Simulate typing of a character at the terminal. 3669325Ssam */ 3679325Ssam case TIOCSTI: 36817183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36917183Smckusick return (EPERM); 3709325Ssam if (u.u_uid && u.u_ttyp != tp) 3719325Ssam return (EACCES); 3729578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3739325Ssam break; 3749325Ssam 37512752Ssam case TIOCSETP: 37612752Ssam case TIOCSETN: { 37712752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37812752Ssam 37912752Ssam tp->t_erase = sg->sg_erase; 38012752Ssam tp->t_kill = sg->sg_kill; 38112752Ssam tp->t_ispeed = sg->sg_ispeed; 38212752Ssam tp->t_ospeed = sg->sg_ospeed; 38312752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 38417545Skarels s = spltty(); 38512752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38612752Ssam ttywait(tp); 38712752Ssam ttyflush(tp, FREAD); 38812752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38912752Ssam if (newflags&CBREAK) { 39012752Ssam struct clist tq; 39112752Ssam 39212752Ssam catq(&tp->t_rawq, &tp->t_canq); 39312752Ssam tq = tp->t_rawq; 39412752Ssam tp->t_rawq = tp->t_canq; 39512752Ssam tp->t_canq = tq; 39612752Ssam } else { 39712752Ssam tp->t_flags |= PENDIN; 39813801Ssam newflags |= PENDIN; 39912752Ssam ttwakeup(tp); 40012752Ssam } 40112752Ssam } 40212752Ssam tp->t_flags = newflags; 40312752Ssam if (tp->t_flags&RAW) { 40412752Ssam tp->t_state &= ~TS_TTSTOP; 40512752Ssam ttstart(tp); 40612752Ssam } 40712752Ssam splx(s); 40812752Ssam break; 40912752Ssam } 41012752Ssam 41112752Ssam /* send current parameters to user */ 41212752Ssam case TIOCGETP: { 41312752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 41412752Ssam 41512752Ssam sg->sg_ispeed = tp->t_ispeed; 41612752Ssam sg->sg_ospeed = tp->t_ospeed; 41712752Ssam sg->sg_erase = tp->t_erase; 41812752Ssam sg->sg_kill = tp->t_kill; 41912752Ssam sg->sg_flags = tp->t_flags; 42012752Ssam break; 42112752Ssam } 42212752Ssam 42312752Ssam case FIONBIO: 42412752Ssam if (*(int *)data) 42512752Ssam tp->t_state |= TS_NBIO; 42612752Ssam else 42712752Ssam tp->t_state &= ~TS_NBIO; 42812752Ssam break; 42912752Ssam 43012752Ssam case FIOASYNC: 43112752Ssam if (*(int *)data) 43212752Ssam tp->t_state |= TS_ASYNC; 43312752Ssam else 43412752Ssam tp->t_state &= ~TS_ASYNC; 43512752Ssam break; 43612752Ssam 43713077Ssam case TIOCGETC: 43813077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43913077Ssam break; 44013077Ssam 44113077Ssam case TIOCSETC: 44213077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 44313077Ssam break; 44413077Ssam 44512752Ssam /* set/get local special characters */ 44612752Ssam case TIOCSLTC: 44712752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44812752Ssam break; 44912752Ssam 45012752Ssam case TIOCGLTC: 45112752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 45212752Ssam break; 45312752Ssam 45412752Ssam /* 45512752Ssam * Modify local mode word. 45612752Ssam */ 45712752Ssam case TIOCLBIS: 45812752Ssam tp->t_flags |= *(int *)data << 16; 45912752Ssam break; 46012752Ssam 46112752Ssam case TIOCLBIC: 46212752Ssam tp->t_flags &= ~(*(int *)data << 16); 46312752Ssam break; 46412752Ssam 46512752Ssam case TIOCLSET: 46612752Ssam tp->t_flags &= 0xffff; 46712752Ssam tp->t_flags |= *(int *)data << 16; 46812752Ssam break; 46912752Ssam 47012752Ssam case TIOCLGET: 47115720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 47212752Ssam break; 47312752Ssam 47417545Skarels /* 47517932Skarels * Allow SPGRP only if tty is open for reading. 47617598Sbloom * Quick check: if we can find a process in the new pgrp, 47717598Sbloom * this user must own that process. 47817598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47917545Skarels */ 48018650Sbloom case TIOCSPGRP: { 48117545Skarels struct proc *p; 48217545Skarels int pgrp = *(int *)data; 48317545Skarels 48417545Skarels if (u.u_uid && (flag & FREAD) == 0) 48517545Skarels return (EPERM); 48617598Sbloom p = pfind(pgrp); 48717598Sbloom if (p && p->p_pgrp == pgrp && 48817598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48917598Sbloom return (EPERM); 49017545Skarels tp->t_pgrp = pgrp; 49112752Ssam break; 49218650Sbloom } 49312752Ssam 49412752Ssam case TIOCGPGRP: 49512752Ssam *(int *)data = tp->t_pgrp; 49612752Ssam break; 49712752Ssam 49817598Sbloom case TIOCSWINSZ: 49918650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 50018650Sbloom sizeof (struct winsize))) { 50117598Sbloom tp->t_winsize = *(struct winsize *)data; 50217598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 50317598Sbloom } 50417598Sbloom break; 50517598Sbloom 50617598Sbloom case TIOCGWINSZ: 50717598Sbloom *(struct winsize *)data = tp->t_winsize; 50817598Sbloom break; 50917598Sbloom 51039Sbill default: 5118556Sroot return (-1); 51239Sbill } 5138556Sroot return (0); 51439Sbill } 5154484Swnj 5164484Swnj ttnread(tp) 5174484Swnj struct tty *tp; 5184484Swnj { 5194484Swnj int nread = 0; 5204484Swnj 5219578Ssam if (tp->t_flags & PENDIN) 5224484Swnj ttypend(tp); 5234484Swnj nread = tp->t_canq.c_cc; 5244484Swnj if (tp->t_flags & (RAW|CBREAK)) 5254484Swnj nread += tp->t_rawq.c_cc; 5264484Swnj return (nread); 5274484Swnj } 5284484Swnj 5295408Swnj ttselect(dev, rw) 5304484Swnj dev_t dev; 5315408Swnj int rw; 5324484Swnj { 5334484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5344484Swnj int nread; 53517545Skarels int s = spltty(); 5364484Swnj 5375408Swnj switch (rw) { 5384484Swnj 5394484Swnj case FREAD: 5404484Swnj nread = ttnread(tp); 54121776Sbloom if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0)) 5425408Swnj goto win; 5434938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5445408Swnj tp->t_state |= TS_RCOLL; 5454484Swnj else 5464484Swnj tp->t_rsel = u.u_procp; 5475408Swnj break; 5484484Swnj 5495408Swnj case FWRITE: 5505408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5515408Swnj goto win; 5525408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5535408Swnj tp->t_state |= TS_WCOLL; 5545408Swnj else 5555408Swnj tp->t_wsel = u.u_procp; 5565408Swnj break; 5574484Swnj } 5585408Swnj splx(s); 5595408Swnj return (0); 5605408Swnj win: 5615408Swnj splx(s); 5625408Swnj return (1); 5634484Swnj } 5647436Skre 5657502Sroot /* 5669578Ssam * Establish a process group for distribution of 5677502Sroot * quits and interrupts from the tty. 5687502Sroot */ 5697502Sroot ttyopen(dev, tp) 5707625Ssam dev_t dev; 5717625Ssam register struct tty *tp; 5727502Sroot { 5737502Sroot register struct proc *pp; 5747502Sroot 5757502Sroot pp = u.u_procp; 5767502Sroot tp->t_dev = dev; 5777625Ssam if (pp->p_pgrp == 0) { 5787502Sroot u.u_ttyp = tp; 5797502Sroot u.u_ttyd = dev; 5807502Sroot if (tp->t_pgrp == 0) 5817502Sroot tp->t_pgrp = pp->p_pid; 5827502Sroot pp->p_pgrp = tp->t_pgrp; 5837502Sroot } 5847502Sroot tp->t_state &= ~TS_WOPEN; 58517545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 58617545Skarels tp->t_state |= TS_ISOPEN; 58717598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58817545Skarels if (tp->t_line != NTTYDISC) 58917545Skarels ttywflush(tp); 59017545Skarels } 5918556Sroot return (0); 5927502Sroot } 5937502Sroot 5947502Sroot /* 5957502Sroot * clean tp on last close 5967502Sroot */ 5977502Sroot ttyclose(tp) 5987625Ssam register struct tty *tp; 5997502Sroot { 6007502Sroot 6017502Sroot if (tp->t_line) { 60212752Ssam ttywflush(tp); 6037502Sroot tp->t_line = 0; 6047502Sroot return; 6057502Sroot } 6067502Sroot tp->t_pgrp = 0; 60712752Ssam ttywflush(tp); 6087502Sroot tp->t_state = 0; 6097502Sroot } 6107502Sroot 6117502Sroot /* 6127502Sroot * reinput pending characters after state switch 61317545Skarels * call at spltty(). 6147502Sroot */ 6157502Sroot ttypend(tp) 6167625Ssam register struct tty *tp; 6177502Sroot { 6187502Sroot struct clist tq; 6197502Sroot register c; 6207502Sroot 6219578Ssam tp->t_flags &= ~PENDIN; 6229578Ssam tp->t_state |= TS_TYPEN; 6237502Sroot tq = tp->t_rawq; 6247502Sroot tp->t_rawq.c_cc = 0; 6257502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6267502Sroot while ((c = getc(&tq)) >= 0) 6277502Sroot ttyinput(c, tp); 6289578Ssam tp->t_state &= ~TS_TYPEN; 6297502Sroot } 6307502Sroot 6317502Sroot /* 6329578Ssam * Place a character on raw TTY input queue, 6339578Ssam * putting in delimiters and waking up top 6349578Ssam * half as needed. Also echo if required. 6359578Ssam * The arguments are the character and the 6369578Ssam * appropriate tty structure. 6377502Sroot */ 6387502Sroot ttyinput(c, tp) 6397625Ssam register c; 6407625Ssam register struct tty *tp; 6417502Sroot { 6429578Ssam register int t_flags = tp->t_flags; 6437502Sroot int i; 6447502Sroot 6459578Ssam /* 6469578Ssam * If input is pending take it first. 6479578Ssam */ 6489578Ssam if (t_flags&PENDIN) 6497502Sroot ttypend(tp); 6507502Sroot tk_nin++; 6517502Sroot c &= 0377; 6529578Ssam 6539578Ssam /* 6549578Ssam * In tandem mode, check high water mark. 6559578Ssam */ 6567502Sroot if (t_flags&TANDEM) 6577502Sroot ttyblock(tp); 6589578Ssam 6599578Ssam if (t_flags&RAW) { 6609578Ssam /* 6619578Ssam * Raw mode, just put character 6629578Ssam * in input q w/o interpretation. 6639578Ssam */ 6649578Ssam if (tp->t_rawq.c_cc > TTYHOG) 66512752Ssam ttyflush(tp, FREAD|FWRITE); 6669578Ssam else { 6679578Ssam if (putc(c, &tp->t_rawq) >= 0) 6689578Ssam ttwakeup(tp); 6699578Ssam ttyecho(c, tp); 6707502Sroot } 6719578Ssam goto endcase; 6729578Ssam } 6739578Ssam 6749578Ssam /* 6759578Ssam * Ignore any high bit added during 6769578Ssam * previous ttyinput processing. 6779578Ssam */ 678*24273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 6799578Ssam c &= 0177; 6809578Ssam /* 6819578Ssam * Check for literal nexting very first 6829578Ssam */ 6839578Ssam if (tp->t_state&TS_LNCH) { 6849578Ssam c |= 0200; 6859578Ssam tp->t_state &= ~TS_LNCH; 6869578Ssam } 6879578Ssam 6889578Ssam /* 6899578Ssam * Scan for special characters. This code 6909578Ssam * is really just a big case statement with 6919578Ssam * non-constant cases. The bottom of the 6929578Ssam * case statement is labeled ``endcase'', so goto 6939578Ssam * it after a case match, or similar. 6949578Ssam */ 6959578Ssam if (tp->t_line == NTTYDISC) { 6969578Ssam if (c == tp->t_lnextc) { 69721776Sbloom if (t_flags&ECHO) 6987502Sroot ttyout("^\b", tp); 6999578Ssam tp->t_state |= TS_LNCH; 7009578Ssam goto endcase; 7019578Ssam } 7029578Ssam if (c == tp->t_flushc) { 70321776Sbloom if (t_flags&FLUSHO) 7049578Ssam tp->t_flags &= ~FLUSHO; 7057502Sroot else { 70612752Ssam ttyflush(tp, FWRITE); 7077502Sroot ttyecho(c, tp); 7089578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7097502Sroot ttyretype(tp); 7109578Ssam tp->t_flags |= FLUSHO; 7117502Sroot } 7129578Ssam goto startoutput; 7139578Ssam } 7149578Ssam if (c == tp->t_suspc) { 71521776Sbloom if ((t_flags&NOFLSH) == 0) 71612752Ssam ttyflush(tp, FREAD); 7179578Ssam ttyecho(c, tp); 7189578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7199578Ssam goto endcase; 7209578Ssam } 7219578Ssam } 7229578Ssam 7239578Ssam /* 7249578Ssam * Handle start/stop characters. 7259578Ssam */ 7269578Ssam if (c == tp->t_stopc) { 7279578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7289578Ssam tp->t_state |= TS_TTSTOP; 7299578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7307502Sroot return; 7319578Ssam } 7329578Ssam if (c != tp->t_startc) 7339578Ssam return; 7349578Ssam goto endcase; 7359578Ssam } 7369578Ssam if (c == tp->t_startc) 7379578Ssam goto restartoutput; 7389578Ssam 7399578Ssam /* 7409578Ssam * Look for interrupt/quit chars. 7419578Ssam */ 7429578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 74321776Sbloom if ((t_flags&NOFLSH) == 0) 74412752Ssam ttyflush(tp, FREAD|FWRITE); 7459578Ssam ttyecho(c, tp); 7469578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7479578Ssam goto endcase; 7489578Ssam } 7499578Ssam 75023165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 75123165Sbloom if (tp->t_state&TS_BKSL) { 75223165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 75323165Sbloom if (maptab[c]) 75423165Sbloom c = maptab[c]; 75523165Sbloom c |= 0200; 75623165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 75723165Sbloom } else if (c >= 'A' && c <= 'Z') 75823165Sbloom c += 'a' - 'A'; 75923165Sbloom else if (c == '\\') 76023165Sbloom tp->t_state |= TS_BKSL; 76123165Sbloom } 76223165Sbloom 7639578Ssam /* 7649578Ssam * Cbreak mode, don't process line editing 7659578Ssam * characters; check high water mark for wakeup. 7669578Ssam */ 7679578Ssam if (t_flags&CBREAK) { 7689578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7697502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7707502Sroot tp->t_line == NTTYDISC) 7717502Sroot (void) ttyoutput(CTRL(g), tp); 7727502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7737502Sroot ttwakeup(tp); 7747502Sroot ttyecho(c, tp); 7757502Sroot } 7769578Ssam goto endcase; 7779578Ssam } 7789578Ssam 7799578Ssam /* 7809578Ssam * From here on down cooked mode character 7819578Ssam * processing takes place. 7829578Ssam */ 7839578Ssam if ((tp->t_state&TS_QUOT) && 7849578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7859578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7869578Ssam c |= 0200; 7879578Ssam } 7889578Ssam if (c == tp->t_erase) { 7899578Ssam if (tp->t_rawq.c_cc) 7909578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7919578Ssam goto endcase; 7929578Ssam } 7939578Ssam if (c == tp->t_kill) { 79421776Sbloom if (t_flags&CRTKIL && 7959578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7969578Ssam while (tp->t_rawq.c_cc) 7979578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7989578Ssam } else { 7999578Ssam ttyecho(c, tp); 8009578Ssam ttyecho('\n', tp); 8019578Ssam while (getc(&tp->t_rawq) > 0) 8029578Ssam ; 8039578Ssam tp->t_rocount = 0; 8049578Ssam } 8059578Ssam tp->t_state &= ~TS_LOCAL; 8069578Ssam goto endcase; 8079578Ssam } 8089578Ssam 8099578Ssam /* 8109578Ssam * New line discipline, 8119578Ssam * check word erase/reprint line. 8129578Ssam */ 8139578Ssam if (tp->t_line == NTTYDISC) { 8149578Ssam if (c == tp->t_werasc) { 8159578Ssam if (tp->t_rawq.c_cc == 0) 8169578Ssam goto endcase; 8179578Ssam do { 8189578Ssam c = unputc(&tp->t_rawq); 8199578Ssam if (c != ' ' && c != '\t') 8209578Ssam goto erasenb; 8219578Ssam ttyrub(c, tp); 8229578Ssam } while (tp->t_rawq.c_cc); 8239578Ssam goto endcase; 8249578Ssam erasenb: 8259578Ssam do { 8269578Ssam ttyrub(c, tp); 8279578Ssam if (tp->t_rawq.c_cc == 0) 8289578Ssam goto endcase; 8299578Ssam c = unputc(&tp->t_rawq); 8309578Ssam } while (c != ' ' && c != '\t'); 8319578Ssam (void) putc(c, &tp->t_rawq); 8329578Ssam goto endcase; 8339578Ssam } 8349578Ssam if (c == tp->t_rprntc) { 8359578Ssam ttyretype(tp); 8369578Ssam goto endcase; 8379578Ssam } 8389578Ssam } 8399578Ssam 8409578Ssam /* 8419578Ssam * Check for input buffer overflow 8429578Ssam */ 84310391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 84410391Ssam if (tp->t_line == NTTYDISC) 84510391Ssam (void) ttyoutput(CTRL(g), tp); 8469578Ssam goto endcase; 84710391Ssam } 8489578Ssam 8499578Ssam /* 8509578Ssam * Put data char in q for user and 8519578Ssam * wakeup on seeing a line delimiter. 8529578Ssam */ 8539578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8549578Ssam if (ttbreakc(c, tp)) { 8559578Ssam tp->t_rocount = 0; 8569578Ssam catq(&tp->t_rawq, &tp->t_canq); 8577502Sroot ttwakeup(tp); 8589578Ssam } else if (tp->t_rocount++ == 0) 8599578Ssam tp->t_rocol = tp->t_col; 8609578Ssam tp->t_state &= ~TS_QUOT; 8619578Ssam if (c == '\\') 8629578Ssam tp->t_state |= TS_QUOT; 8639578Ssam if (tp->t_state&TS_ERASE) { 8649578Ssam tp->t_state &= ~TS_ERASE; 8659578Ssam (void) ttyoutput('/', tp); 8669578Ssam } 8679578Ssam i = tp->t_col; 8687502Sroot ttyecho(c, tp); 86921776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 8709578Ssam i = MIN(2, tp->t_col - i); 8719578Ssam while (i > 0) { 8729578Ssam (void) ttyoutput('\b', tp); 8739578Ssam i--; 8749578Ssam } 8759578Ssam } 8767502Sroot } 8779578Ssam endcase: 8789578Ssam /* 8799578Ssam * If DEC-style start/stop is enabled don't restart 8809578Ssam * output until seeing the start character. 8819578Ssam */ 88221776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8839578Ssam tp->t_startc != tp->t_stopc) 8847502Sroot return; 8859578Ssam restartoutput: 8867502Sroot tp->t_state &= ~TS_TTSTOP; 8879578Ssam tp->t_flags &= ~FLUSHO; 8889578Ssam startoutput: 8897502Sroot ttstart(tp); 8907502Sroot } 8917502Sroot 8927502Sroot /* 8939578Ssam * Put character on TTY output queue, adding delays, 8947502Sroot * expanding tabs, and handling the CR/NL bit. 8959578Ssam * This is called both from the top half for output, 8969578Ssam * and from interrupt level for echoing. 8977502Sroot * The arguments are the character and the tty structure. 8987502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8997502Sroot * Must be recursive. 9007502Sroot */ 9017502Sroot ttyoutput(c, tp) 9027502Sroot register c; 9037502Sroot register struct tty *tp; 9047502Sroot { 9057502Sroot register char *colp; 9067502Sroot register ctype; 9077502Sroot 9089578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9099578Ssam if (tp->t_flags&FLUSHO) 9107502Sroot return (-1); 9117502Sroot if (putc(c, &tp->t_outq)) 9127625Ssam return (c); 9137502Sroot tk_nout++; 9147502Sroot return (-1); 9157502Sroot } 9169578Ssam 9177502Sroot /* 9189578Ssam * Ignore EOT in normal mode to avoid 9199578Ssam * hanging up certain terminals. 9207502Sroot */ 9217502Sroot c &= 0177; 9229578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9237502Sroot return (-1); 9247502Sroot /* 9257502Sroot * Turn tabs to spaces as required 9267502Sroot */ 9279578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9287502Sroot register int s; 9297502Sroot 9307502Sroot c = 8 - (tp->t_col&7); 9319578Ssam if ((tp->t_flags&FLUSHO) == 0) { 93217545Skarels s = spltty(); /* don't interrupt tabs */ 9337502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9347502Sroot tk_nout += c; 9357502Sroot splx(s); 9367502Sroot } 9377502Sroot tp->t_col += c; 9387502Sroot return (c ? -1 : '\t'); 9397502Sroot } 9407502Sroot tk_nout++; 9417502Sroot /* 9427502Sroot * for upper-case-only terminals, 9437502Sroot * generate escapes. 9447502Sroot */ 9457502Sroot if (tp->t_flags&LCASE) { 9467502Sroot colp = "({)}!|^~'`"; 9477625Ssam while (*colp++) 9487625Ssam if (c == *colp++) { 9497502Sroot if (ttyoutput('\\', tp) >= 0) 9507502Sroot return (c); 9517502Sroot c = colp[-2]; 9527502Sroot break; 9537502Sroot } 9549578Ssam if ('A' <= c && c <= 'Z') { 9557502Sroot if (ttyoutput('\\', tp) >= 0) 9567502Sroot return (c); 9579578Ssam } else if ('a' <= c && c <= 'z') 9587502Sroot c += 'A' - 'a'; 9597502Sroot } 9609578Ssam 9617502Sroot /* 9627502Sroot * turn <nl> to <cr><lf> if desired. 9637502Sroot */ 9649578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9657502Sroot if (ttyoutput('\r', tp) >= 0) 9667502Sroot return (c); 9679578Ssam if (c == '~' && tp->t_flags&TILDE) 9687502Sroot c = '`'; 9699578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9707502Sroot return (c); 9717502Sroot /* 9727502Sroot * Calculate delays. 9737502Sroot * The numbers here represent clock ticks 9747502Sroot * and are not necessarily optimal for all terminals. 9757502Sroot * The delays are indicated by characters above 0200. 9767502Sroot * In raw mode there are no delays and the 9777502Sroot * transmission path is 8 bits wide. 9789578Ssam * 9799578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9807502Sroot */ 9817502Sroot colp = &tp->t_col; 9827502Sroot ctype = partab[c]; 9837502Sroot c = 0; 9847502Sroot switch (ctype&077) { 9857502Sroot 9867502Sroot case ORDINARY: 9877502Sroot (*colp)++; 9887502Sroot 9897502Sroot case CONTROL: 9907502Sroot break; 9917502Sroot 9927502Sroot case BACKSPACE: 9937502Sroot if (*colp) 9947502Sroot (*colp)--; 9957502Sroot break; 9967502Sroot 99713821Ssam /* 99813821Ssam * This macro is close enough to the correct thing; 99913821Ssam * it should be replaced by real user settable delays 100013821Ssam * in any event... 100113821Ssam */ 100213821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10037502Sroot case NEWLINE: 10047502Sroot ctype = (tp->t_flags >> 8) & 03; 10057625Ssam if (ctype == 1) { /* tty 37 */ 100612752Ssam if (*colp > 0) 100713863Ssam c = max((((unsigned)*colp) >> 4) + 3, 100813863Ssam (unsigned)6); 10099578Ssam } else if (ctype == 2) /* vt05 */ 101013821Ssam c = mstohz(100); 10117502Sroot *colp = 0; 10127502Sroot break; 10137502Sroot 10147502Sroot case TAB: 10157502Sroot ctype = (tp->t_flags >> 10) & 03; 10167625Ssam if (ctype == 1) { /* tty 37 */ 10177502Sroot c = 1 - (*colp | ~07); 10187625Ssam if (c < 5) 10197502Sroot c = 0; 10207502Sroot } 10217502Sroot *colp |= 07; 10227502Sroot (*colp)++; 10237502Sroot break; 10247502Sroot 10257502Sroot case VTAB: 10269578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10277502Sroot c = 0177; 10287502Sroot break; 10297502Sroot 10307502Sroot case RETURN: 10317502Sroot ctype = (tp->t_flags >> 12) & 03; 10329578Ssam if (ctype == 1) /* tn 300 */ 103313821Ssam c = mstohz(83); 10349578Ssam else if (ctype == 2) /* ti 700 */ 103513821Ssam c = mstohz(166); 10369578Ssam else if (ctype == 3) { /* concept 100 */ 10377502Sroot int i; 10389578Ssam 10397502Sroot if ((i = *colp) >= 0) 10409578Ssam for (; i < 9; i++) 10417502Sroot (void) putc(0177, &tp->t_outq); 10427502Sroot } 10437502Sroot *colp = 0; 10447502Sroot } 10459578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10467502Sroot (void) putc(c|0200, &tp->t_outq); 10477502Sroot return (-1); 10487502Sroot } 104913821Ssam #undef mstohz 10507502Sroot 10517502Sroot /* 10527502Sroot * Called from device's read routine after it has 10537502Sroot * calculated the tty-structure given as argument. 10547502Sroot */ 10557722Swnj ttread(tp, uio) 10567625Ssam register struct tty *tp; 10577722Swnj struct uio *uio; 10587502Sroot { 10597502Sroot register struct clist *qp; 10609578Ssam register c, t_flags; 10619859Ssam int s, first, error = 0; 10627502Sroot 10637502Sroot loop: 10649578Ssam /* 10659578Ssam * Take any pending input first. 10669578Ssam */ 106717545Skarels s = spltty(); 10689578Ssam if (tp->t_flags&PENDIN) 10697502Sroot ttypend(tp); 10709859Ssam splx(s); 10719578Ssam 107223165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 107323165Sbloom return (EIO); 107423165Sbloom 10759578Ssam /* 10769578Ssam * Hang process if it's in the background. 10779578Ssam */ 107815141Skarels #define bit(a) (1<<(a-1)) 107923165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 108015141Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 108115141Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 10827502Sroot u.u_procp->p_flag&SVFORK) 10838520Sroot return (EIO); 10847502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10857502Sroot sleep((caddr_t)&lbolt, TTIPRI); 108623165Sbloom goto loop; 10877502Sroot } 10889578Ssam t_flags = tp->t_flags; 108915141Skarels #undef bit 10909578Ssam 10919578Ssam /* 10929578Ssam * In raw mode take characters directly from the 10939578Ssam * raw queue w/o processing. Interlock against 10949578Ssam * device interrupts when interrogating rawq. 10959578Ssam */ 10969578Ssam if (t_flags&RAW) { 109717545Skarels s = spltty(); 10987502Sroot if (tp->t_rawq.c_cc <= 0) { 10999578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11007502Sroot (tp->t_state&TS_NBIO)) { 11019859Ssam splx(s); 110215094Skarels return (EWOULDBLOCK); 11037502Sroot } 11047502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11059859Ssam splx(s); 11067502Sroot goto loop; 11077502Sroot } 11089859Ssam splx(s); 110914938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 111014938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11119859Ssam goto checktandem; 11129578Ssam } 11139578Ssam 11149578Ssam /* 11159578Ssam * In cbreak mode use the rawq, otherwise 11169578Ssam * take characters from the canonicalized q. 11179578Ssam */ 11189578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11199578Ssam 11209578Ssam /* 11219578Ssam * No input, sleep on rawq awaiting hardware 11229578Ssam * receipt and notification. 11239578Ssam */ 112417545Skarels s = spltty(); 11259578Ssam if (qp->c_cc <= 0) { 11269578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11279578Ssam (tp->t_state&TS_NBIO)) { 11289859Ssam splx(s); 11299578Ssam return (EWOULDBLOCK); 11307502Sroot } 11319578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11329859Ssam splx(s); 11339578Ssam goto loop; 11349578Ssam } 11359859Ssam splx(s); 11369578Ssam 11379578Ssam /* 11389578Ssam * Input present, perform input mapping 11399578Ssam * and processing (we're not in raw mode). 11409578Ssam */ 11419578Ssam first = 1; 11429578Ssam while ((c = getc(qp)) >= 0) { 11439578Ssam if (t_flags&CRMOD && c == '\r') 11449578Ssam c = '\n'; 11459578Ssam /* 11469578Ssam * Check for delayed suspend character. 11479578Ssam */ 11489578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11499578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11509578Ssam if (first) { 11519578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11529578Ssam goto loop; 11539578Ssam } 11549578Ssam break; 11557502Sroot } 11569578Ssam /* 11579578Ssam * Interpret EOF only in cooked mode. 11589578Ssam */ 11599578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11609578Ssam break; 11619578Ssam /* 11629578Ssam * Give user character. 11639578Ssam */ 1164*24273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 11659578Ssam if (error) 11669578Ssam break; 116714938Smckusick if (uio->uio_resid == 0) 11689578Ssam break; 11699578Ssam /* 11709578Ssam * In cooked mode check for a "break character" 11719578Ssam * marking the end of a "line of input". 11729578Ssam */ 11739578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11749578Ssam break; 11759578Ssam first = 0; 11767502Sroot } 11779578Ssam 11789859Ssam checktandem: 11799578Ssam /* 11809578Ssam * Look to unblock output now that (presumably) 11819578Ssam * the input queue has gone down. 11829578Ssam */ 11839859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11849578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11857502Sroot tp->t_state &= ~TS_TBLOCK; 11867502Sroot ttstart(tp); 11877502Sroot } 11888520Sroot return (error); 11897502Sroot } 11907502Sroot 11917502Sroot /* 11927502Sroot * Called from the device's write routine after it has 11937502Sroot * calculated the tty-structure given as argument. 11947502Sroot */ 11957822Sroot ttwrite(tp, uio) 11967625Ssam register struct tty *tp; 11979578Ssam register struct uio *uio; 11987502Sroot { 11997502Sroot register char *cp; 12009578Ssam register int cc, ce, c; 12019578Ssam int i, hiwat, cnt, error, s; 12027502Sroot char obuf[OBUFSIZ]; 12037502Sroot 12049578Ssam hiwat = TTHIWAT(tp); 12059578Ssam cnt = uio->uio_resid; 12069578Ssam error = 0; 12077502Sroot loop: 120821776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 120921776Sbloom return (EIO); 12109578Ssam /* 12119578Ssam * Hang the process if it's in the background. 12129578Ssam */ 121315141Skarels #define bit(a) (1<<(a-1)) 121421776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12159578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 121615141Skarels !(u.u_procp->p_sigignore & bit(SIGTTOU)) && 121721776Sbloom !(u.u_procp->p_sigmask & bit(SIGTTOU))) { 12187502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12197502Sroot sleep((caddr_t)&lbolt, TTIPRI); 122021776Sbloom goto loop; 12217502Sroot } 122215141Skarels #undef bit 12239578Ssam 12249578Ssam /* 12259578Ssam * Process the user's data in at most OBUFSIZ 12269578Ssam * chunks. Perform lower case simulation and 12279578Ssam * similar hacks. Keep track of high water 12289578Ssam * mark, sleep on overflow awaiting device aid 12299578Ssam * in acquiring new space. 12309578Ssam */ 12317822Sroot while (uio->uio_resid > 0) { 12329578Ssam /* 12339578Ssam * Grab a hunk of data from the user. 12349578Ssam */ 12357822Sroot cc = uio->uio_iov->iov_len; 12367822Sroot if (cc == 0) { 12377822Sroot uio->uio_iovcnt--; 12387822Sroot uio->uio_iov++; 123921776Sbloom if (uio->uio_iovcnt <= 0) 12407822Sroot panic("ttwrite"); 12417822Sroot continue; 12427822Sroot } 12437822Sroot if (cc > OBUFSIZ) 12447822Sroot cc = OBUFSIZ; 12457502Sroot cp = obuf; 124612752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12478520Sroot if (error) 12487502Sroot break; 12497502Sroot if (tp->t_outq.c_cc > hiwat) 12507502Sroot goto ovhiwat; 12519578Ssam if (tp->t_flags&FLUSHO) 12527502Sroot continue; 12539578Ssam /* 12549578Ssam * If we're mapping lower case or kludging tildes, 12559578Ssam * then we've got to look at each character, so 12569578Ssam * just feed the stuff to ttyoutput... 12579578Ssam */ 12589578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12599578Ssam while (cc > 0) { 12607502Sroot c = *cp++; 12617502Sroot tp->t_rocount = 0; 12627625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12637502Sroot /* out of clists, wait a bit */ 12647502Sroot ttstart(tp); 12657502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12667502Sroot tp->t_rocount = 0; 126721776Sbloom if (cc != 0) { 126821776Sbloom uio->uio_iov->iov_base -= cc; 126921776Sbloom uio->uio_iov->iov_len += cc; 127021776Sbloom uio->uio_resid += cc; 127121776Sbloom uio->uio_offset -= cc; 127221776Sbloom } 127321776Sbloom goto loop; 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) { 130321776Sbloom /* no c-lists, wait a bit */ 130421776Sbloom ttstart(tp); 130521776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 130621776Sbloom if (cc != 0) { 130721776Sbloom uio->uio_iov->iov_base -= cc; 130821776Sbloom uio->uio_iov->iov_len += cc; 130921776Sbloom uio->uio_resid += cc; 131021776Sbloom uio->uio_offset -= cc; 131121776Sbloom } 131221776Sbloom goto loop; 13137502Sroot } 13149578Ssam cp++, cc--; 13159578Ssam if (tp->t_flags&FLUSHO || 13169578Ssam tp->t_outq.c_cc > hiwat) 13177502Sroot goto ovhiwat; 13189578Ssam continue; 13197502Sroot } 13207502Sroot } 13219578Ssam /* 13229578Ssam * A bunch of normal characters have been found, 13239578Ssam * transfer them en masse to the output queue and 13249578Ssam * continue processing at the top of the loop. 13259578Ssam * If there are any further characters in this 13269578Ssam * <= OBUFSIZ chunk, the first should be a character 13279578Ssam * requiring special handling by ttyoutput. 13289578Ssam */ 13297502Sroot tp->t_rocount = 0; 13309578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13319578Ssam ce -= i; 13329578Ssam tp->t_col += ce; 13339578Ssam cp += ce, cc -= ce, tk_nout += ce; 13349578Ssam if (i > 0) { 13359578Ssam /* out of c-lists, wait a bit */ 13367502Sroot ttstart(tp); 13377502Sroot sleep((caddr_t)&lbolt, TTOPRI); 133821776Sbloom uio->uio_iov->iov_base -= cc; 133921776Sbloom uio->uio_iov->iov_len += cc; 134021776Sbloom uio->uio_resid += cc; 134121776Sbloom uio->uio_offset -= cc; 134221776Sbloom goto loop; 13437502Sroot } 13449578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13457502Sroot goto ovhiwat; 13467502Sroot } 13477502Sroot } 13487502Sroot ttstart(tp); 13498520Sroot return (error); 13507502Sroot 13517502Sroot ovhiwat: 135217545Skarels s = spltty(); 13539578Ssam if (cc != 0) { 13549578Ssam uio->uio_iov->iov_base -= cc; 13559578Ssam uio->uio_iov->iov_len += cc; 13569578Ssam uio->uio_resid += cc; 13579578Ssam uio->uio_offset -= cc; 13589578Ssam } 13599578Ssam /* 13609578Ssam * This can only occur if FLUSHO 13619578Ssam * is also set in t_flags. 13629578Ssam */ 13637502Sroot if (tp->t_outq.c_cc <= hiwat) { 13649578Ssam splx(s); 13657502Sroot goto loop; 13667502Sroot } 13677502Sroot ttstart(tp); 13689578Ssam if (tp->t_state&TS_NBIO) { 136917545Skarels splx(s); 13707822Sroot if (uio->uio_resid == cnt) 13718520Sroot return (EWOULDBLOCK); 13728520Sroot return (0); 13737502Sroot } 13747502Sroot tp->t_state |= TS_ASLEEP; 13757502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13769578Ssam splx(s); 13777502Sroot goto loop; 13787502Sroot } 13797502Sroot 13807502Sroot /* 13817502Sroot * Rubout one character from the rawq of tp 13827502Sroot * as cleanly as possible. 13837502Sroot */ 13847502Sroot ttyrub(c, tp) 13857625Ssam register c; 13867625Ssam register struct tty *tp; 13877502Sroot { 13887502Sroot register char *cp; 13897502Sroot register int savecol; 13907502Sroot int s; 13917502Sroot char *nextc(); 13927502Sroot 13939578Ssam if ((tp->t_flags&ECHO) == 0) 13947502Sroot return; 13959578Ssam tp->t_flags &= ~FLUSHO; 13967502Sroot c &= 0377; 13979578Ssam if (tp->t_flags&CRTBS) { 13987502Sroot if (tp->t_rocount == 0) { 13997502Sroot /* 14007502Sroot * Screwed by ttwrite; retype 14017502Sroot */ 14027502Sroot ttyretype(tp); 14037502Sroot return; 14047502Sroot } 14059578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14067502Sroot ttyrubo(tp, 2); 14079578Ssam else switch (partab[c&=0177]&0177) { 14087502Sroot 14097502Sroot case ORDINARY: 14107502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14117502Sroot ttyrubo(tp, 2); 14127502Sroot else 14137502Sroot ttyrubo(tp, 1); 14147502Sroot break; 14157502Sroot 14167502Sroot case VTAB: 14177502Sroot case BACKSPACE: 14187502Sroot case CONTROL: 14197502Sroot case RETURN: 14209578Ssam if (tp->t_flags&CTLECH) 14217502Sroot ttyrubo(tp, 2); 14227502Sroot break; 14237502Sroot 14247502Sroot case TAB: 14257502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14267502Sroot ttyretype(tp); 14277502Sroot return; 14287502Sroot } 142917545Skarels s = spltty(); 14307502Sroot savecol = tp->t_col; 14319578Ssam tp->t_state |= TS_CNTTB; 14329578Ssam tp->t_flags |= FLUSHO; 14337502Sroot tp->t_col = tp->t_rocol; 14349578Ssam cp = tp->t_rawq.c_cf; 14359578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14367502Sroot ttyecho(*cp, tp); 14379578Ssam tp->t_flags &= ~FLUSHO; 14389578Ssam tp->t_state &= ~TS_CNTTB; 14397502Sroot splx(s); 14407502Sroot /* 14417502Sroot * savecol will now be length of the tab 14427502Sroot */ 14437502Sroot savecol -= tp->t_col; 14447502Sroot tp->t_col += savecol; 14457502Sroot if (savecol > 8) 14467502Sroot savecol = 8; /* overflow screw */ 14477502Sroot while (--savecol >= 0) 14487502Sroot (void) ttyoutput('\b', tp); 14497502Sroot break; 14507502Sroot 14517502Sroot default: 14527502Sroot panic("ttyrub"); 14537502Sroot } 14549578Ssam } else if (tp->t_flags&PRTERA) { 14559578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14567502Sroot (void) ttyoutput('\\', tp); 14579578Ssam tp->t_state |= TS_ERASE; 14587502Sroot } 14597502Sroot ttyecho(c, tp); 14607502Sroot } else 14617502Sroot ttyecho(tp->t_erase, tp); 14627502Sroot tp->t_rocount--; 14637502Sroot } 14647502Sroot 14657502Sroot /* 14667502Sroot * Crt back over cnt chars perhaps 14677502Sroot * erasing them. 14687502Sroot */ 14697502Sroot ttyrubo(tp, cnt) 14707625Ssam register struct tty *tp; 14717625Ssam int cnt; 14727502Sroot { 14739578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14747502Sroot 14757502Sroot while (--cnt >= 0) 14769578Ssam ttyout(rubostring, tp); 14777502Sroot } 14787502Sroot 14797502Sroot /* 14807502Sroot * Reprint the rawq line. 14817502Sroot * We assume c_cc has already been checked. 14827502Sroot */ 14837502Sroot ttyretype(tp) 14847625Ssam register struct tty *tp; 14857502Sroot { 14867502Sroot register char *cp; 14877502Sroot char *nextc(); 14887502Sroot int s; 14897502Sroot 14909578Ssam if (tp->t_rprntc != 0377) 14919578Ssam ttyecho(tp->t_rprntc, tp); 14927502Sroot (void) ttyoutput('\n', tp); 149317545Skarels s = spltty(); 14947502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14957502Sroot ttyecho(*cp, tp); 14967502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14977502Sroot ttyecho(*cp, tp); 14989578Ssam tp->t_state &= ~TS_ERASE; 14997502Sroot splx(s); 15007502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15017502Sroot tp->t_rocol = 0; 15027502Sroot } 15037502Sroot 15047502Sroot /* 15057502Sroot * Echo a typed character to the terminal 15067502Sroot */ 15077502Sroot ttyecho(c, tp) 15087625Ssam register c; 15097625Ssam register struct tty *tp; 15107502Sroot { 15117502Sroot 15129578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15139578Ssam tp->t_flags &= ~FLUSHO; 15147502Sroot if ((tp->t_flags&ECHO) == 0) 15157502Sroot return; 15167502Sroot c &= 0377; 15177502Sroot if (tp->t_flags&RAW) { 15187502Sroot (void) ttyoutput(c, tp); 15197502Sroot return; 15207502Sroot } 15217502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15227502Sroot c = '\n'; 15239578Ssam if (tp->t_flags&CTLECH) { 15247502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15257502Sroot (void) ttyoutput('^', tp); 15267502Sroot c &= 0177; 15277502Sroot if (c == 0177) 15287502Sroot c = '?'; 15297502Sroot else if (tp->t_flags&LCASE) 15307502Sroot c += 'a' - 1; 15317502Sroot else 15327502Sroot c += 'A' - 1; 15337502Sroot } 15347502Sroot } 15359578Ssam (void) ttyoutput(c&0177, tp); 15367502Sroot } 15377502Sroot 15387502Sroot /* 15397502Sroot * Is c a break char for tp? 15407502Sroot */ 15417502Sroot ttbreakc(c, tp) 15427625Ssam register c; 15437625Ssam register struct tty *tp; 15447502Sroot { 15459578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15467502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15477502Sroot } 15487502Sroot 15497502Sroot /* 15507502Sroot * send string cp to tp 15517502Sroot */ 15527502Sroot ttyout(cp, tp) 15537625Ssam register char *cp; 15547625Ssam register struct tty *tp; 15557502Sroot { 15567502Sroot register char c; 15577502Sroot 15587502Sroot while (c = *cp++) 15597502Sroot (void) ttyoutput(c, tp); 15607502Sroot } 15617502Sroot 15627502Sroot ttwakeup(tp) 15637502Sroot struct tty *tp; 15647502Sroot { 15657502Sroot 15667502Sroot if (tp->t_rsel) { 15677502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15687502Sroot tp->t_state &= ~TS_RCOLL; 15697502Sroot tp->t_rsel = 0; 15707502Sroot } 157112752Ssam if (tp->t_state & TS_ASYNC) 157212752Ssam gsignal(tp->t_pgrp, SIGIO); 15737502Sroot wakeup((caddr_t)&tp->t_rawq); 15747502Sroot } 1575