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*34492Skarels * @(#)tty.c 7.12 (Berkeley) 05/26/88 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 "file.h" 1917095Sbloom #include "conf.h" 2029946Skarels #include "dkstat.h" 2117095Sbloom #include "uio.h" 2217095Sbloom #include "kernel.h" 2339Sbill 247436Skre /* 257436Skre * Table giving parity for characters and indicating 267436Skre * character classes to tty driver. In particular, 277436Skre * if the low 6 bits are 0, then the character needs 287436Skre * no special processing on output. 297436Skre */ 3039Sbill 317436Skre char partab[] = { 327436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 337436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 347436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 357436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 367436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 377436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 387436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 397436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 407436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 417436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 427436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 437436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 447436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 457436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 467436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 477436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 487436Skre 497436Skre /* 507436Skre * 7 bit ascii ends with the last character above, 517436Skre * but we contine through all 256 codes for the sake 527436Skre * of the tty output routines which use special vax 537436Skre * instructions which need a 256 character trt table. 547436Skre */ 557436Skre 567436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 577436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 687436Skre 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 }; 737436Skre 74146Sbill /* 7539Sbill * Input mapping table-- if an entry is non-zero, when the 7639Sbill * corresponding character is typed preceded by "\" the escape 7739Sbill * sequence is replaced by the table value. Mostly used for 7839Sbill * upper-case only terminals. 7939Sbill */ 8039Sbill char maptab[] ={ 8139Sbill 000,000,000,000,000,000,000,000, 8239Sbill 000,000,000,000,000,000,000,000, 8339Sbill 000,000,000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,'|',000,000,000,000,000,'`', 8639Sbill '{','}',000,000,000,000,000,000, 8739Sbill 000,000,000,000,000,000,000,000, 8839Sbill 000,000,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, 9339Sbill 000,'A','B','C','D','E','F','G', 9439Sbill 'H','I','J','K','L','M','N','O', 9539Sbill 'P','Q','R','S','T','U','V','W', 9639Sbill 'X','Y','Z',000,000,000,000,000, 9739Sbill }; 9839Sbill 99925Sbill short tthiwat[16] = 1008954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 101925Sbill short ttlowat[16] = 102925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 103925Sbill 104*34492Skarels struct ttychars ttydefaults = { 105*34492Skarels CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 106*34492Skarels CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 107*34492Skarels }; 108*34492Skarels 10930534Skarels extern struct tty *constty; /* temporary virtual console */ 11030534Skarels 11139Sbill ttychars(tp) 1129578Ssam struct tty *tp; 11339Sbill { 114*34492Skarels 115*34492Skarels 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) && 13532336Smckusick tp->t_state&TS_CARR_ON && tp->t_oproc) { 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 && 192*34492Skarels ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) { 193*34492Skarels 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 { 22539Sbill 22632067Skarels if (tp->t_oproc) /* kludge for pty */ 227903Sbill (*tp->t_oproc)(tp); 22839Sbill } 22939Sbill 23039Sbill /* 231903Sbill * Common code for tty ioctls. 23239Sbill */ 2331780Sbill /*ARGSUSED*/ 2347625Ssam ttioctl(tp, com, data, flag) 2357625Ssam register struct tty *tp; 2367625Ssam caddr_t data; 23739Sbill { 238*34492Skarels int dev = tp->t_dev; 23939Sbill extern int nldisp; 2408556Sroot int s; 241*34492Skarels register int newflags; 24239Sbill 24330534Skarels 244903Sbill /* 245903Sbill * If the ioctl involves modification, 24617545Skarels * hang if in the background. 247903Sbill */ 2487625Ssam switch (com) { 24939Sbill 250*34492Skarels case TIOCSETD: 251*34492Skarels case TIOCSETP: 252*34492Skarels case TIOCSETN: 253903Sbill case TIOCFLUSH: 254*34492Skarels case TIOCSETC: 255*34492Skarels case TIOCSLTC: 256903Sbill case TIOCSPGRP: 257*34492Skarels case TIOCLBIS: 258*34492Skarels case TIOCLBIC: 259*34492Skarels case TIOCLSET: 2609325Ssam case TIOCSTI: 26117598Sbloom case TIOCSWINSZ: 262*34492Skarels while (tp->t_line == NTTYDISC && 263903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 264903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 26524392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 26624392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 267903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 268903Sbill sleep((caddr_t)&lbolt, TTOPRI); 269903Sbill } 270903Sbill break; 271903Sbill } 272903Sbill 2739578Ssam /* 2749578Ssam * Process the ioctl. 2759578Ssam */ 2767625Ssam switch (com) { 277903Sbill 2788556Sroot /* get discipline number */ 27939Sbill case TIOCGETD: 2807625Ssam *(int *)data = tp->t_line; 28139Sbill break; 28239Sbill 2838556Sroot /* set line discipline */ 2847625Ssam case TIOCSETD: { 2857625Ssam register int t = *(int *)data; 2869578Ssam int error = 0; 2877625Ssam 28815078Skarels if ((unsigned) t >= nldisp) 28910851Ssam return (ENXIO); 29025584Skarels if (t != tp->t_line) { 29125584Skarels s = spltty(); 29225584Skarels (*linesw[tp->t_line].l_close)(tp); 29325584Skarels error = (*linesw[t].l_open)(dev, tp); 29425584Skarels if (error) { 295*34492Skarels (void) (*linesw[tp->t_line].l_open)(dev, tp); 29625584Skarels splx(s); 29725584Skarels return (error); 29825584Skarels } 29925584Skarels tp->t_line = t; 30010851Ssam splx(s); 30110851Ssam } 30239Sbill break; 3037625Ssam } 30439Sbill 3058556Sroot /* prevent more opens on channel */ 3065614Swnj case TIOCEXCL: 3075614Swnj tp->t_state |= TS_XCLUDE; 3085614Swnj break; 3095614Swnj 3105614Swnj case TIOCNXCL: 3115614Swnj tp->t_state &= ~TS_XCLUDE; 3125614Swnj break; 3135614Swnj 314*34492Skarels /* hang up line on last close */ 31539Sbill case TIOCHPCL: 316*34492Skarels tp->t_state |= TS_HUPCLS; 31739Sbill break; 31839Sbill 3193942Sbugs case TIOCFLUSH: { 3207625Ssam register int flags = *(int *)data; 3217625Ssam 3227625Ssam if (flags == 0) 3233942Sbugs flags = FREAD|FWRITE; 3247625Ssam else 3257625Ssam flags &= FREAD|FWRITE; 32612752Ssam ttyflush(tp, flags); 32739Sbill break; 3283944Sbugs } 32939Sbill 3308556Sroot /* return number of characters immediately available */ 3317625Ssam case FIONREAD: 3327625Ssam *(off_t *)data = ttnread(tp); 333174Sbill break; 334174Sbill 33513077Ssam case TIOCOUTQ: 33613077Ssam *(int *)data = tp->t_outq.c_cc; 33713077Ssam break; 33813077Ssam 3398589Sroot case TIOCSTOP: 34017545Skarels s = spltty(); 3419578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3425573Swnj tp->t_state |= TS_TTSTOP; 3435573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3445573Swnj } 3457625Ssam splx(s); 3465573Swnj break; 3475573Swnj 3488589Sroot case TIOCSTART: 34917545Skarels s = spltty(); 350*34492Skarels if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3515573Swnj tp->t_state &= ~TS_TTSTOP; 352*34492Skarels tp->t_flags &= ~FLUSHO; 3535573Swnj ttstart(tp); 3545573Swnj } 3557625Ssam splx(s); 3565573Swnj break; 3575573Swnj 3589325Ssam /* 3599325Ssam * Simulate typing of a character at the terminal. 3609325Ssam */ 3619325Ssam case TIOCSTI: 36217183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36317183Smckusick return (EPERM); 3649325Ssam if (u.u_uid && u.u_ttyp != tp) 3659325Ssam return (EACCES); 3669578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3679325Ssam break; 3689325Ssam 369*34492Skarels case TIOCSETP: 370*34492Skarels case TIOCSETN: { 371*34492Skarels register struct sgttyb *sg = (struct sgttyb *)data; 37212752Ssam 373*34492Skarels tp->t_erase = sg->sg_erase; 374*34492Skarels tp->t_kill = sg->sg_kill; 375*34492Skarels tp->t_ispeed = sg->sg_ispeed; 376*34492Skarels tp->t_ospeed = sg->sg_ospeed; 377*34492Skarels newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37817545Skarels s = spltty(); 379*34492Skarels if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 380*34492Skarels ttywait(tp); 381*34492Skarels ttyflush(tp, FREAD); 382*34492Skarels } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 383*34492Skarels if (newflags&CBREAK) { 384*34492Skarels struct clist tq; 38512752Ssam 386*34492Skarels catq(&tp->t_rawq, &tp->t_canq); 387*34492Skarels tq = tp->t_rawq; 388*34492Skarels tp->t_rawq = tp->t_canq; 389*34492Skarels tp->t_canq = tq; 390*34492Skarels } else { 391*34492Skarels tp->t_flags |= PENDIN; 392*34492Skarels newflags |= PENDIN; 393*34492Skarels ttwakeup(tp); 394*34492Skarels } 39512752Ssam } 396*34492Skarels tp->t_flags = newflags; 397*34492Skarels if (tp->t_flags&RAW) { 398*34492Skarels tp->t_state &= ~TS_TTSTOP; 399*34492Skarels ttstart(tp); 40012752Ssam } 40112752Ssam splx(s); 40212752Ssam break; 40312752Ssam } 40412752Ssam 405*34492Skarels /* send current parameters to user */ 406*34492Skarels case TIOCGETP: { 407*34492Skarels register struct sgttyb *sg = (struct sgttyb *)data; 408*34492Skarels 409*34492Skarels sg->sg_ispeed = tp->t_ispeed; 410*34492Skarels sg->sg_ospeed = tp->t_ospeed; 411*34492Skarels sg->sg_erase = tp->t_erase; 412*34492Skarels sg->sg_kill = tp->t_kill; 413*34492Skarels sg->sg_flags = tp->t_flags; 41412752Ssam break; 415*34492Skarels } 41612752Ssam 41712752Ssam case FIONBIO: 41812752Ssam if (*(int *)data) 41912752Ssam tp->t_state |= TS_NBIO; 42012752Ssam else 42112752Ssam tp->t_state &= ~TS_NBIO; 42212752Ssam break; 42312752Ssam 42412752Ssam case FIOASYNC: 42512752Ssam if (*(int *)data) 42612752Ssam tp->t_state |= TS_ASYNC; 42712752Ssam else 42812752Ssam tp->t_state &= ~TS_ASYNC; 42912752Ssam break; 43012752Ssam 431*34492Skarels case TIOCGETC: 432*34492Skarels bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 433*34492Skarels break; 43413077Ssam 435*34492Skarels case TIOCSETC: 436*34492Skarels bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 437*34492Skarels break; 438*34492Skarels 439*34492Skarels /* set/get local special characters */ 440*34492Skarels case TIOCSLTC: 441*34492Skarels bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 442*34492Skarels break; 443*34492Skarels 444*34492Skarels case TIOCGLTC: 445*34492Skarels bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 446*34492Skarels break; 447*34492Skarels 44812752Ssam /* 449*34492Skarels * Modify local mode word. 450*34492Skarels */ 451*34492Skarels case TIOCLBIS: 452*34492Skarels tp->t_flags |= *(int *)data << 16; 453*34492Skarels break; 454*34492Skarels 455*34492Skarels case TIOCLBIC: 456*34492Skarels tp->t_flags &= ~(*(int *)data << 16); 457*34492Skarels break; 458*34492Skarels 459*34492Skarels case TIOCLSET: 460*34492Skarels tp->t_flags &= 0xffff; 461*34492Skarels tp->t_flags |= *(int *)data << 16; 462*34492Skarels break; 463*34492Skarels 464*34492Skarels case TIOCLGET: 465*34492Skarels *(int *)data = ((unsigned)tp->t_flags) >> 16; 466*34492Skarels break; 467*34492Skarels 468*34492Skarels /* 46917932Skarels * Allow SPGRP only if tty is open for reading. 47017598Sbloom * Quick check: if we can find a process in the new pgrp, 47117598Sbloom * this user must own that process. 47217598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47317545Skarels */ 47418650Sbloom case TIOCSPGRP: { 47517545Skarels struct proc *p; 47617545Skarels int pgrp = *(int *)data; 47717545Skarels 47817545Skarels if (u.u_uid && (flag & FREAD) == 0) 47917545Skarels return (EPERM); 48017598Sbloom p = pfind(pgrp); 48117598Sbloom if (p && p->p_pgrp == pgrp && 48217598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48317598Sbloom return (EPERM); 48417545Skarels tp->t_pgrp = pgrp; 48512752Ssam break; 48618650Sbloom } 48712752Ssam 48812752Ssam case TIOCGPGRP: 48912752Ssam *(int *)data = tp->t_pgrp; 49012752Ssam break; 49112752Ssam 49217598Sbloom case TIOCSWINSZ: 49318650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 49418650Sbloom sizeof (struct winsize))) { 49517598Sbloom tp->t_winsize = *(struct winsize *)data; 49617598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 49717598Sbloom } 49817598Sbloom break; 49917598Sbloom 50017598Sbloom case TIOCGWINSZ: 50117598Sbloom *(struct winsize *)data = tp->t_winsize; 50217598Sbloom break; 50317598Sbloom 50430534Skarels case TIOCCONS: 50530534Skarels if (*(int *)data) { 50630534Skarels if (constty != NULL) 50730534Skarels return (EBUSY); 50830534Skarels #ifndef UCONSOLE 50930534Skarels if (!suser()) 51030534Skarels return (EPERM); 51130534Skarels #endif 51230534Skarels constty = tp; 51330534Skarels } else if (tp == constty) 51433404Skarels constty = NULL; 51530534Skarels break; 51630534Skarels 51739Sbill default: 5188556Sroot return (-1); 51939Sbill } 5208556Sroot return (0); 52139Sbill } 5224484Swnj 5234484Swnj ttnread(tp) 5244484Swnj struct tty *tp; 5254484Swnj { 5264484Swnj int nread = 0; 5274484Swnj 528*34492Skarels if (tp->t_flags & PENDIN) 5294484Swnj ttypend(tp); 5304484Swnj nread = tp->t_canq.c_cc; 531*34492Skarels if (tp->t_flags & (RAW|CBREAK)) 5324484Swnj nread += tp->t_rawq.c_cc; 5334484Swnj return (nread); 5344484Swnj } 5354484Swnj 5365408Swnj ttselect(dev, rw) 5374484Swnj dev_t dev; 5385408Swnj int rw; 5394484Swnj { 5404484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5414484Swnj int nread; 54217545Skarels int s = spltty(); 5434484Swnj 5445408Swnj switch (rw) { 5454484Swnj 5464484Swnj case FREAD: 5474484Swnj nread = ttnread(tp); 54829946Skarels if (nread > 0 || (tp->t_state & TS_CARR_ON) == 0) 5495408Swnj goto win; 5504938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5515408Swnj tp->t_state |= TS_RCOLL; 5524484Swnj else 5534484Swnj tp->t_rsel = u.u_procp; 5545408Swnj break; 5554484Swnj 5565408Swnj case FWRITE: 5575408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5585408Swnj goto win; 5595408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5605408Swnj tp->t_state |= TS_WCOLL; 5615408Swnj else 5625408Swnj tp->t_wsel = u.u_procp; 5635408Swnj break; 5644484Swnj } 5655408Swnj splx(s); 5665408Swnj return (0); 5675408Swnj win: 5685408Swnj splx(s); 5695408Swnj return (1); 5704484Swnj } 5717436Skre 5727502Sroot /* 57325391Skarels * Initial open of tty, or (re)entry to line discipline. 5749578Ssam * Establish a process group for distribution of 5757502Sroot * quits and interrupts from the tty. 5767502Sroot */ 5777502Sroot ttyopen(dev, tp) 5787625Ssam dev_t dev; 5797625Ssam register struct tty *tp; 5807502Sroot { 5817502Sroot register struct proc *pp; 5827502Sroot 5837502Sroot pp = u.u_procp; 5847502Sroot tp->t_dev = dev; 585*34492Skarels if (pp->p_pgrp == 0) { 5867502Sroot u.u_ttyp = tp; 5877502Sroot u.u_ttyd = dev; 5887502Sroot if (tp->t_pgrp == 0) 5897502Sroot tp->t_pgrp = pp->p_pid; 5907502Sroot pp->p_pgrp = tp->t_pgrp; 5917502Sroot } 5927502Sroot tp->t_state &= ~TS_WOPEN; 59317545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 59417545Skarels tp->t_state |= TS_ISOPEN; 59517598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 596*34492Skarels if (tp->t_line != NTTYDISC) 597*34492Skarels ttywflush(tp); 59817545Skarels } 5998556Sroot return (0); 6007502Sroot } 6017502Sroot 6027502Sroot /* 60325391Skarels * "close" a line discipline 60425391Skarels */ 60525391Skarels ttylclose(tp) 60625391Skarels register struct tty *tp; 60725391Skarels { 60825391Skarels 60925391Skarels ttywflush(tp); 610*34492Skarels tp->t_line = 0; 61125391Skarels } 61225391Skarels 61325391Skarels /* 6147502Sroot * clean tp on last close 6157502Sroot */ 6167502Sroot ttyclose(tp) 6177625Ssam register struct tty *tp; 6187502Sroot { 6197502Sroot 62030534Skarels if (constty == tp) 62130534Skarels constty = NULL; 62225391Skarels ttyflush(tp, FREAD|FWRITE); 6237502Sroot tp->t_pgrp = 0; 6247502Sroot tp->t_state = 0; 6257502Sroot } 6267502Sroot 6277502Sroot /* 62825391Skarels * Handle modem control transition on a tty. 62925391Skarels * Flag indicates new state of carrier. 63025391Skarels * Returns 0 if the line should be turned off, otherwise 1. 63125391Skarels */ 63225391Skarels ttymodem(tp, flag) 63325391Skarels register struct tty *tp; 63425391Skarels { 63525391Skarels 636*34492Skarels if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { 63725391Skarels /* 63825391Skarels * MDMBUF: do flow control according to carrier flag 63925391Skarels */ 64025391Skarels if (flag) { 64125391Skarels tp->t_state &= ~TS_TTSTOP; 64225391Skarels ttstart(tp); 64325391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 64425391Skarels tp->t_state |= TS_TTSTOP; 64525391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 64625391Skarels } 64725391Skarels } else if (flag == 0) { 64825391Skarels /* 64925391Skarels * Lost carrier. 65025391Skarels */ 65125391Skarels tp->t_state &= ~TS_CARR_ON; 65225391Skarels if (tp->t_state & TS_ISOPEN) { 653*34492Skarels if ((tp->t_flags & NOHANG) == 0) { 65425391Skarels gsignal(tp->t_pgrp, SIGHUP); 65525391Skarels gsignal(tp->t_pgrp, SIGCONT); 65625391Skarels ttyflush(tp, FREAD|FWRITE); 65725391Skarels return (0); 65825391Skarels } 65925391Skarels } 66025391Skarels } else { 66125391Skarels /* 66225391Skarels * Carrier now on. 66325391Skarels */ 66425391Skarels tp->t_state |= TS_CARR_ON; 66525391Skarels wakeup((caddr_t)&tp->t_rawq); 66625391Skarels } 66725391Skarels return (1); 66825391Skarels } 66925391Skarels 67025391Skarels /* 67125404Skarels * Default modem control routine (for other line disciplines). 67225404Skarels * Return argument flag, to turn off device on carrier drop. 67325404Skarels */ 67425415Skarels nullmodem(tp, flag) 67525415Skarels register struct tty *tp; 67625404Skarels int flag; 67725404Skarels { 67825404Skarels 67925404Skarels if (flag) 68025404Skarels tp->t_state |= TS_CARR_ON; 68125404Skarels else 68225404Skarels tp->t_state &= ~TS_CARR_ON; 68325404Skarels return (flag); 68425404Skarels } 68525404Skarels 68625404Skarels /* 6877502Sroot * reinput pending characters after state switch 68817545Skarels * call at spltty(). 6897502Sroot */ 6907502Sroot ttypend(tp) 6917625Ssam register struct tty *tp; 6927502Sroot { 6937502Sroot struct clist tq; 6947502Sroot register c; 6957502Sroot 696*34492Skarels tp->t_flags &= ~PENDIN; 6979578Ssam tp->t_state |= TS_TYPEN; 6987502Sroot tq = tp->t_rawq; 6997502Sroot tp->t_rawq.c_cc = 0; 7007502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7017502Sroot while ((c = getc(&tq)) >= 0) 7027502Sroot ttyinput(c, tp); 7039578Ssam tp->t_state &= ~TS_TYPEN; 7047502Sroot } 7057502Sroot 7067502Sroot /* 7079578Ssam * Place a character on raw TTY input queue, 7089578Ssam * putting in delimiters and waking up top 7099578Ssam * half as needed. Also echo if required. 7109578Ssam * The arguments are the character and the 7119578Ssam * appropriate tty structure. 7127502Sroot */ 7137502Sroot ttyinput(c, tp) 7147625Ssam register c; 7157625Ssam register struct tty *tp; 7167502Sroot { 717*34492Skarels register int t_flags = tp->t_flags; 718*34492Skarels int i; 7197502Sroot 7209578Ssam /* 7219578Ssam * If input is pending take it first. 7229578Ssam */ 723*34492Skarels if (t_flags&PENDIN) 7247502Sroot ttypend(tp); 7257502Sroot tk_nin++; 726*34492Skarels c &= 0377; 7279578Ssam 7289578Ssam /* 729*34492Skarels * In tandem mode, check high water mark. 7309578Ssam */ 731*34492Skarels if (t_flags&TANDEM) 732*34492Skarels ttyblock(tp); 733*34492Skarels 734*34492Skarels if (t_flags&RAW) { 735*34492Skarels /* 736*34492Skarels * Raw mode, just put character 737*34492Skarels * in input q w/o interpretation. 738*34492Skarels */ 739*34492Skarels if (tp->t_rawq.c_cc > TTYHOG) 740*34492Skarels ttyflush(tp, FREAD|FWRITE); 741*34492Skarels else { 742*34492Skarels if (putc(c, &tp->t_rawq) >= 0) 743*34492Skarels ttwakeup(tp); 744*34492Skarels ttyecho(c, tp); 7457502Sroot } 746*34492Skarels goto endcase; 7479578Ssam } 7489578Ssam 7499578Ssam /* 7509578Ssam * Ignore any high bit added during 7519578Ssam * previous ttyinput processing. 7529578Ssam */ 753*34492Skarels if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 7549578Ssam c &= 0177; 7559578Ssam /* 7569578Ssam * Check for literal nexting very first 7579578Ssam */ 7589578Ssam if (tp->t_state&TS_LNCH) { 7599578Ssam c |= 0200; 7609578Ssam tp->t_state &= ~TS_LNCH; 7619578Ssam } 7629578Ssam 7639578Ssam /* 7649578Ssam * Scan for special characters. This code 7659578Ssam * is really just a big case statement with 7669578Ssam * non-constant cases. The bottom of the 7679578Ssam * case statement is labeled ``endcase'', so goto 7689578Ssam * it after a case match, or similar. 7699578Ssam */ 770*34492Skarels if (tp->t_line == NTTYDISC) { 771*34492Skarels if (c == tp->t_lnextc) { 772*34492Skarels if (t_flags&ECHO) 773*34492Skarels ttyout("^\b", tp); 7749578Ssam tp->t_state |= TS_LNCH; 7759578Ssam goto endcase; 7769578Ssam } 777*34492Skarels if (c == tp->t_flushc) { 778*34492Skarels if (t_flags&FLUSHO) 779*34492Skarels tp->t_flags &= ~FLUSHO; 7807502Sroot else { 78112752Ssam ttyflush(tp, FWRITE); 7827502Sroot ttyecho(c, tp); 7839578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7847502Sroot ttyretype(tp); 785*34492Skarels tp->t_flags |= FLUSHO; 7867502Sroot } 7879578Ssam goto startoutput; 7889578Ssam } 789*34492Skarels if (c == tp->t_suspc) { 790*34492Skarels if ((t_flags&NOFLSH) == 0) 79112752Ssam ttyflush(tp, FREAD); 7929578Ssam ttyecho(c, tp); 7939578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7949578Ssam goto endcase; 7959578Ssam } 7969578Ssam } 7979578Ssam 7989578Ssam /* 7999578Ssam * Handle start/stop characters. 8009578Ssam */ 801*34492Skarels if (c == tp->t_stopc) { 802*34492Skarels if ((tp->t_state&TS_TTSTOP) == 0) { 803*34492Skarels tp->t_state |= TS_TTSTOP; 804*34492Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 805*34492Skarels return; 8069578Ssam } 807*34492Skarels if (c != tp->t_startc) 808*34492Skarels return; 809*34492Skarels goto endcase; 8109578Ssam } 811*34492Skarels if (c == tp->t_startc) 812*34492Skarels goto restartoutput; 8139578Ssam 8149578Ssam /* 815*34492Skarels * Look for interrupt/quit chars. 8169578Ssam */ 817*34492Skarels if (c == tp->t_intrc || c == tp->t_quitc) { 818*34492Skarels if ((t_flags&NOFLSH) == 0) 819*34492Skarels ttyflush(tp, FREAD|FWRITE); 820*34492Skarels ttyecho(c, tp); 821*34492Skarels gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 822*34492Skarels goto endcase; 8239578Ssam } 8249578Ssam 82523165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 82623165Sbloom if (tp->t_state&TS_BKSL) { 82723165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 82823165Sbloom if (maptab[c]) 82923165Sbloom c = maptab[c]; 83023165Sbloom c |= 0200; 83123165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 83223165Sbloom } else if (c >= 'A' && c <= 'Z') 83323165Sbloom c += 'a' - 'A'; 83423165Sbloom else if (c == '\\') 83523165Sbloom tp->t_state |= TS_BKSL; 83623165Sbloom } 83723165Sbloom 8389578Ssam /* 839*34492Skarels * Cbreak mode, don't process line editing 8409578Ssam * characters; check high water mark for wakeup. 8419578Ssam */ 842*34492Skarels if (t_flags&CBREAK) { 8439578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 844*34492Skarels if (tp->t_outq.c_cc < TTHIWAT(tp) && 845*34492Skarels tp->t_line == NTTYDISC) 846*34492Skarels (void) ttyoutput(CTRL('g'), tp); 8477502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 8487502Sroot ttwakeup(tp); 8497502Sroot ttyecho(c, tp); 8507502Sroot } 8519578Ssam goto endcase; 8529578Ssam } 8539578Ssam 8549578Ssam /* 855*34492Skarels * From here on down cooked mode character 8569578Ssam * processing takes place. 8579578Ssam */ 8589578Ssam if ((tp->t_state&TS_QUOT) && 859*34492Skarels (c == tp->t_erase || c == tp->t_kill)) { 8609578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8619578Ssam c |= 0200; 8629578Ssam } 863*34492Skarels if (c == tp->t_erase) { 8649578Ssam if (tp->t_rawq.c_cc) 8659578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8669578Ssam goto endcase; 8679578Ssam } 868*34492Skarels if (c == tp->t_kill) { 869*34492Skarels if (t_flags&CRTKIL && 8709578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8719578Ssam while (tp->t_rawq.c_cc) 8729578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8739578Ssam } else { 8749578Ssam ttyecho(c, tp); 875*34492Skarels ttyecho('\n', tp); 8769578Ssam while (getc(&tp->t_rawq) > 0) 8779578Ssam ; 8789578Ssam tp->t_rocount = 0; 8799578Ssam } 8809578Ssam tp->t_state &= ~TS_LOCAL; 8819578Ssam goto endcase; 8829578Ssam } 8839578Ssam 8849578Ssam /* 885*34492Skarels * New line discipline, 886*34492Skarels * check word erase/reprint line. 8879578Ssam */ 888*34492Skarels if (tp->t_line == NTTYDISC) { 889*34492Skarels if (c == tp->t_werasc) { 8909578Ssam if (tp->t_rawq.c_cc == 0) 8919578Ssam goto endcase; 892*34492Skarels do { 893*34492Skarels c = unputc(&tp->t_rawq); 894*34492Skarels if (c != ' ' && c != '\t') 895*34492Skarels goto erasenb; 896*34492Skarels ttyrub(c, tp); 897*34492Skarels } while (tp->t_rawq.c_cc); 898*34492Skarels goto endcase; 899*34492Skarels erasenb: 900*34492Skarels do { 901*34492Skarels ttyrub(c, tp); 902*34492Skarels if (tp->t_rawq.c_cc == 0) 903*34492Skarels goto endcase; 904*34492Skarels c = unputc(&tp->t_rawq); 905*34492Skarels } while (c != ' ' && c != '\t'); 906*34492Skarels (void) putc(c, &tp->t_rawq); 907*34492Skarels goto endcase; 908*34492Skarels } 909*34492Skarels if (c == tp->t_rprntc) { 910*34492Skarels ttyretype(tp); 911*34492Skarels goto endcase; 912*34492Skarels } 9139578Ssam } 9149578Ssam 9159578Ssam /* 9169578Ssam * Check for input buffer overflow 9179578Ssam */ 91810391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 919*34492Skarels if (tp->t_line == NTTYDISC) 920*34492Skarels (void) ttyoutput(CTRL('g'), tp); 9219578Ssam goto endcase; 92210391Ssam } 9239578Ssam 9249578Ssam /* 9259578Ssam * Put data char in q for user and 9269578Ssam * wakeup on seeing a line delimiter. 9279578Ssam */ 9289578Ssam if (putc(c, &tp->t_rawq) >= 0) { 929*34492Skarels if (ttbreakc(c, tp)) { 9309578Ssam tp->t_rocount = 0; 9319578Ssam catq(&tp->t_rawq, &tp->t_canq); 9327502Sroot ttwakeup(tp); 9339578Ssam } else if (tp->t_rocount++ == 0) 9349578Ssam tp->t_rocol = tp->t_col; 9359578Ssam tp->t_state &= ~TS_QUOT; 936*34492Skarels if (c == '\\') 937*34492Skarels tp->t_state |= TS_QUOT; 9389578Ssam if (tp->t_state&TS_ERASE) { 9399578Ssam tp->t_state &= ~TS_ERASE; 9409578Ssam (void) ttyoutput('/', tp); 9419578Ssam } 9429578Ssam i = tp->t_col; 9437502Sroot ttyecho(c, tp); 944*34492Skarels if (c == tp->t_eofc && t_flags&ECHO) { 9459578Ssam i = MIN(2, tp->t_col - i); 9469578Ssam while (i > 0) { 9479578Ssam (void) ttyoutput('\b', tp); 9489578Ssam i--; 9499578Ssam } 9509578Ssam } 9517502Sroot } 9529578Ssam endcase: 9539578Ssam /* 954*34492Skarels * If DEC-style start/stop is enabled don't restart 955*34492Skarels * output until seeing the start character. 9569578Ssam */ 957*34492Skarels if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 958*34492Skarels tp->t_startc != tp->t_stopc) 9597502Sroot return; 9609578Ssam restartoutput: 9617502Sroot tp->t_state &= ~TS_TTSTOP; 962*34492Skarels tp->t_flags &= ~FLUSHO; 9639578Ssam startoutput: 9647502Sroot ttstart(tp); 9657502Sroot } 9667502Sroot 9677502Sroot /* 9689578Ssam * Put character on TTY output queue, adding delays, 9697502Sroot * expanding tabs, and handling the CR/NL bit. 9709578Ssam * This is called both from the top half for output, 9719578Ssam * and from interrupt level for echoing. 9727502Sroot * The arguments are the character and the tty structure. 9737502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 9747502Sroot * Must be recursive. 9757502Sroot */ 9767502Sroot ttyoutput(c, tp) 9777502Sroot register c; 9787502Sroot register struct tty *tp; 9797502Sroot { 9807502Sroot register char *colp; 9817502Sroot register ctype; 9827502Sroot 983*34492Skarels if (tp->t_flags & (RAW|LITOUT)) { 984*34492Skarels if (tp->t_flags&FLUSHO) 9857502Sroot return (-1); 9867502Sroot if (putc(c, &tp->t_outq)) 9877625Ssam return (c); 9887502Sroot tk_nout++; 9897502Sroot return (-1); 9907502Sroot } 991*34492Skarels 9927502Sroot /* 993*34492Skarels * Ignore EOT in normal mode to avoid 994*34492Skarels * hanging up certain terminals. 995*34492Skarels */ 996*34492Skarels c &= 0177; 997*34492Skarels if (c == CEOT && (tp->t_flags&CBREAK) == 0) 998*34492Skarels return (-1); 999*34492Skarels /* 10007502Sroot * Turn tabs to spaces as required 10017502Sroot */ 1002*34492Skarels if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 10037502Sroot register int s; 10047502Sroot 10057502Sroot c = 8 - (tp->t_col&7); 1006*34492Skarels if ((tp->t_flags&FLUSHO) == 0) { 100717545Skarels s = spltty(); /* don't interrupt tabs */ 10087502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10097502Sroot tk_nout += c; 10107502Sroot splx(s); 10117502Sroot } 10127502Sroot tp->t_col += c; 10137502Sroot return (c ? -1 : '\t'); 10147502Sroot } 10157502Sroot tk_nout++; 10167502Sroot /* 10177502Sroot * for upper-case-only terminals, 10187502Sroot * generate escapes. 10197502Sroot */ 10207502Sroot if (tp->t_flags&LCASE) { 10217502Sroot colp = "({)}!|^~'`"; 10227625Ssam while (*colp++) 10237625Ssam if (c == *colp++) { 10247502Sroot if (ttyoutput('\\', tp) >= 0) 10257502Sroot return (c); 10267502Sroot c = colp[-2]; 10277502Sroot break; 10287502Sroot } 10299578Ssam if ('A' <= c && c <= 'Z') { 10307502Sroot if (ttyoutput('\\', tp) >= 0) 10317502Sroot return (c); 10329578Ssam } else if ('a' <= c && c <= 'z') 10337502Sroot c += 'A' - 'a'; 10347502Sroot } 10359578Ssam 10367502Sroot /* 10377502Sroot * turn <nl> to <cr><lf> if desired. 10387502Sroot */ 1039*34492Skarels if (c == '\n' && tp->t_flags&CRMOD) 1040*34492Skarels if (ttyoutput('\r', tp) >= 0) 10417502Sroot return (c); 10429578Ssam if (c == '~' && tp->t_flags&TILDE) 10437502Sroot c = '`'; 1044*34492Skarels if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 10457502Sroot return (c); 10467502Sroot /* 10477502Sroot * Calculate delays. 10487502Sroot * The numbers here represent clock ticks 10497502Sroot * and are not necessarily optimal for all terminals. 10507502Sroot * The delays are indicated by characters above 0200. 10517502Sroot * In raw mode there are no delays and the 10527502Sroot * transmission path is 8 bits wide. 10539578Ssam * 10549578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 10557502Sroot */ 10567502Sroot colp = &tp->t_col; 10577502Sroot ctype = partab[c]; 10587502Sroot c = 0; 10597502Sroot switch (ctype&077) { 10607502Sroot 10617502Sroot case ORDINARY: 10627502Sroot (*colp)++; 10637502Sroot 10647502Sroot case CONTROL: 10657502Sroot break; 10667502Sroot 10677502Sroot case BACKSPACE: 10687502Sroot if (*colp) 10697502Sroot (*colp)--; 10707502Sroot break; 10717502Sroot 107213821Ssam /* 107313821Ssam * This macro is close enough to the correct thing; 107413821Ssam * it should be replaced by real user settable delays 107513821Ssam * in any event... 107613821Ssam */ 107713821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10787502Sroot case NEWLINE: 10797502Sroot ctype = (tp->t_flags >> 8) & 03; 10807625Ssam if (ctype == 1) { /* tty 37 */ 108126357Skarels if (*colp > 0) { 108226357Skarels c = (((unsigned)*colp) >> 4) + 3; 108326357Skarels if ((unsigned)c > 6) 108426357Skarels c = 6; 108526357Skarels } 10869578Ssam } else if (ctype == 2) /* vt05 */ 108713821Ssam c = mstohz(100); 10887502Sroot *colp = 0; 10897502Sroot break; 10907502Sroot 10917502Sroot case TAB: 10927502Sroot ctype = (tp->t_flags >> 10) & 03; 10937625Ssam if (ctype == 1) { /* tty 37 */ 10947502Sroot c = 1 - (*colp | ~07); 10957625Ssam if (c < 5) 10967502Sroot c = 0; 10977502Sroot } 10987502Sroot *colp |= 07; 10997502Sroot (*colp)++; 11007502Sroot break; 11017502Sroot 11027502Sroot case VTAB: 11039578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11047502Sroot c = 0177; 11057502Sroot break; 11067502Sroot 11077502Sroot case RETURN: 11087502Sroot ctype = (tp->t_flags >> 12) & 03; 11099578Ssam if (ctype == 1) /* tn 300 */ 111013821Ssam c = mstohz(83); 11119578Ssam else if (ctype == 2) /* ti 700 */ 111213821Ssam c = mstohz(166); 11139578Ssam else if (ctype == 3) { /* concept 100 */ 11147502Sroot int i; 11159578Ssam 11167502Sroot if ((i = *colp) >= 0) 11179578Ssam for (; i < 9; i++) 11187502Sroot (void) putc(0177, &tp->t_outq); 11197502Sroot } 11207502Sroot *colp = 0; 11217502Sroot } 1122*34492Skarels if (c && (tp->t_flags&FLUSHO) == 0) 11237502Sroot (void) putc(c|0200, &tp->t_outq); 11247502Sroot return (-1); 11257502Sroot } 112613821Ssam #undef mstohz 11277502Sroot 11287502Sroot /* 11297502Sroot * Called from device's read routine after it has 11307502Sroot * calculated the tty-structure given as argument. 11317502Sroot */ 11327722Swnj ttread(tp, uio) 11337625Ssam register struct tty *tp; 11347722Swnj struct uio *uio; 11357502Sroot { 11367502Sroot register struct clist *qp; 1137*34492Skarels register c, t_flags; 11389859Ssam int s, first, error = 0; 11397502Sroot 11407502Sroot loop: 11419578Ssam /* 11429578Ssam * Take any pending input first. 11439578Ssam */ 114417545Skarels s = spltty(); 1145*34492Skarels if (tp->t_flags&PENDIN) 11467502Sroot ttypend(tp); 11479859Ssam splx(s); 11489578Ssam 114923165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 115023165Sbloom return (EIO); 115123165Sbloom 11529578Ssam /* 11539578Ssam * Hang process if it's in the background. 11549578Ssam */ 115523165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 115624392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 115724392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11587502Sroot u.u_procp->p_flag&SVFORK) 11598520Sroot return (EIO); 11607502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11617502Sroot sleep((caddr_t)&lbolt, TTIPRI); 116223165Sbloom goto loop; 11637502Sroot } 11649578Ssam t_flags = tp->t_flags; 11659578Ssam 11669578Ssam /* 1167*34492Skarels * In raw mode take characters directly from the 1168*34492Skarels * raw queue w/o processing. Interlock against 1169*34492Skarels * device interrupts when interrogating rawq. 11709578Ssam */ 1171*34492Skarels if (t_flags&RAW) { 1172*34492Skarels s = spltty(); 1173*34492Skarels if (tp->t_rawq.c_cc <= 0) { 1174*34492Skarels if ((tp->t_state&TS_CARR_ON) == 0 || 1175*34492Skarels (tp->t_state&TS_NBIO)) { 1176*34492Skarels splx(s); 1177*34492Skarels return (EWOULDBLOCK); 1178*34492Skarels } 1179*34492Skarels sleep((caddr_t)&tp->t_rawq, TTIPRI); 1180*34492Skarels splx(s); 1181*34492Skarels goto loop; 1182*34492Skarels } 1183*34492Skarels splx(s); 1184*34492Skarels while (!error && tp->t_rawq.c_cc && uio->uio_resid) 1185*34492Skarels error = ureadc(getc(&tp->t_rawq), uio); 1186*34492Skarels goto checktandem; 1187*34492Skarels } 11889578Ssam 11899578Ssam /* 1190*34492Skarels * In cbreak mode use the rawq, otherwise 1191*34492Skarels * take characters from the canonicalized q. 1192*34492Skarels */ 1193*34492Skarels qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 1194*34492Skarels 1195*34492Skarels /* 11969578Ssam * No input, sleep on rawq awaiting hardware 11979578Ssam * receipt and notification. 11989578Ssam */ 119917545Skarels s = spltty(); 12009578Ssam if (qp->c_cc <= 0) { 12019578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 12029578Ssam (tp->t_state&TS_NBIO)) { 12039859Ssam splx(s); 12049578Ssam return (EWOULDBLOCK); 12057502Sroot } 12069578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 12079859Ssam splx(s); 12089578Ssam goto loop; 12099578Ssam } 12109859Ssam splx(s); 12119578Ssam 12129578Ssam /* 1213*34492Skarels * Input present, perform input mapping 1214*34492Skarels * and processing (we're not in raw mode). 12159578Ssam */ 12169578Ssam first = 1; 12179578Ssam while ((c = getc(qp)) >= 0) { 1218*34492Skarels if (t_flags&CRMOD && c == '\r') 1219*34492Skarels c = '\n'; 12209578Ssam /* 1221*34492Skarels * Check for delayed suspend character. 12229578Ssam */ 1223*34492Skarels if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 12249578Ssam gsignal(tp->t_pgrp, SIGTSTP); 12259578Ssam if (first) { 12269578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12279578Ssam goto loop; 12289578Ssam } 12299578Ssam break; 12307502Sroot } 12319578Ssam /* 1232*34492Skarels * Interpret EOF only in cooked mode. 12339578Ssam */ 1234*34492Skarels if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12359578Ssam break; 12369578Ssam /* 12379578Ssam * Give user character. 12389578Ssam */ 1239*34492Skarels error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12409578Ssam if (error) 12419578Ssam break; 124214938Smckusick if (uio->uio_resid == 0) 12439578Ssam break; 12449578Ssam /* 1245*34492Skarels * In cooked mode check for a "break character" 12469578Ssam * marking the end of a "line of input". 12479578Ssam */ 1248*34492Skarels if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12499578Ssam break; 12509578Ssam first = 0; 12517502Sroot } 12529578Ssam 12539859Ssam checktandem: 12549578Ssam /* 12559578Ssam * Look to unblock output now that (presumably) 12569578Ssam * the input queue has gone down. 12579578Ssam */ 1258*34492Skarels if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 1259*34492Skarels if (putc(tp->t_startc, &tp->t_outq) == 0) { 12607502Sroot tp->t_state &= ~TS_TBLOCK; 12617502Sroot ttstart(tp); 12627502Sroot } 12638520Sroot return (error); 12647502Sroot } 12657502Sroot 12667502Sroot /* 126725391Skarels * Check the output queue on tp for space for a kernel message 126825391Skarels * (from uprintf/tprintf). Allow some space over the normal 126925391Skarels * hiwater mark so we don't lose messages due to normal flow 127025391Skarels * control, but don't let the tty run amok. 127130695Skarels * Sleeps here are not interruptible, but we return prematurely 127230695Skarels * if new signals come in. 127325391Skarels */ 127425391Skarels ttycheckoutq(tp, wait) 127525391Skarels register struct tty *tp; 127625391Skarels int wait; 127725391Skarels { 127830695Skarels int hiwat, s, oldsig; 127925391Skarels 128025391Skarels hiwat = TTHIWAT(tp); 128125391Skarels s = spltty(); 128230695Skarels oldsig = u.u_procp->p_sig; 128325391Skarels if (tp->t_outq.c_cc > hiwat + 200) 128429946Skarels while (tp->t_outq.c_cc > hiwat) { 128529946Skarels ttstart(tp); 128630695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 128729946Skarels splx(s); 128829946Skarels return (0); 128929946Skarels } 129030695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 129129946Skarels tp->t_state |= TS_ASLEEP; 129230695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 129325391Skarels } 129425391Skarels splx(s); 129525391Skarels return (1); 129625391Skarels } 129725391Skarels 129825391Skarels /* 12997502Sroot * Called from the device's write routine after it has 13007502Sroot * calculated the tty-structure given as argument. 13017502Sroot */ 13027822Sroot ttwrite(tp, uio) 13037625Ssam register struct tty *tp; 13049578Ssam register struct uio *uio; 13057502Sroot { 13067502Sroot register char *cp; 13079578Ssam register int cc, ce, c; 13089578Ssam int i, hiwat, cnt, error, s; 13097502Sroot char obuf[OBUFSIZ]; 13107502Sroot 13119578Ssam hiwat = TTHIWAT(tp); 13129578Ssam cnt = uio->uio_resid; 13139578Ssam error = 0; 13147502Sroot loop: 131521776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 131621776Sbloom return (EIO); 13179578Ssam /* 13189578Ssam * Hang the process if it's in the background. 13199578Ssam */ 132021776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 1321*34492Skarels (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 132224392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 132324392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 13247502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 13257502Sroot sleep((caddr_t)&lbolt, TTIPRI); 132621776Sbloom goto loop; 13277502Sroot } 13289578Ssam 13299578Ssam /* 13309578Ssam * Process the user's data in at most OBUFSIZ 13319578Ssam * chunks. Perform lower case simulation and 13329578Ssam * similar hacks. Keep track of high water 13339578Ssam * mark, sleep on overflow awaiting device aid 13349578Ssam * in acquiring new space. 13359578Ssam */ 13367822Sroot while (uio->uio_resid > 0) { 133732067Skarels if (tp->t_outq.c_cc > hiwat) { 133832067Skarels cc = 0; 133932067Skarels goto ovhiwat; 134032067Skarels } 13419578Ssam /* 13429578Ssam * Grab a hunk of data from the user. 13439578Ssam */ 13447822Sroot cc = uio->uio_iov->iov_len; 13457822Sroot if (cc == 0) { 13467822Sroot uio->uio_iovcnt--; 13477822Sroot uio->uio_iov++; 134821776Sbloom if (uio->uio_iovcnt <= 0) 13497822Sroot panic("ttwrite"); 13507822Sroot continue; 13517822Sroot } 13527822Sroot if (cc > OBUFSIZ) 13537822Sroot cc = OBUFSIZ; 13547502Sroot cp = obuf; 135512752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13568520Sroot if (error) 13577502Sroot break; 1358*34492Skarels 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) { 1398*34492Skarels if (tp->t_flags & (RAW|LITOUT)) 13997502Sroot ce = cc; 14007502Sroot else { 1401*34492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 1402*34492Skarels (u_char *)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--; 1422*34492Skarels 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 } 1451*34492Skarels if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14527502Sroot goto ovhiwat; 14537502Sroot } 14547502Sroot } 1455*34492Skarels ttstart(tp); 14568520Sroot return (error); 14577502Sroot 14587502Sroot ovhiwat: 14599578Ssam if (cc != 0) { 14609578Ssam uio->uio_iov->iov_base -= cc; 14619578Ssam uio->uio_iov->iov_len += cc; 14629578Ssam uio->uio_resid += cc; 14639578Ssam uio->uio_offset -= cc; 14649578Ssam } 146532067Skarels ttstart(tp); 146632067Skarels s = spltty(); 14679578Ssam /* 1468*34492Skarels * This can only occur if FLUSHO is set in t_flags, 146932067Skarels * or if ttstart/oproc is synchronous (or very fast). 14709578Ssam */ 14717502Sroot if (tp->t_outq.c_cc <= hiwat) { 14729578Ssam splx(s); 14737502Sroot goto loop; 14747502Sroot } 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 1500*34492Skarels if ((tp->t_flags&ECHO) == 0) 15017502Sroot return; 1502*34492Skarels tp->t_flags &= ~FLUSHO; 15037502Sroot c &= 0377; 1504*34492Skarels 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: 1527*34492Skarels 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; 1539*34492Skarels 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); 1544*34492Skarels 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 } 1561*34492Skarels } 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 1568*34492Skarels 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 { 1580*34492Skarels 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 1597*34492Skarels if (tp->t_rprntc != 0377) 1598*34492Skarels 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 /* 1612*34492Skarels * 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) 1620*34492Skarels tp->t_flags &= ~FLUSHO; 1621*34492Skarels if ((tp->t_flags&ECHO) == 0) 16227502Sroot return; 1623*34492Skarels c &= 0377; 1624*34492Skarels if (tp->t_flags&RAW) { 1625*34492Skarels (void) ttyoutput(c, tp); 1626*34492Skarels return; 1627*34492Skarels } 1628*34492Skarels if (c == '\r' && tp->t_flags&CRMOD) 1629*34492Skarels c = '\n'; 1630*34492Skarels 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 /* 1646*34492Skarels * Is c a break char for tp? 1647*34492Skarels */ 1648*34492Skarels ttbreakc(c, tp) 1649*34492Skarels register c; 1650*34492Skarels register struct tty *tp; 1651*34492Skarels { 1652*34492Skarels return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 1653*34492Skarels c == '\r' && (tp->t_flags&CRMOD)); 1654*34492Skarels } 1655*34492Skarels 1656*34492Skarels /* 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