123387Smckusick /* 229107Smckusick * Copyright (c) 1982, 1986 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*30534Skarels * @(#)tty.c 7.4 (Berkeley) 02/19/87 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" 2229946Skarels #include "dkstat.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 111*30534Skarels extern struct tty *constty; /* temporary virtual console */ 112*30534Skarels 11339Sbill ttychars(tp) 1149578Ssam struct tty *tp; 11539Sbill { 116174Sbill 1179578Ssam tp->t_chars = ttydefaults; 11839Sbill } 11939Sbill 12039Sbill /* 121903Sbill * Wait for output to drain, then flush input waiting. 12239Sbill */ 12312752Ssam ttywflush(tp) 1245408Swnj register struct tty *tp; 12539Sbill { 12639Sbill 12712752Ssam ttywait(tp); 12812752Ssam ttyflush(tp, FREAD); 12912752Ssam } 13012752Ssam 13112752Ssam ttywait(tp) 13212752Ssam register struct tty *tp; 13312752Ssam { 13417545Skarels register int s = spltty(); 13512752Ssam 13613809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 13725391Skarels tp->t_state&TS_CARR_ON) { 138903Sbill (*tp->t_oproc)(tp); 1395408Swnj tp->t_state |= TS_ASLEEP; 140903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 141903Sbill } 1429859Ssam splx(s); 14339Sbill } 14439Sbill 14539Sbill /* 1469578Ssam * Flush all TTY queues 14739Sbill */ 14812752Ssam ttyflush(tp, rw) 1497625Ssam register struct tty *tp; 15039Sbill { 151903Sbill register s; 152903Sbill 15317545Skarels s = spltty(); 154903Sbill if (rw & FREAD) { 155903Sbill while (getc(&tp->t_canq) >= 0) 156903Sbill ; 157903Sbill wakeup((caddr_t)&tp->t_rawq); 158903Sbill } 159903Sbill if (rw & FWRITE) { 160903Sbill wakeup((caddr_t)&tp->t_outq); 1615408Swnj tp->t_state &= ~TS_TTSTOP; 1625426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 163903Sbill while (getc(&tp->t_outq) >= 0) 164903Sbill ; 165903Sbill } 166903Sbill if (rw & FREAD) { 167903Sbill while (getc(&tp->t_rawq) >= 0) 168903Sbill ; 1699578Ssam tp->t_rocount = 0; 170903Sbill tp->t_rocol = 0; 1719578Ssam tp->t_state &= ~TS_LOCAL; 172903Sbill } 173903Sbill splx(s); 17439Sbill } 17539Sbill 176903Sbill /* 177903Sbill * Send stop character on input overflow. 178903Sbill */ 179903Sbill ttyblock(tp) 1807625Ssam register struct tty *tp; 18139Sbill { 182903Sbill register x; 1839578Ssam 184903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 185903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 18612752Ssam ttyflush(tp, FREAD|FWRITE); 1875408Swnj tp->t_state &= ~TS_TBLOCK; 188903Sbill } 18915118Skarels /* 19015118Skarels * Block further input iff: 19115118Skarels * Current input > threshold AND input is available to user program 19215118Skarels */ 19316055Skarels if (x >= TTYHOG/2 && 19416055Skarels ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) { 19515118Skarels if (putc(tp->t_stopc, &tp->t_outq)==0) { 19615118Skarels tp->t_state |= TS_TBLOCK; 19715118Skarels ttstart(tp); 19815118Skarels } 199903Sbill } 20039Sbill } 20139Sbill 20239Sbill /* 203903Sbill * Restart typewriter output following a delay 204903Sbill * timeout. 205903Sbill * The name of the routine is passed to the timeout 206903Sbill * subroutine and it is called during a clock interrupt. 207121Sbill */ 208903Sbill ttrstrt(tp) 2097625Ssam register struct tty *tp; 210121Sbill { 211121Sbill 2129578Ssam if (tp == 0) 2139578Ssam panic("ttrstrt"); 2145408Swnj tp->t_state &= ~TS_TIMEOUT; 215903Sbill ttstart(tp); 216121Sbill } 217121Sbill 218121Sbill /* 219903Sbill * Start output on the typewriter. It is used from the top half 220903Sbill * after some characters have been put on the output queue, 221903Sbill * from the interrupt routine to transmit the next 222903Sbill * character, and after a timeout has finished. 22339Sbill */ 224903Sbill ttstart(tp) 2257625Ssam register struct tty *tp; 22639Sbill { 227903Sbill register s; 22839Sbill 22917545Skarels s = spltty(); 2309578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2315622Swnj tp->t_oproc) /* kludge for pty */ 232903Sbill (*tp->t_oproc)(tp); 233903Sbill splx(s); 23439Sbill } 23539Sbill 23639Sbill /* 237903Sbill * Common code for tty ioctls. 23839Sbill */ 2391780Sbill /*ARGSUSED*/ 2407625Ssam ttioctl(tp, com, data, flag) 2417625Ssam register struct tty *tp; 2427625Ssam caddr_t data; 24339Sbill { 2448520Sroot int dev = tp->t_dev; 24539Sbill extern int nldisp; 2468556Sroot int s; 24712752Ssam register int newflags; 24839Sbill 249*30534Skarels 250903Sbill /* 251903Sbill * If the ioctl involves modification, 25217545Skarels * hang if in the background. 253903Sbill */ 2547625Ssam switch (com) { 25539Sbill 256915Sbill case TIOCSETD: 257915Sbill case TIOCSETP: 258915Sbill case TIOCSETN: 259903Sbill case TIOCFLUSH: 260903Sbill case TIOCSETC: 261903Sbill case TIOCSLTC: 262903Sbill case TIOCSPGRP: 263903Sbill case TIOCLBIS: 264903Sbill case TIOCLBIC: 265903Sbill case TIOCLSET: 2669325Ssam case TIOCSTI: 26717598Sbloom case TIOCSWINSZ: 268903Sbill while (tp->t_line == NTTYDISC && 269903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 270903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 27124392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 27224392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 273903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 274903Sbill sleep((caddr_t)&lbolt, TTOPRI); 275903Sbill } 276903Sbill break; 277903Sbill } 278903Sbill 2799578Ssam /* 2809578Ssam * Process the ioctl. 2819578Ssam */ 2827625Ssam switch (com) { 283903Sbill 2848556Sroot /* get discipline number */ 28539Sbill case TIOCGETD: 2867625Ssam *(int *)data = tp->t_line; 28739Sbill break; 28839Sbill 2898556Sroot /* set line discipline */ 2907625Ssam case TIOCSETD: { 2917625Ssam register int t = *(int *)data; 2929578Ssam int error = 0; 2937625Ssam 29415078Skarels if ((unsigned) t >= nldisp) 29510851Ssam return (ENXIO); 29625584Skarels if (t != tp->t_line) { 29725584Skarels s = spltty(); 29825584Skarels (*linesw[tp->t_line].l_close)(tp); 29925584Skarels error = (*linesw[t].l_open)(dev, tp); 30025584Skarels if (error) { 30125584Skarels (void) (*linesw[tp->t_line].l_open)(dev, tp); 30225584Skarels splx(s); 30325584Skarels return (error); 30425584Skarels } 30525584Skarels tp->t_line = t; 30610851Ssam splx(s); 30710851Ssam } 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: 47129946Skarels *(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 510*30534Skarels case TIOCCONS: 511*30534Skarels if (*(int *)data) { 512*30534Skarels if (constty != NULL) 513*30534Skarels return (EBUSY); 514*30534Skarels #ifndef UCONSOLE 515*30534Skarels if (!suser()) 516*30534Skarels return (EPERM); 517*30534Skarels #endif 518*30534Skarels constty = tp; 519*30534Skarels } else if (tp == constty) 520*30534Skarels constty == NULL; 521*30534Skarels break; 522*30534Skarels 52339Sbill default: 5248556Sroot return (-1); 52539Sbill } 5268556Sroot return (0); 52739Sbill } 5284484Swnj 5294484Swnj ttnread(tp) 5304484Swnj struct tty *tp; 5314484Swnj { 5324484Swnj int nread = 0; 5334484Swnj 5349578Ssam if (tp->t_flags & PENDIN) 5354484Swnj ttypend(tp); 5364484Swnj nread = tp->t_canq.c_cc; 5374484Swnj if (tp->t_flags & (RAW|CBREAK)) 5384484Swnj nread += tp->t_rawq.c_cc; 5394484Swnj return (nread); 5404484Swnj } 5414484Swnj 5425408Swnj ttselect(dev, rw) 5434484Swnj dev_t dev; 5445408Swnj int rw; 5454484Swnj { 5464484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5474484Swnj int nread; 54817545Skarels int s = spltty(); 5494484Swnj 5505408Swnj switch (rw) { 5514484Swnj 5524484Swnj case FREAD: 5534484Swnj nread = ttnread(tp); 55429946Skarels if (nread > 0 || (tp->t_state & TS_CARR_ON) == 0) 5555408Swnj goto win; 5564938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5575408Swnj tp->t_state |= TS_RCOLL; 5584484Swnj else 5594484Swnj tp->t_rsel = u.u_procp; 5605408Swnj break; 5614484Swnj 5625408Swnj case FWRITE: 5635408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5645408Swnj goto win; 5655408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5665408Swnj tp->t_state |= TS_WCOLL; 5675408Swnj else 5685408Swnj tp->t_wsel = u.u_procp; 5695408Swnj break; 5704484Swnj } 5715408Swnj splx(s); 5725408Swnj return (0); 5735408Swnj win: 5745408Swnj splx(s); 5755408Swnj return (1); 5764484Swnj } 5777436Skre 5787502Sroot /* 57925391Skarels * Initial open of tty, or (re)entry to line discipline. 5809578Ssam * Establish a process group for distribution of 5817502Sroot * quits and interrupts from the tty. 5827502Sroot */ 5837502Sroot ttyopen(dev, tp) 5847625Ssam dev_t dev; 5857625Ssam register struct tty *tp; 5867502Sroot { 5877502Sroot register struct proc *pp; 5887502Sroot 5897502Sroot pp = u.u_procp; 5907502Sroot tp->t_dev = dev; 5917625Ssam if (pp->p_pgrp == 0) { 5927502Sroot u.u_ttyp = tp; 5937502Sroot u.u_ttyd = dev; 5947502Sroot if (tp->t_pgrp == 0) 5957502Sroot tp->t_pgrp = pp->p_pid; 5967502Sroot pp->p_pgrp = tp->t_pgrp; 5977502Sroot } 5987502Sroot tp->t_state &= ~TS_WOPEN; 59917545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 60017545Skarels tp->t_state |= TS_ISOPEN; 60117598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 60217545Skarels if (tp->t_line != NTTYDISC) 60317545Skarels ttywflush(tp); 60417545Skarels } 6058556Sroot return (0); 6067502Sroot } 6077502Sroot 6087502Sroot /* 60925391Skarels * "close" a line discipline 61025391Skarels */ 61125391Skarels ttylclose(tp) 61225391Skarels register struct tty *tp; 61325391Skarels { 61425391Skarels 61525391Skarels ttywflush(tp); 61625391Skarels tp->t_line = 0; 61725391Skarels } 61825391Skarels 61925391Skarels /* 6207502Sroot * clean tp on last close 6217502Sroot */ 6227502Sroot ttyclose(tp) 6237625Ssam register struct tty *tp; 6247502Sroot { 6257502Sroot 626*30534Skarels if (constty == tp) 627*30534Skarels constty = NULL; 62825391Skarels ttyflush(tp, FREAD|FWRITE); 6297502Sroot tp->t_pgrp = 0; 6307502Sroot tp->t_state = 0; 6317502Sroot } 6327502Sroot 6337502Sroot /* 63425391Skarels * Handle modem control transition on a tty. 63525391Skarels * Flag indicates new state of carrier. 63625391Skarels * Returns 0 if the line should be turned off, otherwise 1. 63725391Skarels */ 63825391Skarels ttymodem(tp, flag) 63925391Skarels register struct tty *tp; 64025391Skarels { 64125391Skarels 64225391Skarels if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { 64325391Skarels /* 64425391Skarels * MDMBUF: do flow control according to carrier flag 64525391Skarels */ 64625391Skarels if (flag) { 64725391Skarels tp->t_state &= ~TS_TTSTOP; 64825391Skarels ttstart(tp); 64925391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 65025391Skarels tp->t_state |= TS_TTSTOP; 65125391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 65225391Skarels } 65325391Skarels } else if (flag == 0) { 65425391Skarels /* 65525391Skarels * Lost carrier. 65625391Skarels */ 65725391Skarels tp->t_state &= ~TS_CARR_ON; 65825391Skarels if (tp->t_state & TS_ISOPEN) { 65925391Skarels if ((tp->t_flags & NOHANG) == 0) { 66025391Skarels gsignal(tp->t_pgrp, SIGHUP); 66125391Skarels gsignal(tp->t_pgrp, SIGCONT); 66225391Skarels ttyflush(tp, FREAD|FWRITE); 66325391Skarels return (0); 66425391Skarels } 66525391Skarels } 66625391Skarels } else { 66725391Skarels /* 66825391Skarels * Carrier now on. 66925391Skarels */ 67025391Skarels tp->t_state |= TS_CARR_ON; 67125391Skarels wakeup((caddr_t)&tp->t_rawq); 67225391Skarels } 67325391Skarels return (1); 67425391Skarels } 67525391Skarels 67625391Skarels /* 67725404Skarels * Default modem control routine (for other line disciplines). 67825404Skarels * Return argument flag, to turn off device on carrier drop. 67925404Skarels */ 68025415Skarels nullmodem(tp, flag) 68125415Skarels register struct tty *tp; 68225404Skarels int flag; 68325404Skarels { 68425404Skarels 68525404Skarels if (flag) 68625404Skarels tp->t_state |= TS_CARR_ON; 68725404Skarels else 68825404Skarels tp->t_state &= ~TS_CARR_ON; 68925404Skarels return (flag); 69025404Skarels } 69125404Skarels 69225404Skarels /* 6937502Sroot * reinput pending characters after state switch 69417545Skarels * call at spltty(). 6957502Sroot */ 6967502Sroot ttypend(tp) 6977625Ssam register struct tty *tp; 6987502Sroot { 6997502Sroot struct clist tq; 7007502Sroot register c; 7017502Sroot 7029578Ssam tp->t_flags &= ~PENDIN; 7039578Ssam tp->t_state |= TS_TYPEN; 7047502Sroot tq = tp->t_rawq; 7057502Sroot tp->t_rawq.c_cc = 0; 7067502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7077502Sroot while ((c = getc(&tq)) >= 0) 7087502Sroot ttyinput(c, tp); 7099578Ssam tp->t_state &= ~TS_TYPEN; 7107502Sroot } 7117502Sroot 7127502Sroot /* 7139578Ssam * Place a character on raw TTY input queue, 7149578Ssam * putting in delimiters and waking up top 7159578Ssam * half as needed. Also echo if required. 7169578Ssam * The arguments are the character and the 7179578Ssam * appropriate tty structure. 7187502Sroot */ 7197502Sroot ttyinput(c, tp) 7207625Ssam register c; 7217625Ssam register struct tty *tp; 7227502Sroot { 7239578Ssam register int t_flags = tp->t_flags; 7247502Sroot int i; 7257502Sroot 7269578Ssam /* 7279578Ssam * If input is pending take it first. 7289578Ssam */ 7299578Ssam if (t_flags&PENDIN) 7307502Sroot ttypend(tp); 7317502Sroot tk_nin++; 7327502Sroot c &= 0377; 7339578Ssam 7349578Ssam /* 7359578Ssam * In tandem mode, check high water mark. 7369578Ssam */ 7377502Sroot if (t_flags&TANDEM) 7387502Sroot ttyblock(tp); 7399578Ssam 7409578Ssam if (t_flags&RAW) { 7419578Ssam /* 7429578Ssam * Raw mode, just put character 7439578Ssam * in input q w/o interpretation. 7449578Ssam */ 7459578Ssam if (tp->t_rawq.c_cc > TTYHOG) 74612752Ssam ttyflush(tp, FREAD|FWRITE); 7479578Ssam else { 7489578Ssam if (putc(c, &tp->t_rawq) >= 0) 7499578Ssam ttwakeup(tp); 7509578Ssam ttyecho(c, tp); 7517502Sroot } 7529578Ssam goto endcase; 7539578Ssam } 7549578Ssam 7559578Ssam /* 7569578Ssam * Ignore any high bit added during 7579578Ssam * previous ttyinput processing. 7589578Ssam */ 75924273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 7609578Ssam c &= 0177; 7619578Ssam /* 7629578Ssam * Check for literal nexting very first 7639578Ssam */ 7649578Ssam if (tp->t_state&TS_LNCH) { 7659578Ssam c |= 0200; 7669578Ssam tp->t_state &= ~TS_LNCH; 7679578Ssam } 7689578Ssam 7699578Ssam /* 7709578Ssam * Scan for special characters. This code 7719578Ssam * is really just a big case statement with 7729578Ssam * non-constant cases. The bottom of the 7739578Ssam * case statement is labeled ``endcase'', so goto 7749578Ssam * it after a case match, or similar. 7759578Ssam */ 7769578Ssam if (tp->t_line == NTTYDISC) { 7779578Ssam if (c == tp->t_lnextc) { 77821776Sbloom if (t_flags&ECHO) 7797502Sroot ttyout("^\b", tp); 7809578Ssam tp->t_state |= TS_LNCH; 7819578Ssam goto endcase; 7829578Ssam } 7839578Ssam if (c == tp->t_flushc) { 78421776Sbloom if (t_flags&FLUSHO) 7859578Ssam tp->t_flags &= ~FLUSHO; 7867502Sroot else { 78712752Ssam ttyflush(tp, FWRITE); 7887502Sroot ttyecho(c, tp); 7899578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7907502Sroot ttyretype(tp); 7919578Ssam tp->t_flags |= FLUSHO; 7927502Sroot } 7939578Ssam goto startoutput; 7949578Ssam } 7959578Ssam if (c == tp->t_suspc) { 79621776Sbloom if ((t_flags&NOFLSH) == 0) 79712752Ssam ttyflush(tp, FREAD); 7989578Ssam ttyecho(c, tp); 7999578Ssam gsignal(tp->t_pgrp, SIGTSTP); 8009578Ssam goto endcase; 8019578Ssam } 8029578Ssam } 8039578Ssam 8049578Ssam /* 8059578Ssam * Handle start/stop characters. 8069578Ssam */ 8079578Ssam if (c == tp->t_stopc) { 8089578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 8099578Ssam tp->t_state |= TS_TTSTOP; 8109578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 8117502Sroot return; 8129578Ssam } 8139578Ssam if (c != tp->t_startc) 8149578Ssam return; 8159578Ssam goto endcase; 8169578Ssam } 8179578Ssam if (c == tp->t_startc) 8189578Ssam goto restartoutput; 8199578Ssam 8209578Ssam /* 8219578Ssam * Look for interrupt/quit chars. 8229578Ssam */ 8239578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 82421776Sbloom if ((t_flags&NOFLSH) == 0) 82512752Ssam ttyflush(tp, FREAD|FWRITE); 8269578Ssam ttyecho(c, tp); 8279578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 8289578Ssam goto endcase; 8299578Ssam } 8309578Ssam 83123165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 83223165Sbloom if (tp->t_state&TS_BKSL) { 83323165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 83423165Sbloom if (maptab[c]) 83523165Sbloom c = maptab[c]; 83623165Sbloom c |= 0200; 83723165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 83823165Sbloom } else if (c >= 'A' && c <= 'Z') 83923165Sbloom c += 'a' - 'A'; 84023165Sbloom else if (c == '\\') 84123165Sbloom tp->t_state |= TS_BKSL; 84223165Sbloom } 84323165Sbloom 8449578Ssam /* 8459578Ssam * Cbreak mode, don't process line editing 8469578Ssam * characters; check high water mark for wakeup. 8479578Ssam */ 8489578Ssam if (t_flags&CBREAK) { 8499578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 8507502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 8517502Sroot tp->t_line == NTTYDISC) 8527502Sroot (void) ttyoutput(CTRL(g), tp); 8537502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 8547502Sroot ttwakeup(tp); 8557502Sroot ttyecho(c, tp); 8567502Sroot } 8579578Ssam goto endcase; 8589578Ssam } 8599578Ssam 8609578Ssam /* 8619578Ssam * From here on down cooked mode character 8629578Ssam * processing takes place. 8639578Ssam */ 8649578Ssam if ((tp->t_state&TS_QUOT) && 8659578Ssam (c == tp->t_erase || c == tp->t_kill)) { 8669578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8679578Ssam c |= 0200; 8689578Ssam } 8699578Ssam if (c == tp->t_erase) { 8709578Ssam if (tp->t_rawq.c_cc) 8719578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8729578Ssam goto endcase; 8739578Ssam } 8749578Ssam if (c == tp->t_kill) { 87521776Sbloom if (t_flags&CRTKIL && 8769578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8779578Ssam while (tp->t_rawq.c_cc) 8789578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8799578Ssam } else { 8809578Ssam ttyecho(c, tp); 8819578Ssam ttyecho('\n', tp); 8829578Ssam while (getc(&tp->t_rawq) > 0) 8839578Ssam ; 8849578Ssam tp->t_rocount = 0; 8859578Ssam } 8869578Ssam tp->t_state &= ~TS_LOCAL; 8879578Ssam goto endcase; 8889578Ssam } 8899578Ssam 8909578Ssam /* 8919578Ssam * New line discipline, 8929578Ssam * check word erase/reprint line. 8939578Ssam */ 8949578Ssam if (tp->t_line == NTTYDISC) { 8959578Ssam if (c == tp->t_werasc) { 8969578Ssam if (tp->t_rawq.c_cc == 0) 8979578Ssam goto endcase; 8989578Ssam do { 8999578Ssam c = unputc(&tp->t_rawq); 9009578Ssam if (c != ' ' && c != '\t') 9019578Ssam goto erasenb; 9029578Ssam ttyrub(c, tp); 9039578Ssam } while (tp->t_rawq.c_cc); 9049578Ssam goto endcase; 9059578Ssam erasenb: 9069578Ssam do { 9079578Ssam ttyrub(c, tp); 9089578Ssam if (tp->t_rawq.c_cc == 0) 9099578Ssam goto endcase; 9109578Ssam c = unputc(&tp->t_rawq); 9119578Ssam } while (c != ' ' && c != '\t'); 9129578Ssam (void) putc(c, &tp->t_rawq); 9139578Ssam goto endcase; 9149578Ssam } 9159578Ssam if (c == tp->t_rprntc) { 9169578Ssam ttyretype(tp); 9179578Ssam goto endcase; 9189578Ssam } 9199578Ssam } 9209578Ssam 9219578Ssam /* 9229578Ssam * Check for input buffer overflow 9239578Ssam */ 92410391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 92510391Ssam if (tp->t_line == NTTYDISC) 92610391Ssam (void) ttyoutput(CTRL(g), tp); 9279578Ssam goto endcase; 92810391Ssam } 9299578Ssam 9309578Ssam /* 9319578Ssam * Put data char in q for user and 9329578Ssam * wakeup on seeing a line delimiter. 9339578Ssam */ 9349578Ssam if (putc(c, &tp->t_rawq) >= 0) { 9359578Ssam if (ttbreakc(c, tp)) { 9369578Ssam tp->t_rocount = 0; 9379578Ssam catq(&tp->t_rawq, &tp->t_canq); 9387502Sroot ttwakeup(tp); 9399578Ssam } else if (tp->t_rocount++ == 0) 9409578Ssam tp->t_rocol = tp->t_col; 9419578Ssam tp->t_state &= ~TS_QUOT; 9429578Ssam if (c == '\\') 9439578Ssam tp->t_state |= TS_QUOT; 9449578Ssam if (tp->t_state&TS_ERASE) { 9459578Ssam tp->t_state &= ~TS_ERASE; 9469578Ssam (void) ttyoutput('/', tp); 9479578Ssam } 9489578Ssam i = tp->t_col; 9497502Sroot ttyecho(c, tp); 95021776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 9519578Ssam i = MIN(2, tp->t_col - i); 9529578Ssam while (i > 0) { 9539578Ssam (void) ttyoutput('\b', tp); 9549578Ssam i--; 9559578Ssam } 9569578Ssam } 9577502Sroot } 9589578Ssam endcase: 9599578Ssam /* 9609578Ssam * If DEC-style start/stop is enabled don't restart 9619578Ssam * output until seeing the start character. 9629578Ssam */ 96321776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 9649578Ssam tp->t_startc != tp->t_stopc) 9657502Sroot return; 9669578Ssam restartoutput: 9677502Sroot tp->t_state &= ~TS_TTSTOP; 9689578Ssam tp->t_flags &= ~FLUSHO; 9699578Ssam startoutput: 9707502Sroot ttstart(tp); 9717502Sroot } 9727502Sroot 9737502Sroot /* 9749578Ssam * Put character on TTY output queue, adding delays, 9757502Sroot * expanding tabs, and handling the CR/NL bit. 9769578Ssam * This is called both from the top half for output, 9779578Ssam * and from interrupt level for echoing. 9787502Sroot * The arguments are the character and the tty structure. 9797502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 9807502Sroot * Must be recursive. 9817502Sroot */ 9827502Sroot ttyoutput(c, tp) 9837502Sroot register c; 9847502Sroot register struct tty *tp; 9857502Sroot { 9867502Sroot register char *colp; 9877502Sroot register ctype; 9887502Sroot 9899578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9909578Ssam if (tp->t_flags&FLUSHO) 9917502Sroot return (-1); 9927502Sroot if (putc(c, &tp->t_outq)) 9937625Ssam return (c); 9947502Sroot tk_nout++; 9957502Sroot return (-1); 9967502Sroot } 9979578Ssam 9987502Sroot /* 9999578Ssam * Ignore EOT in normal mode to avoid 10009578Ssam * hanging up certain terminals. 10017502Sroot */ 10027502Sroot c &= 0177; 10039578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 10047502Sroot return (-1); 10057502Sroot /* 10067502Sroot * Turn tabs to spaces as required 10077502Sroot */ 10089578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 10097502Sroot register int s; 10107502Sroot 10117502Sroot c = 8 - (tp->t_col&7); 10129578Ssam if ((tp->t_flags&FLUSHO) == 0) { 101317545Skarels s = spltty(); /* don't interrupt tabs */ 10147502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10157502Sroot tk_nout += c; 10167502Sroot splx(s); 10177502Sroot } 10187502Sroot tp->t_col += c; 10197502Sroot return (c ? -1 : '\t'); 10207502Sroot } 10217502Sroot tk_nout++; 10227502Sroot /* 10237502Sroot * for upper-case-only terminals, 10247502Sroot * generate escapes. 10257502Sroot */ 10267502Sroot if (tp->t_flags&LCASE) { 10277502Sroot colp = "({)}!|^~'`"; 10287625Ssam while (*colp++) 10297625Ssam if (c == *colp++) { 10307502Sroot if (ttyoutput('\\', tp) >= 0) 10317502Sroot return (c); 10327502Sroot c = colp[-2]; 10337502Sroot break; 10347502Sroot } 10359578Ssam if ('A' <= c && c <= 'Z') { 10367502Sroot if (ttyoutput('\\', tp) >= 0) 10377502Sroot return (c); 10389578Ssam } else if ('a' <= c && c <= 'z') 10397502Sroot c += 'A' - 'a'; 10407502Sroot } 10419578Ssam 10427502Sroot /* 10437502Sroot * turn <nl> to <cr><lf> if desired. 10447502Sroot */ 10459578Ssam if (c == '\n' && tp->t_flags&CRMOD) 10467502Sroot if (ttyoutput('\r', tp) >= 0) 10477502Sroot return (c); 10489578Ssam if (c == '~' && tp->t_flags&TILDE) 10497502Sroot c = '`'; 10509578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 10517502Sroot return (c); 10527502Sroot /* 10537502Sroot * Calculate delays. 10547502Sroot * The numbers here represent clock ticks 10557502Sroot * and are not necessarily optimal for all terminals. 10567502Sroot * The delays are indicated by characters above 0200. 10577502Sroot * In raw mode there are no delays and the 10587502Sroot * transmission path is 8 bits wide. 10599578Ssam * 10609578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 10617502Sroot */ 10627502Sroot colp = &tp->t_col; 10637502Sroot ctype = partab[c]; 10647502Sroot c = 0; 10657502Sroot switch (ctype&077) { 10667502Sroot 10677502Sroot case ORDINARY: 10687502Sroot (*colp)++; 10697502Sroot 10707502Sroot case CONTROL: 10717502Sroot break; 10727502Sroot 10737502Sroot case BACKSPACE: 10747502Sroot if (*colp) 10757502Sroot (*colp)--; 10767502Sroot break; 10777502Sroot 107813821Ssam /* 107913821Ssam * This macro is close enough to the correct thing; 108013821Ssam * it should be replaced by real user settable delays 108113821Ssam * in any event... 108213821Ssam */ 108313821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10847502Sroot case NEWLINE: 10857502Sroot ctype = (tp->t_flags >> 8) & 03; 10867625Ssam if (ctype == 1) { /* tty 37 */ 108726357Skarels if (*colp > 0) { 108826357Skarels c = (((unsigned)*colp) >> 4) + 3; 108926357Skarels if ((unsigned)c > 6) 109026357Skarels c = 6; 109126357Skarels } 10929578Ssam } else if (ctype == 2) /* vt05 */ 109313821Ssam c = mstohz(100); 10947502Sroot *colp = 0; 10957502Sroot break; 10967502Sroot 10977502Sroot case TAB: 10987502Sroot ctype = (tp->t_flags >> 10) & 03; 10997625Ssam if (ctype == 1) { /* tty 37 */ 11007502Sroot c = 1 - (*colp | ~07); 11017625Ssam if (c < 5) 11027502Sroot c = 0; 11037502Sroot } 11047502Sroot *colp |= 07; 11057502Sroot (*colp)++; 11067502Sroot break; 11077502Sroot 11087502Sroot case VTAB: 11099578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11107502Sroot c = 0177; 11117502Sroot break; 11127502Sroot 11137502Sroot case RETURN: 11147502Sroot ctype = (tp->t_flags >> 12) & 03; 11159578Ssam if (ctype == 1) /* tn 300 */ 111613821Ssam c = mstohz(83); 11179578Ssam else if (ctype == 2) /* ti 700 */ 111813821Ssam c = mstohz(166); 11199578Ssam else if (ctype == 3) { /* concept 100 */ 11207502Sroot int i; 11219578Ssam 11227502Sroot if ((i = *colp) >= 0) 11239578Ssam for (; i < 9; i++) 11247502Sroot (void) putc(0177, &tp->t_outq); 11257502Sroot } 11267502Sroot *colp = 0; 11277502Sroot } 11289578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 11297502Sroot (void) putc(c|0200, &tp->t_outq); 11307502Sroot return (-1); 11317502Sroot } 113213821Ssam #undef mstohz 11337502Sroot 11347502Sroot /* 11357502Sroot * Called from device's read routine after it has 11367502Sroot * calculated the tty-structure given as argument. 11377502Sroot */ 11387722Swnj ttread(tp, uio) 11397625Ssam register struct tty *tp; 11407722Swnj struct uio *uio; 11417502Sroot { 11427502Sroot register struct clist *qp; 11439578Ssam register c, t_flags; 11449859Ssam int s, first, error = 0; 11457502Sroot 11467502Sroot loop: 11479578Ssam /* 11489578Ssam * Take any pending input first. 11499578Ssam */ 115017545Skarels s = spltty(); 11519578Ssam if (tp->t_flags&PENDIN) 11527502Sroot ttypend(tp); 11539859Ssam splx(s); 11549578Ssam 115523165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 115623165Sbloom return (EIO); 115723165Sbloom 11589578Ssam /* 11599578Ssam * Hang process if it's in the background. 11609578Ssam */ 116123165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 116224392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 116324392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11647502Sroot u.u_procp->p_flag&SVFORK) 11658520Sroot return (EIO); 11667502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11677502Sroot sleep((caddr_t)&lbolt, TTIPRI); 116823165Sbloom goto loop; 11697502Sroot } 11709578Ssam t_flags = tp->t_flags; 11719578Ssam 11729578Ssam /* 11739578Ssam * In raw mode take characters directly from the 11749578Ssam * raw queue w/o processing. Interlock against 11759578Ssam * device interrupts when interrogating rawq. 11769578Ssam */ 11779578Ssam if (t_flags&RAW) { 117817545Skarels s = spltty(); 11797502Sroot if (tp->t_rawq.c_cc <= 0) { 11809578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11817502Sroot (tp->t_state&TS_NBIO)) { 11829859Ssam splx(s); 118315094Skarels return (EWOULDBLOCK); 11847502Sroot } 11857502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11869859Ssam splx(s); 11877502Sroot goto loop; 11887502Sroot } 11899859Ssam splx(s); 119014938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 119114938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11929859Ssam goto checktandem; 11939578Ssam } 11949578Ssam 11959578Ssam /* 11969578Ssam * In cbreak mode use the rawq, otherwise 11979578Ssam * take characters from the canonicalized q. 11989578Ssam */ 11999578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 12009578Ssam 12019578Ssam /* 12029578Ssam * No input, sleep on rawq awaiting hardware 12039578Ssam * receipt and notification. 12049578Ssam */ 120517545Skarels s = spltty(); 12069578Ssam if (qp->c_cc <= 0) { 12079578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 12089578Ssam (tp->t_state&TS_NBIO)) { 12099859Ssam splx(s); 12109578Ssam return (EWOULDBLOCK); 12117502Sroot } 12129578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 12139859Ssam splx(s); 12149578Ssam goto loop; 12159578Ssam } 12169859Ssam splx(s); 12179578Ssam 12189578Ssam /* 12199578Ssam * Input present, perform input mapping 12209578Ssam * and processing (we're not in raw mode). 12219578Ssam */ 12229578Ssam first = 1; 12239578Ssam while ((c = getc(qp)) >= 0) { 12249578Ssam if (t_flags&CRMOD && c == '\r') 12259578Ssam c = '\n'; 12269578Ssam /* 12279578Ssam * Check for delayed suspend character. 12289578Ssam */ 12299578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 12309578Ssam gsignal(tp->t_pgrp, SIGTSTP); 12319578Ssam if (first) { 12329578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12339578Ssam goto loop; 12349578Ssam } 12359578Ssam break; 12367502Sroot } 12379578Ssam /* 12389578Ssam * Interpret EOF only in cooked mode. 12399578Ssam */ 12409578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12419578Ssam break; 12429578Ssam /* 12439578Ssam * Give user character. 12449578Ssam */ 124524273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12469578Ssam if (error) 12479578Ssam break; 124814938Smckusick if (uio->uio_resid == 0) 12499578Ssam break; 12509578Ssam /* 12519578Ssam * In cooked mode check for a "break character" 12529578Ssam * marking the end of a "line of input". 12539578Ssam */ 12549578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12559578Ssam break; 12569578Ssam first = 0; 12577502Sroot } 12589578Ssam 12599859Ssam checktandem: 12609578Ssam /* 12619578Ssam * Look to unblock output now that (presumably) 12629578Ssam * the input queue has gone down. 12639578Ssam */ 12649859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 12659578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 12667502Sroot tp->t_state &= ~TS_TBLOCK; 12677502Sroot ttstart(tp); 12687502Sroot } 12698520Sroot return (error); 12707502Sroot } 12717502Sroot 12727502Sroot /* 127325391Skarels * Check the output queue on tp for space for a kernel message 127425391Skarels * (from uprintf/tprintf). Allow some space over the normal 127525391Skarels * hiwater mark so we don't lose messages due to normal flow 127625391Skarels * control, but don't let the tty run amok. 127725391Skarels */ 127825391Skarels ttycheckoutq(tp, wait) 127925391Skarels register struct tty *tp; 128025391Skarels int wait; 128125391Skarels { 128225391Skarels int hiwat, s; 128325391Skarels 128425391Skarels hiwat = TTHIWAT(tp); 128525391Skarels s = spltty(); 128625391Skarels if (tp->t_outq.c_cc > hiwat + 200) 128729946Skarels while (tp->t_outq.c_cc > hiwat) { 128829946Skarels ttstart(tp); 128929946Skarels if (wait == 0) { 129029946Skarels splx(s); 129129946Skarels return (0); 129229946Skarels } 129329946Skarels tp->t_state |= TS_ASLEEP; 129429946Skarels sleep((caddr_t)&tp->t_outq, TTOPRI); 129525391Skarels } 129625391Skarels splx(s); 129725391Skarels return (1); 129825391Skarels } 129925391Skarels 130025391Skarels /* 13017502Sroot * Called from the device's write routine after it has 13027502Sroot * calculated the tty-structure given as argument. 13037502Sroot */ 13047822Sroot ttwrite(tp, uio) 13057625Ssam register struct tty *tp; 13069578Ssam register struct uio *uio; 13077502Sroot { 13087502Sroot register char *cp; 13099578Ssam register int cc, ce, c; 13109578Ssam int i, hiwat, cnt, error, s; 13117502Sroot char obuf[OBUFSIZ]; 13127502Sroot 13139578Ssam hiwat = TTHIWAT(tp); 13149578Ssam cnt = uio->uio_resid; 13159578Ssam error = 0; 13167502Sroot loop: 131721776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 131821776Sbloom return (EIO); 13199578Ssam /* 13209578Ssam * Hang the process if it's in the background. 13219578Ssam */ 132221776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 13239578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 132424392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 132524392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 13267502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 13277502Sroot sleep((caddr_t)&lbolt, TTIPRI); 132821776Sbloom goto loop; 13297502Sroot } 13309578Ssam 13319578Ssam /* 13329578Ssam * Process the user's data in at most OBUFSIZ 13339578Ssam * chunks. Perform lower case simulation and 13349578Ssam * similar hacks. Keep track of high water 13359578Ssam * mark, sleep on overflow awaiting device aid 13369578Ssam * in acquiring new space. 13379578Ssam */ 13387822Sroot while (uio->uio_resid > 0) { 13399578Ssam /* 13409578Ssam * Grab a hunk of data from the user. 13419578Ssam */ 13427822Sroot cc = uio->uio_iov->iov_len; 13437822Sroot if (cc == 0) { 13447822Sroot uio->uio_iovcnt--; 13457822Sroot uio->uio_iov++; 134621776Sbloom if (uio->uio_iovcnt <= 0) 13477822Sroot panic("ttwrite"); 13487822Sroot continue; 13497822Sroot } 13507822Sroot if (cc > OBUFSIZ) 13517822Sroot cc = OBUFSIZ; 13527502Sroot cp = obuf; 135312752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13548520Sroot if (error) 13557502Sroot break; 13567502Sroot if (tp->t_outq.c_cc > hiwat) 13577502Sroot goto ovhiwat; 13589578Ssam if (tp->t_flags&FLUSHO) 13597502Sroot continue; 13609578Ssam /* 13619578Ssam * If we're mapping lower case or kludging tildes, 13629578Ssam * then we've got to look at each character, so 13639578Ssam * just feed the stuff to ttyoutput... 13649578Ssam */ 13659578Ssam if (tp->t_flags & (LCASE|TILDE)) { 13669578Ssam while (cc > 0) { 13677502Sroot c = *cp++; 13687502Sroot tp->t_rocount = 0; 13697625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 13707502Sroot /* out of clists, wait a bit */ 13717502Sroot ttstart(tp); 13727502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13737502Sroot tp->t_rocount = 0; 137421776Sbloom if (cc != 0) { 137521776Sbloom uio->uio_iov->iov_base -= cc; 137621776Sbloom uio->uio_iov->iov_len += cc; 137721776Sbloom uio->uio_resid += cc; 137821776Sbloom uio->uio_offset -= cc; 137921776Sbloom } 138021776Sbloom goto loop; 13817502Sroot } 13827502Sroot --cc; 13837502Sroot if (tp->t_outq.c_cc > hiwat) 13847502Sroot goto ovhiwat; 13857502Sroot } 13867502Sroot continue; 13877502Sroot } 13889578Ssam /* 13899578Ssam * If nothing fancy need be done, grab those characters we 13909578Ssam * can handle without any of ttyoutput's processing and 13919578Ssam * just transfer them to the output q. For those chars 13929578Ssam * which require special processing (as indicated by the 13939578Ssam * bits in partab), call ttyoutput. After processing 13949578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13959578Ssam * immediately. 13969578Ssam */ 13979578Ssam while (cc > 0) { 13989578Ssam if (tp->t_flags & (RAW|LITOUT)) 13997502Sroot ce = cc; 14007502Sroot else { 140112752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 140212752Ssam (caddr_t)partab, 077); 14039578Ssam /* 14049578Ssam * If ce is zero, then we're processing 14059578Ssam * a special character through ttyoutput. 14069578Ssam */ 14079578Ssam if (ce == 0) { 14087502Sroot tp->t_rocount = 0; 14097502Sroot if (ttyoutput(*cp, tp) >= 0) { 141021776Sbloom /* no c-lists, wait a bit */ 141121776Sbloom ttstart(tp); 141221776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 141321776Sbloom if (cc != 0) { 141421776Sbloom uio->uio_iov->iov_base -= cc; 141521776Sbloom uio->uio_iov->iov_len += cc; 141621776Sbloom uio->uio_resid += cc; 141721776Sbloom uio->uio_offset -= cc; 141821776Sbloom } 141921776Sbloom goto loop; 14207502Sroot } 14219578Ssam cp++, cc--; 14229578Ssam if (tp->t_flags&FLUSHO || 14239578Ssam tp->t_outq.c_cc > hiwat) 14247502Sroot goto ovhiwat; 14259578Ssam continue; 14267502Sroot } 14277502Sroot } 14289578Ssam /* 14299578Ssam * A bunch of normal characters have been found, 14309578Ssam * transfer them en masse to the output queue and 14319578Ssam * continue processing at the top of the loop. 14329578Ssam * If there are any further characters in this 14339578Ssam * <= OBUFSIZ chunk, the first should be a character 14349578Ssam * requiring special handling by ttyoutput. 14359578Ssam */ 14367502Sroot tp->t_rocount = 0; 14379578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14389578Ssam ce -= i; 14399578Ssam tp->t_col += ce; 14409578Ssam cp += ce, cc -= ce, tk_nout += ce; 14419578Ssam if (i > 0) { 14429578Ssam /* out of c-lists, wait a bit */ 14437502Sroot ttstart(tp); 14447502Sroot sleep((caddr_t)&lbolt, TTOPRI); 144521776Sbloom uio->uio_iov->iov_base -= cc; 144621776Sbloom uio->uio_iov->iov_len += cc; 144721776Sbloom uio->uio_resid += cc; 144821776Sbloom uio->uio_offset -= cc; 144921776Sbloom goto loop; 14507502Sroot } 14519578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14527502Sroot goto ovhiwat; 14537502Sroot } 14547502Sroot } 14557502Sroot ttstart(tp); 14568520Sroot return (error); 14577502Sroot 14587502Sroot ovhiwat: 145917545Skarels s = spltty(); 14609578Ssam if (cc != 0) { 14619578Ssam uio->uio_iov->iov_base -= cc; 14629578Ssam uio->uio_iov->iov_len += cc; 14639578Ssam uio->uio_resid += cc; 14649578Ssam uio->uio_offset -= cc; 14659578Ssam } 14669578Ssam /* 14679578Ssam * This can only occur if FLUSHO 14689578Ssam * is also set in t_flags. 14699578Ssam */ 14707502Sroot if (tp->t_outq.c_cc <= hiwat) { 14719578Ssam splx(s); 14727502Sroot goto loop; 14737502Sroot } 14747502Sroot ttstart(tp); 14759578Ssam if (tp->t_state&TS_NBIO) { 147617545Skarels splx(s); 14777822Sroot if (uio->uio_resid == cnt) 14788520Sroot return (EWOULDBLOCK); 14798520Sroot return (0); 14807502Sroot } 14817502Sroot tp->t_state |= TS_ASLEEP; 14827502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14839578Ssam splx(s); 14847502Sroot goto loop; 14857502Sroot } 14867502Sroot 14877502Sroot /* 14887502Sroot * Rubout one character from the rawq of tp 14897502Sroot * as cleanly as possible. 14907502Sroot */ 14917502Sroot ttyrub(c, tp) 14927625Ssam register c; 14937625Ssam register struct tty *tp; 14947502Sroot { 14957502Sroot register char *cp; 14967502Sroot register int savecol; 14977502Sroot int s; 14987502Sroot char *nextc(); 14997502Sroot 15009578Ssam if ((tp->t_flags&ECHO) == 0) 15017502Sroot return; 15029578Ssam tp->t_flags &= ~FLUSHO; 15037502Sroot c &= 0377; 15049578Ssam if (tp->t_flags&CRTBS) { 15057502Sroot if (tp->t_rocount == 0) { 15067502Sroot /* 15077502Sroot * Screwed by ttwrite; retype 15087502Sroot */ 15097502Sroot ttyretype(tp); 15107502Sroot return; 15117502Sroot } 15129578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 15137502Sroot ttyrubo(tp, 2); 15149578Ssam else switch (partab[c&=0177]&0177) { 15157502Sroot 15167502Sroot case ORDINARY: 15177502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 15187502Sroot ttyrubo(tp, 2); 15197502Sroot else 15207502Sroot ttyrubo(tp, 1); 15217502Sroot break; 15227502Sroot 15237502Sroot case VTAB: 15247502Sroot case BACKSPACE: 15257502Sroot case CONTROL: 15267502Sroot case RETURN: 15279578Ssam if (tp->t_flags&CTLECH) 15287502Sroot ttyrubo(tp, 2); 15297502Sroot break; 15307502Sroot 15317502Sroot case TAB: 15327502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15337502Sroot ttyretype(tp); 15347502Sroot return; 15357502Sroot } 153617545Skarels s = spltty(); 15377502Sroot savecol = tp->t_col; 15389578Ssam tp->t_state |= TS_CNTTB; 15399578Ssam tp->t_flags |= FLUSHO; 15407502Sroot tp->t_col = tp->t_rocol; 15419578Ssam cp = tp->t_rawq.c_cf; 15429578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 15437502Sroot ttyecho(*cp, tp); 15449578Ssam tp->t_flags &= ~FLUSHO; 15459578Ssam tp->t_state &= ~TS_CNTTB; 15467502Sroot splx(s); 15477502Sroot /* 15487502Sroot * savecol will now be length of the tab 15497502Sroot */ 15507502Sroot savecol -= tp->t_col; 15517502Sroot tp->t_col += savecol; 15527502Sroot if (savecol > 8) 15537502Sroot savecol = 8; /* overflow screw */ 15547502Sroot while (--savecol >= 0) 15557502Sroot (void) ttyoutput('\b', tp); 15567502Sroot break; 15577502Sroot 15587502Sroot default: 15597502Sroot panic("ttyrub"); 15607502Sroot } 15619578Ssam } else if (tp->t_flags&PRTERA) { 15629578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15637502Sroot (void) ttyoutput('\\', tp); 15649578Ssam tp->t_state |= TS_ERASE; 15657502Sroot } 15667502Sroot ttyecho(c, tp); 15677502Sroot } else 15687502Sroot ttyecho(tp->t_erase, tp); 15697502Sroot tp->t_rocount--; 15707502Sroot } 15717502Sroot 15727502Sroot /* 15737502Sroot * Crt back over cnt chars perhaps 15747502Sroot * erasing them. 15757502Sroot */ 15767502Sroot ttyrubo(tp, cnt) 15777625Ssam register struct tty *tp; 15787625Ssam int cnt; 15797502Sroot { 15809578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 15817502Sroot 15827502Sroot while (--cnt >= 0) 15839578Ssam ttyout(rubostring, tp); 15847502Sroot } 15857502Sroot 15867502Sroot /* 15877502Sroot * Reprint the rawq line. 15887502Sroot * We assume c_cc has already been checked. 15897502Sroot */ 15907502Sroot ttyretype(tp) 15917625Ssam register struct tty *tp; 15927502Sroot { 15937502Sroot register char *cp; 15947502Sroot char *nextc(); 15957502Sroot int s; 15967502Sroot 15979578Ssam if (tp->t_rprntc != 0377) 15989578Ssam ttyecho(tp->t_rprntc, tp); 15997502Sroot (void) ttyoutput('\n', tp); 160017545Skarels s = spltty(); 16017502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 16027502Sroot ttyecho(*cp, tp); 16037502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 16047502Sroot ttyecho(*cp, tp); 16059578Ssam tp->t_state &= ~TS_ERASE; 16067502Sroot splx(s); 16077502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16087502Sroot tp->t_rocol = 0; 16097502Sroot } 16107502Sroot 16117502Sroot /* 16127502Sroot * Echo a typed character to the terminal 16137502Sroot */ 16147502Sroot ttyecho(c, tp) 16157625Ssam register c; 16167625Ssam register struct tty *tp; 16177502Sroot { 16187502Sroot 16199578Ssam if ((tp->t_state&TS_CNTTB) == 0) 16209578Ssam tp->t_flags &= ~FLUSHO; 16217502Sroot if ((tp->t_flags&ECHO) == 0) 16227502Sroot return; 16237502Sroot c &= 0377; 16247502Sroot if (tp->t_flags&RAW) { 16257502Sroot (void) ttyoutput(c, tp); 16267502Sroot return; 16277502Sroot } 16287502Sroot if (c == '\r' && tp->t_flags&CRMOD) 16297502Sroot c = '\n'; 16309578Ssam if (tp->t_flags&CTLECH) { 16317502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 16327502Sroot (void) ttyoutput('^', tp); 16337502Sroot c &= 0177; 16347502Sroot if (c == 0177) 16357502Sroot c = '?'; 16367502Sroot else if (tp->t_flags&LCASE) 16377502Sroot c += 'a' - 1; 16387502Sroot else 16397502Sroot c += 'A' - 1; 16407502Sroot } 16417502Sroot } 16429578Ssam (void) ttyoutput(c&0177, tp); 16437502Sroot } 16447502Sroot 16457502Sroot /* 16467502Sroot * Is c a break char for tp? 16477502Sroot */ 16487502Sroot ttbreakc(c, tp) 16497625Ssam register c; 16507625Ssam register struct tty *tp; 16517502Sroot { 16529578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 16537502Sroot c == '\r' && (tp->t_flags&CRMOD)); 16547502Sroot } 16557502Sroot 16567502Sroot /* 16577502Sroot * send string cp to tp 16587502Sroot */ 16597502Sroot ttyout(cp, tp) 16607625Ssam register char *cp; 16617625Ssam register struct tty *tp; 16627502Sroot { 16637502Sroot register char c; 16647502Sroot 16657502Sroot while (c = *cp++) 16667502Sroot (void) ttyoutput(c, tp); 16677502Sroot } 16687502Sroot 16697502Sroot ttwakeup(tp) 16707502Sroot struct tty *tp; 16717502Sroot { 16727502Sroot 16737502Sroot if (tp->t_rsel) { 16747502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16757502Sroot tp->t_state &= ~TS_RCOLL; 16767502Sroot tp->t_rsel = 0; 16777502Sroot } 167812752Ssam if (tp->t_state & TS_ASYNC) 167912752Ssam gsignal(tp->t_pgrp, SIGIO); 16807502Sroot wakeup((caddr_t)&tp->t_rawq); 16817502Sroot } 1682