123387Smckusick /* 223387Smckusick * Copyright (c) 1982 Regents of the University of California. 323387Smckusick * All rights reserved. The Berkeley software License Agreement 423387Smckusick * specifies the terms and conditions for redistribution. 523387Smckusick * 6*24392Skarels * @(#)tty.c 6.21 (Berkeley) 08/22/85 723387Smckusick */ 839Sbill 99760Ssam #include "../machine/reg.h" 109760Ssam 1117095Sbloom #include "param.h" 1217095Sbloom #include "systm.h" 1317095Sbloom #include "dir.h" 1417095Sbloom #include "user.h" 1517095Sbloom #include "ioctl.h" 1617095Sbloom #include "tty.h" 1717095Sbloom #include "proc.h" 1817095Sbloom #include "inode.h" 1917095Sbloom #include "file.h" 2017095Sbloom #include "conf.h" 2117095Sbloom #include "buf.h" 2217095Sbloom #include "dk.h" 2317095Sbloom #include "uio.h" 2417095Sbloom #include "kernel.h" 2539Sbill 267436Skre /* 277436Skre * Table giving parity for characters and indicating 287436Skre * character classes to tty driver. In particular, 297436Skre * if the low 6 bits are 0, then the character needs 307436Skre * no special processing on output. 317436Skre */ 3239Sbill 337436Skre char partab[] = { 347436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 357436Skre 0202,0004,0003,0201,0005,0206,0201,0001, 367436Skre 0201,0001,0001,0201,0001,0201,0201,0001, 377436Skre 0001,0201,0201,0001,0201,0001,0001,0201, 387436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 397436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 407436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 417436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 427436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 437436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 447436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 457436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 467436Skre 0000,0200,0200,0000,0200,0000,0000,0200, 477436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 487436Skre 0200,0000,0000,0200,0000,0200,0200,0000, 497436Skre 0000,0200,0200,0000,0200,0000,0000,0201, 507436Skre 517436Skre /* 527436Skre * 7 bit ascii ends with the last character above, 537436Skre * but we contine through all 256 codes for the sake 547436Skre * of the tty output routines which use special vax 557436Skre * instructions which need a 256 character trt table. 567436Skre */ 577436Skre 587436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 597436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 607436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 617436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 627436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 637436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 647436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 657436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 667436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 677436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 687436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 697436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 707436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 717436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 727436Skre 0007,0007,0007,0007,0007,0007,0007,0007, 737436Skre 0007,0007,0007,0007,0007,0007,0007,0007 747436Skre }; 757436Skre 76146Sbill /* 7739Sbill * Input mapping table-- if an entry is non-zero, when the 7839Sbill * corresponding character is typed preceded by "\" the escape 7939Sbill * sequence is replaced by the table value. Mostly used for 8039Sbill * upper-case only terminals. 8139Sbill */ 8239Sbill char maptab[] ={ 8339Sbill 000,000,000,000,000,000,000,000, 8439Sbill 000,000,000,000,000,000,000,000, 8539Sbill 000,000,000,000,000,000,000,000, 8639Sbill 000,000,000,000,000,000,000,000, 8739Sbill 000,'|',000,000,000,000,000,'`', 8839Sbill '{','}',000,000,000,000,000,000, 8939Sbill 000,000,000,000,000,000,000,000, 9039Sbill 000,000,000,000,000,000,000,000, 9139Sbill 000,000,000,000,000,000,000,000, 9239Sbill 000,000,000,000,000,000,000,000, 9339Sbill 000,000,000,000,000,000,000,000, 9439Sbill 000,000,000,000,000,000,'~',000, 9539Sbill 000,'A','B','C','D','E','F','G', 9639Sbill 'H','I','J','K','L','M','N','O', 9739Sbill 'P','Q','R','S','T','U','V','W', 9839Sbill 'X','Y','Z',000,000,000,000,000, 9939Sbill }; 10039Sbill 101925Sbill short tthiwat[16] = 1028954Sroot { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; 103925Sbill short ttlowat[16] = 104925Sbill { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 }; 105925Sbill 1069578Ssam struct ttychars ttydefaults = { 1079578Ssam CERASE, CKILL, CINTR, CQUIT, CSTART, CSTOP, CEOF, 1089578Ssam CBRK, CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE,CLNEXT 1099578Ssam }; 11039Sbill 11139Sbill ttychars(tp) 1129578Ssam struct tty *tp; 11339Sbill { 114174Sbill 1159578Ssam tp->t_chars = ttydefaults; 11639Sbill } 11739Sbill 11839Sbill /* 119903Sbill * Wait for output to drain, then flush input waiting. 12039Sbill */ 12112752Ssam ttywflush(tp) 1225408Swnj register struct tty *tp; 12339Sbill { 12439Sbill 12512752Ssam ttywait(tp); 12612752Ssam ttyflush(tp, FREAD); 12712752Ssam } 12812752Ssam 12912752Ssam ttywait(tp) 13012752Ssam register struct tty *tp; 13112752Ssam { 13217545Skarels register int s = spltty(); 13312752Ssam 13413809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 13513809Ssam tp->t_state&TS_CARR_ON && tp->t_oproc) { /* kludge for pty */ 136903Sbill (*tp->t_oproc)(tp); 1375408Swnj tp->t_state |= TS_ASLEEP; 138903Sbill sleep((caddr_t)&tp->t_outq, TTOPRI); 139903Sbill } 1409859Ssam splx(s); 14139Sbill } 14239Sbill 14339Sbill /* 1449578Ssam * Flush all TTY queues 14539Sbill */ 14612752Ssam ttyflush(tp, rw) 1477625Ssam register struct tty *tp; 14839Sbill { 149903Sbill register s; 150903Sbill 15117545Skarels s = spltty(); 152903Sbill if (rw & FREAD) { 153903Sbill while (getc(&tp->t_canq) >= 0) 154903Sbill ; 155903Sbill wakeup((caddr_t)&tp->t_rawq); 156903Sbill } 157903Sbill if (rw & FWRITE) { 158903Sbill wakeup((caddr_t)&tp->t_outq); 1595408Swnj tp->t_state &= ~TS_TTSTOP; 1605426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 161903Sbill while (getc(&tp->t_outq) >= 0) 162903Sbill ; 163903Sbill } 164903Sbill if (rw & FREAD) { 165903Sbill while (getc(&tp->t_rawq) >= 0) 166903Sbill ; 1679578Ssam tp->t_rocount = 0; 168903Sbill tp->t_rocol = 0; 1699578Ssam tp->t_state &= ~TS_LOCAL; 170903Sbill } 171903Sbill splx(s); 17239Sbill } 17339Sbill 174903Sbill /* 175903Sbill * Send stop character on input overflow. 176903Sbill */ 177903Sbill ttyblock(tp) 1787625Ssam register struct tty *tp; 17939Sbill { 180903Sbill register x; 1819578Ssam 182903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 183903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 18412752Ssam ttyflush(tp, FREAD|FWRITE); 1855408Swnj tp->t_state &= ~TS_TBLOCK; 186903Sbill } 18715118Skarels /* 18815118Skarels * Block further input iff: 18915118Skarels * Current input > threshold AND input is available to user program 19015118Skarels */ 19116055Skarels if (x >= TTYHOG/2 && 19216055Skarels ((tp->t_flags & (RAW|CBREAK)) || (tp->t_canq.c_cc > 0))) { 19315118Skarels if (putc(tp->t_stopc, &tp->t_outq)==0) { 19415118Skarels tp->t_state |= TS_TBLOCK; 19515118Skarels ttstart(tp); 19615118Skarels } 197903Sbill } 19839Sbill } 19939Sbill 20039Sbill /* 201903Sbill * Restart typewriter output following a delay 202903Sbill * timeout. 203903Sbill * The name of the routine is passed to the timeout 204903Sbill * subroutine and it is called during a clock interrupt. 205121Sbill */ 206903Sbill ttrstrt(tp) 2077625Ssam register struct tty *tp; 208121Sbill { 209121Sbill 2109578Ssam if (tp == 0) 2119578Ssam panic("ttrstrt"); 2125408Swnj tp->t_state &= ~TS_TIMEOUT; 213903Sbill ttstart(tp); 214121Sbill } 215121Sbill 216121Sbill /* 217903Sbill * Start output on the typewriter. It is used from the top half 218903Sbill * after some characters have been put on the output queue, 219903Sbill * from the interrupt routine to transmit the next 220903Sbill * character, and after a timeout has finished. 22139Sbill */ 222903Sbill ttstart(tp) 2237625Ssam register struct tty *tp; 22439Sbill { 225903Sbill register s; 22639Sbill 22717545Skarels s = spltty(); 2289578Ssam if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 && 2295622Swnj tp->t_oproc) /* kludge for pty */ 230903Sbill (*tp->t_oproc)(tp); 231903Sbill splx(s); 23239Sbill } 23339Sbill 23439Sbill /* 235903Sbill * Common code for tty ioctls. 23639Sbill */ 2371780Sbill /*ARGSUSED*/ 2387625Ssam ttioctl(tp, com, data, flag) 2397625Ssam register struct tty *tp; 2407625Ssam caddr_t data; 24139Sbill { 2428520Sroot int dev = tp->t_dev; 24339Sbill extern int nldisp; 2448556Sroot int s; 24512752Ssam register int newflags; 24639Sbill 247903Sbill /* 248903Sbill * If the ioctl involves modification, 24917545Skarels * hang if in the background. 250903Sbill */ 2517625Ssam switch (com) { 25239Sbill 253915Sbill case TIOCSETD: 254915Sbill case TIOCSETP: 255915Sbill case TIOCSETN: 256903Sbill case TIOCFLUSH: 257903Sbill case TIOCSETC: 258903Sbill case TIOCSLTC: 259903Sbill case TIOCSPGRP: 260903Sbill case TIOCLBIS: 261903Sbill case TIOCLBIC: 262903Sbill case TIOCLSET: 2639325Ssam case TIOCSTI: 26417598Sbloom case TIOCSWINSZ: 265903Sbill while (tp->t_line == NTTYDISC && 266903Sbill u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 267903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 268*24392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 269*24392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 270903Sbill gsignal(u.u_procp->p_pgrp, SIGTTOU); 271903Sbill sleep((caddr_t)&lbolt, TTOPRI); 272903Sbill } 273903Sbill break; 274903Sbill } 275903Sbill 2769578Ssam /* 2779578Ssam * Process the ioctl. 2789578Ssam */ 2797625Ssam switch (com) { 280903Sbill 2818556Sroot /* get discipline number */ 28239Sbill case TIOCGETD: 2837625Ssam *(int *)data = tp->t_line; 28439Sbill break; 28539Sbill 2868556Sroot /* set line discipline */ 2877625Ssam case TIOCSETD: { 2887625Ssam register int t = *(int *)data; 2899578Ssam int error = 0; 2907625Ssam 29115078Skarels if ((unsigned) t >= nldisp) 29210851Ssam return (ENXIO); 29317545Skarels s = spltty(); 29439Sbill if (tp->t_line) 29539Sbill (*linesw[tp->t_line].l_close)(tp); 29639Sbill if (t) 2978556Sroot error = (*linesw[t].l_open)(dev, tp); 29810851Ssam if (error) { 29910851Ssam if (tp->t_line) 30010851Ssam (void) (*linesw[tp->t_line].l_open)(dev, tp); 30110851Ssam splx(s); 3028556Sroot return (error); 30310851Ssam } 3048556Sroot tp->t_line = t; 30518650Sbloom splx(s); 30639Sbill break; 3077625Ssam } 30839Sbill 3098556Sroot /* prevent more opens on channel */ 3105614Swnj case TIOCEXCL: 3115614Swnj tp->t_state |= TS_XCLUDE; 3125614Swnj break; 3135614Swnj 3145614Swnj case TIOCNXCL: 3155614Swnj tp->t_state &= ~TS_XCLUDE; 3165614Swnj break; 3175614Swnj 3188556Sroot /* hang up line on last close */ 31939Sbill case TIOCHPCL: 3205408Swnj tp->t_state |= TS_HUPCLS; 32139Sbill break; 32239Sbill 3233942Sbugs case TIOCFLUSH: { 3247625Ssam register int flags = *(int *)data; 3257625Ssam 3267625Ssam if (flags == 0) 3273942Sbugs flags = FREAD|FWRITE; 3287625Ssam else 3297625Ssam flags &= FREAD|FWRITE; 33012752Ssam ttyflush(tp, flags); 33139Sbill break; 3323944Sbugs } 33339Sbill 3348556Sroot /* return number of characters immediately available */ 3357625Ssam case FIONREAD: 3367625Ssam *(off_t *)data = ttnread(tp); 337174Sbill break; 338174Sbill 33913077Ssam case TIOCOUTQ: 34013077Ssam *(int *)data = tp->t_outq.c_cc; 34113077Ssam break; 34213077Ssam 3438589Sroot case TIOCSTOP: 34417545Skarels s = spltty(); 3459578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3465573Swnj tp->t_state |= TS_TTSTOP; 3475573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3485573Swnj } 3497625Ssam splx(s); 3505573Swnj break; 3515573Swnj 3528589Sroot case TIOCSTART: 35317545Skarels s = spltty(); 3549578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3555573Swnj tp->t_state &= ~TS_TTSTOP; 3569578Ssam tp->t_flags &= ~FLUSHO; 3575573Swnj ttstart(tp); 3585573Swnj } 3597625Ssam splx(s); 3605573Swnj break; 3615573Swnj 3629325Ssam /* 3639325Ssam * Simulate typing of a character at the terminal. 3649325Ssam */ 3659325Ssam case TIOCSTI: 36617183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36717183Smckusick return (EPERM); 3689325Ssam if (u.u_uid && u.u_ttyp != tp) 3699325Ssam return (EACCES); 3709578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3719325Ssam break; 3729325Ssam 37312752Ssam case TIOCSETP: 37412752Ssam case TIOCSETN: { 37512752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37612752Ssam 37712752Ssam tp->t_erase = sg->sg_erase; 37812752Ssam tp->t_kill = sg->sg_kill; 37912752Ssam tp->t_ispeed = sg->sg_ispeed; 38012752Ssam tp->t_ospeed = sg->sg_ospeed; 38112752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 38217545Skarels s = spltty(); 38312752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38412752Ssam ttywait(tp); 38512752Ssam ttyflush(tp, FREAD); 38612752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38712752Ssam if (newflags&CBREAK) { 38812752Ssam struct clist tq; 38912752Ssam 39012752Ssam catq(&tp->t_rawq, &tp->t_canq); 39112752Ssam tq = tp->t_rawq; 39212752Ssam tp->t_rawq = tp->t_canq; 39312752Ssam tp->t_canq = tq; 39412752Ssam } else { 39512752Ssam tp->t_flags |= PENDIN; 39613801Ssam newflags |= PENDIN; 39712752Ssam ttwakeup(tp); 39812752Ssam } 39912752Ssam } 40012752Ssam tp->t_flags = newflags; 40112752Ssam if (tp->t_flags&RAW) { 40212752Ssam tp->t_state &= ~TS_TTSTOP; 40312752Ssam ttstart(tp); 40412752Ssam } 40512752Ssam splx(s); 40612752Ssam break; 40712752Ssam } 40812752Ssam 40912752Ssam /* send current parameters to user */ 41012752Ssam case TIOCGETP: { 41112752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 41212752Ssam 41312752Ssam sg->sg_ispeed = tp->t_ispeed; 41412752Ssam sg->sg_ospeed = tp->t_ospeed; 41512752Ssam sg->sg_erase = tp->t_erase; 41612752Ssam sg->sg_kill = tp->t_kill; 41712752Ssam sg->sg_flags = tp->t_flags; 41812752Ssam break; 41912752Ssam } 42012752Ssam 42112752Ssam case FIONBIO: 42212752Ssam if (*(int *)data) 42312752Ssam tp->t_state |= TS_NBIO; 42412752Ssam else 42512752Ssam tp->t_state &= ~TS_NBIO; 42612752Ssam break; 42712752Ssam 42812752Ssam case FIOASYNC: 42912752Ssam if (*(int *)data) 43012752Ssam tp->t_state |= TS_ASYNC; 43112752Ssam else 43212752Ssam tp->t_state &= ~TS_ASYNC; 43312752Ssam break; 43412752Ssam 43513077Ssam case TIOCGETC: 43613077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43713077Ssam break; 43813077Ssam 43913077Ssam case TIOCSETC: 44013077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 44113077Ssam break; 44213077Ssam 44312752Ssam /* set/get local special characters */ 44412752Ssam case TIOCSLTC: 44512752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44612752Ssam break; 44712752Ssam 44812752Ssam case TIOCGLTC: 44912752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 45012752Ssam break; 45112752Ssam 45212752Ssam /* 45312752Ssam * Modify local mode word. 45412752Ssam */ 45512752Ssam case TIOCLBIS: 45612752Ssam tp->t_flags |= *(int *)data << 16; 45712752Ssam break; 45812752Ssam 45912752Ssam case TIOCLBIC: 46012752Ssam tp->t_flags &= ~(*(int *)data << 16); 46112752Ssam break; 46212752Ssam 46312752Ssam case TIOCLSET: 46412752Ssam tp->t_flags &= 0xffff; 46512752Ssam tp->t_flags |= *(int *)data << 16; 46612752Ssam break; 46712752Ssam 46812752Ssam case TIOCLGET: 46915720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 47012752Ssam break; 47112752Ssam 47217545Skarels /* 47317932Skarels * Allow SPGRP only if tty is open for reading. 47417598Sbloom * Quick check: if we can find a process in the new pgrp, 47517598Sbloom * this user must own that process. 47617598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47717545Skarels */ 47818650Sbloom case TIOCSPGRP: { 47917545Skarels struct proc *p; 48017545Skarels int pgrp = *(int *)data; 48117545Skarels 48217545Skarels if (u.u_uid && (flag & FREAD) == 0) 48317545Skarels return (EPERM); 48417598Sbloom p = pfind(pgrp); 48517598Sbloom if (p && p->p_pgrp == pgrp && 48617598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48717598Sbloom return (EPERM); 48817545Skarels tp->t_pgrp = pgrp; 48912752Ssam break; 49018650Sbloom } 49112752Ssam 49212752Ssam case TIOCGPGRP: 49312752Ssam *(int *)data = tp->t_pgrp; 49412752Ssam break; 49512752Ssam 49617598Sbloom case TIOCSWINSZ: 49718650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 49818650Sbloom sizeof (struct winsize))) { 49917598Sbloom tp->t_winsize = *(struct winsize *)data; 50017598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 50117598Sbloom } 50217598Sbloom break; 50317598Sbloom 50417598Sbloom case TIOCGWINSZ: 50517598Sbloom *(struct winsize *)data = tp->t_winsize; 50617598Sbloom break; 50717598Sbloom 50839Sbill default: 5098556Sroot return (-1); 51039Sbill } 5118556Sroot return (0); 51239Sbill } 5134484Swnj 5144484Swnj ttnread(tp) 5154484Swnj struct tty *tp; 5164484Swnj { 5174484Swnj int nread = 0; 5184484Swnj 5199578Ssam if (tp->t_flags & PENDIN) 5204484Swnj ttypend(tp); 5214484Swnj nread = tp->t_canq.c_cc; 5224484Swnj if (tp->t_flags & (RAW|CBREAK)) 5234484Swnj nread += tp->t_rawq.c_cc; 5244484Swnj return (nread); 5254484Swnj } 5264484Swnj 5275408Swnj ttselect(dev, rw) 5284484Swnj dev_t dev; 5295408Swnj int rw; 5304484Swnj { 5314484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5324484Swnj int nread; 53317545Skarels int s = spltty(); 5344484Swnj 5355408Swnj switch (rw) { 5364484Swnj 5374484Swnj case FREAD: 5384484Swnj nread = ttnread(tp); 53921776Sbloom if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0)) 5405408Swnj goto win; 5414938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5425408Swnj tp->t_state |= TS_RCOLL; 5434484Swnj else 5444484Swnj tp->t_rsel = u.u_procp; 5455408Swnj break; 5464484Swnj 5475408Swnj case FWRITE: 5485408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5495408Swnj goto win; 5505408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5515408Swnj tp->t_state |= TS_WCOLL; 5525408Swnj else 5535408Swnj tp->t_wsel = u.u_procp; 5545408Swnj break; 5554484Swnj } 5565408Swnj splx(s); 5575408Swnj return (0); 5585408Swnj win: 5595408Swnj splx(s); 5605408Swnj return (1); 5614484Swnj } 5627436Skre 5637502Sroot /* 5649578Ssam * Establish a process group for distribution of 5657502Sroot * quits and interrupts from the tty. 5667502Sroot */ 5677502Sroot ttyopen(dev, tp) 5687625Ssam dev_t dev; 5697625Ssam register struct tty *tp; 5707502Sroot { 5717502Sroot register struct proc *pp; 5727502Sroot 5737502Sroot pp = u.u_procp; 5747502Sroot tp->t_dev = dev; 5757625Ssam if (pp->p_pgrp == 0) { 5767502Sroot u.u_ttyp = tp; 5777502Sroot u.u_ttyd = dev; 5787502Sroot if (tp->t_pgrp == 0) 5797502Sroot tp->t_pgrp = pp->p_pid; 5807502Sroot pp->p_pgrp = tp->t_pgrp; 5817502Sroot } 5827502Sroot tp->t_state &= ~TS_WOPEN; 58317545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 58417545Skarels tp->t_state |= TS_ISOPEN; 58517598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58617545Skarels if (tp->t_line != NTTYDISC) 58717545Skarels ttywflush(tp); 58817545Skarels } 5898556Sroot return (0); 5907502Sroot } 5917502Sroot 5927502Sroot /* 5937502Sroot * clean tp on last close 5947502Sroot */ 5957502Sroot ttyclose(tp) 5967625Ssam register struct tty *tp; 5977502Sroot { 5987502Sroot 5997502Sroot if (tp->t_line) { 60012752Ssam ttywflush(tp); 6017502Sroot tp->t_line = 0; 6027502Sroot return; 6037502Sroot } 6047502Sroot tp->t_pgrp = 0; 60512752Ssam ttywflush(tp); 6067502Sroot tp->t_state = 0; 6077502Sroot } 6087502Sroot 6097502Sroot /* 6107502Sroot * reinput pending characters after state switch 61117545Skarels * call at spltty(). 6127502Sroot */ 6137502Sroot ttypend(tp) 6147625Ssam register struct tty *tp; 6157502Sroot { 6167502Sroot struct clist tq; 6177502Sroot register c; 6187502Sroot 6199578Ssam tp->t_flags &= ~PENDIN; 6209578Ssam tp->t_state |= TS_TYPEN; 6217502Sroot tq = tp->t_rawq; 6227502Sroot tp->t_rawq.c_cc = 0; 6237502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6247502Sroot while ((c = getc(&tq)) >= 0) 6257502Sroot ttyinput(c, tp); 6269578Ssam tp->t_state &= ~TS_TYPEN; 6277502Sroot } 6287502Sroot 6297502Sroot /* 6309578Ssam * Place a character on raw TTY input queue, 6319578Ssam * putting in delimiters and waking up top 6329578Ssam * half as needed. Also echo if required. 6339578Ssam * The arguments are the character and the 6349578Ssam * appropriate tty structure. 6357502Sroot */ 6367502Sroot ttyinput(c, tp) 6377625Ssam register c; 6387625Ssam register struct tty *tp; 6397502Sroot { 6409578Ssam register int t_flags = tp->t_flags; 6417502Sroot int i; 6427502Sroot 6439578Ssam /* 6449578Ssam * If input is pending take it first. 6459578Ssam */ 6469578Ssam if (t_flags&PENDIN) 6477502Sroot ttypend(tp); 6487502Sroot tk_nin++; 6497502Sroot c &= 0377; 6509578Ssam 6519578Ssam /* 6529578Ssam * In tandem mode, check high water mark. 6539578Ssam */ 6547502Sroot if (t_flags&TANDEM) 6557502Sroot ttyblock(tp); 6569578Ssam 6579578Ssam if (t_flags&RAW) { 6589578Ssam /* 6599578Ssam * Raw mode, just put character 6609578Ssam * in input q w/o interpretation. 6619578Ssam */ 6629578Ssam if (tp->t_rawq.c_cc > TTYHOG) 66312752Ssam ttyflush(tp, FREAD|FWRITE); 6649578Ssam else { 6659578Ssam if (putc(c, &tp->t_rawq) >= 0) 6669578Ssam ttwakeup(tp); 6679578Ssam ttyecho(c, tp); 6687502Sroot } 6699578Ssam goto endcase; 6709578Ssam } 6719578Ssam 6729578Ssam /* 6739578Ssam * Ignore any high bit added during 6749578Ssam * previous ttyinput processing. 6759578Ssam */ 67624273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 6779578Ssam c &= 0177; 6789578Ssam /* 6799578Ssam * Check for literal nexting very first 6809578Ssam */ 6819578Ssam if (tp->t_state&TS_LNCH) { 6829578Ssam c |= 0200; 6839578Ssam tp->t_state &= ~TS_LNCH; 6849578Ssam } 6859578Ssam 6869578Ssam /* 6879578Ssam * Scan for special characters. This code 6889578Ssam * is really just a big case statement with 6899578Ssam * non-constant cases. The bottom of the 6909578Ssam * case statement is labeled ``endcase'', so goto 6919578Ssam * it after a case match, or similar. 6929578Ssam */ 6939578Ssam if (tp->t_line == NTTYDISC) { 6949578Ssam if (c == tp->t_lnextc) { 69521776Sbloom if (t_flags&ECHO) 6967502Sroot ttyout("^\b", tp); 6979578Ssam tp->t_state |= TS_LNCH; 6989578Ssam goto endcase; 6999578Ssam } 7009578Ssam if (c == tp->t_flushc) { 70121776Sbloom if (t_flags&FLUSHO) 7029578Ssam tp->t_flags &= ~FLUSHO; 7037502Sroot else { 70412752Ssam ttyflush(tp, FWRITE); 7057502Sroot ttyecho(c, tp); 7069578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7077502Sroot ttyretype(tp); 7089578Ssam tp->t_flags |= FLUSHO; 7097502Sroot } 7109578Ssam goto startoutput; 7119578Ssam } 7129578Ssam if (c == tp->t_suspc) { 71321776Sbloom if ((t_flags&NOFLSH) == 0) 71412752Ssam ttyflush(tp, FREAD); 7159578Ssam ttyecho(c, tp); 7169578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7179578Ssam goto endcase; 7189578Ssam } 7199578Ssam } 7209578Ssam 7219578Ssam /* 7229578Ssam * Handle start/stop characters. 7239578Ssam */ 7249578Ssam if (c == tp->t_stopc) { 7259578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7269578Ssam tp->t_state |= TS_TTSTOP; 7279578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7287502Sroot return; 7299578Ssam } 7309578Ssam if (c != tp->t_startc) 7319578Ssam return; 7329578Ssam goto endcase; 7339578Ssam } 7349578Ssam if (c == tp->t_startc) 7359578Ssam goto restartoutput; 7369578Ssam 7379578Ssam /* 7389578Ssam * Look for interrupt/quit chars. 7399578Ssam */ 7409578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 74121776Sbloom if ((t_flags&NOFLSH) == 0) 74212752Ssam ttyflush(tp, FREAD|FWRITE); 7439578Ssam ttyecho(c, tp); 7449578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7459578Ssam goto endcase; 7469578Ssam } 7479578Ssam 74823165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 74923165Sbloom if (tp->t_state&TS_BKSL) { 75023165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 75123165Sbloom if (maptab[c]) 75223165Sbloom c = maptab[c]; 75323165Sbloom c |= 0200; 75423165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 75523165Sbloom } else if (c >= 'A' && c <= 'Z') 75623165Sbloom c += 'a' - 'A'; 75723165Sbloom else if (c == '\\') 75823165Sbloom tp->t_state |= TS_BKSL; 75923165Sbloom } 76023165Sbloom 7619578Ssam /* 7629578Ssam * Cbreak mode, don't process line editing 7639578Ssam * characters; check high water mark for wakeup. 7649578Ssam */ 7659578Ssam if (t_flags&CBREAK) { 7669578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 7677502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 7687502Sroot tp->t_line == NTTYDISC) 7697502Sroot (void) ttyoutput(CTRL(g), tp); 7707502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 7717502Sroot ttwakeup(tp); 7727502Sroot ttyecho(c, tp); 7737502Sroot } 7749578Ssam goto endcase; 7759578Ssam } 7769578Ssam 7779578Ssam /* 7789578Ssam * From here on down cooked mode character 7799578Ssam * processing takes place. 7809578Ssam */ 7819578Ssam if ((tp->t_state&TS_QUOT) && 7829578Ssam (c == tp->t_erase || c == tp->t_kill)) { 7839578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7849578Ssam c |= 0200; 7859578Ssam } 7869578Ssam if (c == tp->t_erase) { 7879578Ssam if (tp->t_rawq.c_cc) 7889578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7899578Ssam goto endcase; 7909578Ssam } 7919578Ssam if (c == tp->t_kill) { 79221776Sbloom if (t_flags&CRTKIL && 7939578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 7949578Ssam while (tp->t_rawq.c_cc) 7959578Ssam ttyrub(unputc(&tp->t_rawq), tp); 7969578Ssam } else { 7979578Ssam ttyecho(c, tp); 7989578Ssam ttyecho('\n', tp); 7999578Ssam while (getc(&tp->t_rawq) > 0) 8009578Ssam ; 8019578Ssam tp->t_rocount = 0; 8029578Ssam } 8039578Ssam tp->t_state &= ~TS_LOCAL; 8049578Ssam goto endcase; 8059578Ssam } 8069578Ssam 8079578Ssam /* 8089578Ssam * New line discipline, 8099578Ssam * check word erase/reprint line. 8109578Ssam */ 8119578Ssam if (tp->t_line == NTTYDISC) { 8129578Ssam if (c == tp->t_werasc) { 8139578Ssam if (tp->t_rawq.c_cc == 0) 8149578Ssam goto endcase; 8159578Ssam do { 8169578Ssam c = unputc(&tp->t_rawq); 8179578Ssam if (c != ' ' && c != '\t') 8189578Ssam goto erasenb; 8199578Ssam ttyrub(c, tp); 8209578Ssam } while (tp->t_rawq.c_cc); 8219578Ssam goto endcase; 8229578Ssam erasenb: 8239578Ssam do { 8249578Ssam ttyrub(c, tp); 8259578Ssam if (tp->t_rawq.c_cc == 0) 8269578Ssam goto endcase; 8279578Ssam c = unputc(&tp->t_rawq); 8289578Ssam } while (c != ' ' && c != '\t'); 8299578Ssam (void) putc(c, &tp->t_rawq); 8309578Ssam goto endcase; 8319578Ssam } 8329578Ssam if (c == tp->t_rprntc) { 8339578Ssam ttyretype(tp); 8349578Ssam goto endcase; 8359578Ssam } 8369578Ssam } 8379578Ssam 8389578Ssam /* 8399578Ssam * Check for input buffer overflow 8409578Ssam */ 84110391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 84210391Ssam if (tp->t_line == NTTYDISC) 84310391Ssam (void) ttyoutput(CTRL(g), tp); 8449578Ssam goto endcase; 84510391Ssam } 8469578Ssam 8479578Ssam /* 8489578Ssam * Put data char in q for user and 8499578Ssam * wakeup on seeing a line delimiter. 8509578Ssam */ 8519578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8529578Ssam if (ttbreakc(c, tp)) { 8539578Ssam tp->t_rocount = 0; 8549578Ssam catq(&tp->t_rawq, &tp->t_canq); 8557502Sroot ttwakeup(tp); 8569578Ssam } else if (tp->t_rocount++ == 0) 8579578Ssam tp->t_rocol = tp->t_col; 8589578Ssam tp->t_state &= ~TS_QUOT; 8599578Ssam if (c == '\\') 8609578Ssam tp->t_state |= TS_QUOT; 8619578Ssam if (tp->t_state&TS_ERASE) { 8629578Ssam tp->t_state &= ~TS_ERASE; 8639578Ssam (void) ttyoutput('/', tp); 8649578Ssam } 8659578Ssam i = tp->t_col; 8667502Sroot ttyecho(c, tp); 86721776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 8689578Ssam i = MIN(2, tp->t_col - i); 8699578Ssam while (i > 0) { 8709578Ssam (void) ttyoutput('\b', tp); 8719578Ssam i--; 8729578Ssam } 8739578Ssam } 8747502Sroot } 8759578Ssam endcase: 8769578Ssam /* 8779578Ssam * If DEC-style start/stop is enabled don't restart 8789578Ssam * output until seeing the start character. 8799578Ssam */ 88021776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 8819578Ssam tp->t_startc != tp->t_stopc) 8827502Sroot return; 8839578Ssam restartoutput: 8847502Sroot tp->t_state &= ~TS_TTSTOP; 8859578Ssam tp->t_flags &= ~FLUSHO; 8869578Ssam startoutput: 8877502Sroot ttstart(tp); 8887502Sroot } 8897502Sroot 8907502Sroot /* 8919578Ssam * Put character on TTY output queue, adding delays, 8927502Sroot * expanding tabs, and handling the CR/NL bit. 8939578Ssam * This is called both from the top half for output, 8949578Ssam * and from interrupt level for echoing. 8957502Sroot * The arguments are the character and the tty structure. 8967502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 8977502Sroot * Must be recursive. 8987502Sroot */ 8997502Sroot ttyoutput(c, tp) 9007502Sroot register c; 9017502Sroot register struct tty *tp; 9027502Sroot { 9037502Sroot register char *colp; 9047502Sroot register ctype; 9057502Sroot 9069578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9079578Ssam if (tp->t_flags&FLUSHO) 9087502Sroot return (-1); 9097502Sroot if (putc(c, &tp->t_outq)) 9107625Ssam return (c); 9117502Sroot tk_nout++; 9127502Sroot return (-1); 9137502Sroot } 9149578Ssam 9157502Sroot /* 9169578Ssam * Ignore EOT in normal mode to avoid 9179578Ssam * hanging up certain terminals. 9187502Sroot */ 9197502Sroot c &= 0177; 9209578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9217502Sroot return (-1); 9227502Sroot /* 9237502Sroot * Turn tabs to spaces as required 9247502Sroot */ 9259578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9267502Sroot register int s; 9277502Sroot 9287502Sroot c = 8 - (tp->t_col&7); 9299578Ssam if ((tp->t_flags&FLUSHO) == 0) { 93017545Skarels s = spltty(); /* don't interrupt tabs */ 9317502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9327502Sroot tk_nout += c; 9337502Sroot splx(s); 9347502Sroot } 9357502Sroot tp->t_col += c; 9367502Sroot return (c ? -1 : '\t'); 9377502Sroot } 9387502Sroot tk_nout++; 9397502Sroot /* 9407502Sroot * for upper-case-only terminals, 9417502Sroot * generate escapes. 9427502Sroot */ 9437502Sroot if (tp->t_flags&LCASE) { 9447502Sroot colp = "({)}!|^~'`"; 9457625Ssam while (*colp++) 9467625Ssam if (c == *colp++) { 9477502Sroot if (ttyoutput('\\', tp) >= 0) 9487502Sroot return (c); 9497502Sroot c = colp[-2]; 9507502Sroot break; 9517502Sroot } 9529578Ssam if ('A' <= c && c <= 'Z') { 9537502Sroot if (ttyoutput('\\', tp) >= 0) 9547502Sroot return (c); 9559578Ssam } else if ('a' <= c && c <= 'z') 9567502Sroot c += 'A' - 'a'; 9577502Sroot } 9589578Ssam 9597502Sroot /* 9607502Sroot * turn <nl> to <cr><lf> if desired. 9617502Sroot */ 9629578Ssam if (c == '\n' && tp->t_flags&CRMOD) 9637502Sroot if (ttyoutput('\r', tp) >= 0) 9647502Sroot return (c); 9659578Ssam if (c == '~' && tp->t_flags&TILDE) 9667502Sroot c = '`'; 9679578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 9687502Sroot return (c); 9697502Sroot /* 9707502Sroot * Calculate delays. 9717502Sroot * The numbers here represent clock ticks 9727502Sroot * and are not necessarily optimal for all terminals. 9737502Sroot * The delays are indicated by characters above 0200. 9747502Sroot * In raw mode there are no delays and the 9757502Sroot * transmission path is 8 bits wide. 9769578Ssam * 9779578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 9787502Sroot */ 9797502Sroot colp = &tp->t_col; 9807502Sroot ctype = partab[c]; 9817502Sroot c = 0; 9827502Sroot switch (ctype&077) { 9837502Sroot 9847502Sroot case ORDINARY: 9857502Sroot (*colp)++; 9867502Sroot 9877502Sroot case CONTROL: 9887502Sroot break; 9897502Sroot 9907502Sroot case BACKSPACE: 9917502Sroot if (*colp) 9927502Sroot (*colp)--; 9937502Sroot break; 9947502Sroot 99513821Ssam /* 99613821Ssam * This macro is close enough to the correct thing; 99713821Ssam * it should be replaced by real user settable delays 99813821Ssam * in any event... 99913821Ssam */ 100013821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10017502Sroot case NEWLINE: 10027502Sroot ctype = (tp->t_flags >> 8) & 03; 10037625Ssam if (ctype == 1) { /* tty 37 */ 100412752Ssam if (*colp > 0) 100513863Ssam c = max((((unsigned)*colp) >> 4) + 3, 100613863Ssam (unsigned)6); 10079578Ssam } else if (ctype == 2) /* vt05 */ 100813821Ssam c = mstohz(100); 10097502Sroot *colp = 0; 10107502Sroot break; 10117502Sroot 10127502Sroot case TAB: 10137502Sroot ctype = (tp->t_flags >> 10) & 03; 10147625Ssam if (ctype == 1) { /* tty 37 */ 10157502Sroot c = 1 - (*colp | ~07); 10167625Ssam if (c < 5) 10177502Sroot c = 0; 10187502Sroot } 10197502Sroot *colp |= 07; 10207502Sroot (*colp)++; 10217502Sroot break; 10227502Sroot 10237502Sroot case VTAB: 10249578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10257502Sroot c = 0177; 10267502Sroot break; 10277502Sroot 10287502Sroot case RETURN: 10297502Sroot ctype = (tp->t_flags >> 12) & 03; 10309578Ssam if (ctype == 1) /* tn 300 */ 103113821Ssam c = mstohz(83); 10329578Ssam else if (ctype == 2) /* ti 700 */ 103313821Ssam c = mstohz(166); 10349578Ssam else if (ctype == 3) { /* concept 100 */ 10357502Sroot int i; 10369578Ssam 10377502Sroot if ((i = *colp) >= 0) 10389578Ssam for (; i < 9; i++) 10397502Sroot (void) putc(0177, &tp->t_outq); 10407502Sroot } 10417502Sroot *colp = 0; 10427502Sroot } 10439578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10447502Sroot (void) putc(c|0200, &tp->t_outq); 10457502Sroot return (-1); 10467502Sroot } 104713821Ssam #undef mstohz 10487502Sroot 10497502Sroot /* 10507502Sroot * Called from device's read routine after it has 10517502Sroot * calculated the tty-structure given as argument. 10527502Sroot */ 10537722Swnj ttread(tp, uio) 10547625Ssam register struct tty *tp; 10557722Swnj struct uio *uio; 10567502Sroot { 10577502Sroot register struct clist *qp; 10589578Ssam register c, t_flags; 10599859Ssam int s, first, error = 0; 10607502Sroot 10617502Sroot loop: 10629578Ssam /* 10639578Ssam * Take any pending input first. 10649578Ssam */ 106517545Skarels s = spltty(); 10669578Ssam if (tp->t_flags&PENDIN) 10677502Sroot ttypend(tp); 10689859Ssam splx(s); 10699578Ssam 107023165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 107123165Sbloom return (EIO); 107223165Sbloom 10739578Ssam /* 10749578Ssam * Hang process if it's in the background. 10759578Ssam */ 107623165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 1077*24392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 1078*24392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 10797502Sroot u.u_procp->p_flag&SVFORK) 10808520Sroot return (EIO); 10817502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 10827502Sroot sleep((caddr_t)&lbolt, TTIPRI); 108323165Sbloom goto loop; 10847502Sroot } 10859578Ssam t_flags = tp->t_flags; 10869578Ssam 10879578Ssam /* 10889578Ssam * In raw mode take characters directly from the 10899578Ssam * raw queue w/o processing. Interlock against 10909578Ssam * device interrupts when interrogating rawq. 10919578Ssam */ 10929578Ssam if (t_flags&RAW) { 109317545Skarels s = spltty(); 10947502Sroot if (tp->t_rawq.c_cc <= 0) { 10959578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 10967502Sroot (tp->t_state&TS_NBIO)) { 10979859Ssam splx(s); 109815094Skarels return (EWOULDBLOCK); 10997502Sroot } 11007502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11019859Ssam splx(s); 11027502Sroot goto loop; 11037502Sroot } 11049859Ssam splx(s); 110514938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 110614938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11079859Ssam goto checktandem; 11089578Ssam } 11099578Ssam 11109578Ssam /* 11119578Ssam * In cbreak mode use the rawq, otherwise 11129578Ssam * take characters from the canonicalized q. 11139578Ssam */ 11149578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11159578Ssam 11169578Ssam /* 11179578Ssam * No input, sleep on rawq awaiting hardware 11189578Ssam * receipt and notification. 11199578Ssam */ 112017545Skarels s = spltty(); 11219578Ssam if (qp->c_cc <= 0) { 11229578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11239578Ssam (tp->t_state&TS_NBIO)) { 11249859Ssam splx(s); 11259578Ssam return (EWOULDBLOCK); 11267502Sroot } 11279578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11289859Ssam splx(s); 11299578Ssam goto loop; 11309578Ssam } 11319859Ssam splx(s); 11329578Ssam 11339578Ssam /* 11349578Ssam * Input present, perform input mapping 11359578Ssam * and processing (we're not in raw mode). 11369578Ssam */ 11379578Ssam first = 1; 11389578Ssam while ((c = getc(qp)) >= 0) { 11399578Ssam if (t_flags&CRMOD && c == '\r') 11409578Ssam c = '\n'; 11419578Ssam /* 11429578Ssam * Check for delayed suspend character. 11439578Ssam */ 11449578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11459578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11469578Ssam if (first) { 11479578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11489578Ssam goto loop; 11499578Ssam } 11509578Ssam break; 11517502Sroot } 11529578Ssam /* 11539578Ssam * Interpret EOF only in cooked mode. 11549578Ssam */ 11559578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 11569578Ssam break; 11579578Ssam /* 11589578Ssam * Give user character. 11599578Ssam */ 116024273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 11619578Ssam if (error) 11629578Ssam break; 116314938Smckusick if (uio->uio_resid == 0) 11649578Ssam break; 11659578Ssam /* 11669578Ssam * In cooked mode check for a "break character" 11679578Ssam * marking the end of a "line of input". 11689578Ssam */ 11699578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 11709578Ssam break; 11719578Ssam first = 0; 11727502Sroot } 11739578Ssam 11749859Ssam checktandem: 11759578Ssam /* 11769578Ssam * Look to unblock output now that (presumably) 11779578Ssam * the input queue has gone down. 11789578Ssam */ 11799859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 11809578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 11817502Sroot tp->t_state &= ~TS_TBLOCK; 11827502Sroot ttstart(tp); 11837502Sroot } 11848520Sroot return (error); 11857502Sroot } 11867502Sroot 11877502Sroot /* 11887502Sroot * Called from the device's write routine after it has 11897502Sroot * calculated the tty-structure given as argument. 11907502Sroot */ 11917822Sroot ttwrite(tp, uio) 11927625Ssam register struct tty *tp; 11939578Ssam register struct uio *uio; 11947502Sroot { 11957502Sroot register char *cp; 11969578Ssam register int cc, ce, c; 11979578Ssam int i, hiwat, cnt, error, s; 11987502Sroot char obuf[OBUFSIZ]; 11997502Sroot 12009578Ssam hiwat = TTHIWAT(tp); 12019578Ssam cnt = uio->uio_resid; 12029578Ssam error = 0; 12037502Sroot loop: 120421776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 120521776Sbloom return (EIO); 12069578Ssam /* 12079578Ssam * Hang the process if it's in the background. 12089578Ssam */ 120921776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12109578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 1211*24392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 1212*24392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 12137502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12147502Sroot sleep((caddr_t)&lbolt, TTIPRI); 121521776Sbloom goto loop; 12167502Sroot } 12179578Ssam 12189578Ssam /* 12199578Ssam * Process the user's data in at most OBUFSIZ 12209578Ssam * chunks. Perform lower case simulation and 12219578Ssam * similar hacks. Keep track of high water 12229578Ssam * mark, sleep on overflow awaiting device aid 12239578Ssam * in acquiring new space. 12249578Ssam */ 12257822Sroot while (uio->uio_resid > 0) { 12269578Ssam /* 12279578Ssam * Grab a hunk of data from the user. 12289578Ssam */ 12297822Sroot cc = uio->uio_iov->iov_len; 12307822Sroot if (cc == 0) { 12317822Sroot uio->uio_iovcnt--; 12327822Sroot uio->uio_iov++; 123321776Sbloom if (uio->uio_iovcnt <= 0) 12347822Sroot panic("ttwrite"); 12357822Sroot continue; 12367822Sroot } 12377822Sroot if (cc > OBUFSIZ) 12387822Sroot cc = OBUFSIZ; 12397502Sroot cp = obuf; 124012752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 12418520Sroot if (error) 12427502Sroot break; 12437502Sroot if (tp->t_outq.c_cc > hiwat) 12447502Sroot goto ovhiwat; 12459578Ssam if (tp->t_flags&FLUSHO) 12467502Sroot continue; 12479578Ssam /* 12489578Ssam * If we're mapping lower case or kludging tildes, 12499578Ssam * then we've got to look at each character, so 12509578Ssam * just feed the stuff to ttyoutput... 12519578Ssam */ 12529578Ssam if (tp->t_flags & (LCASE|TILDE)) { 12539578Ssam while (cc > 0) { 12547502Sroot c = *cp++; 12557502Sroot tp->t_rocount = 0; 12567625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 12577502Sroot /* out of clists, wait a bit */ 12587502Sroot ttstart(tp); 12597502Sroot sleep((caddr_t)&lbolt, TTOPRI); 12607502Sroot tp->t_rocount = 0; 126121776Sbloom if (cc != 0) { 126221776Sbloom uio->uio_iov->iov_base -= cc; 126321776Sbloom uio->uio_iov->iov_len += cc; 126421776Sbloom uio->uio_resid += cc; 126521776Sbloom uio->uio_offset -= cc; 126621776Sbloom } 126721776Sbloom goto loop; 12687502Sroot } 12697502Sroot --cc; 12707502Sroot if (tp->t_outq.c_cc > hiwat) 12717502Sroot goto ovhiwat; 12727502Sroot } 12737502Sroot continue; 12747502Sroot } 12759578Ssam /* 12769578Ssam * If nothing fancy need be done, grab those characters we 12779578Ssam * can handle without any of ttyoutput's processing and 12789578Ssam * just transfer them to the output q. For those chars 12799578Ssam * which require special processing (as indicated by the 12809578Ssam * bits in partab), call ttyoutput. After processing 12819578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 12829578Ssam * immediately. 12839578Ssam */ 12849578Ssam while (cc > 0) { 12859578Ssam if (tp->t_flags & (RAW|LITOUT)) 12867502Sroot ce = cc; 12877502Sroot else { 128812752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 128912752Ssam (caddr_t)partab, 077); 12909578Ssam /* 12919578Ssam * If ce is zero, then we're processing 12929578Ssam * a special character through ttyoutput. 12939578Ssam */ 12949578Ssam if (ce == 0) { 12957502Sroot tp->t_rocount = 0; 12967502Sroot if (ttyoutput(*cp, tp) >= 0) { 129721776Sbloom /* no c-lists, wait a bit */ 129821776Sbloom ttstart(tp); 129921776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 130021776Sbloom if (cc != 0) { 130121776Sbloom uio->uio_iov->iov_base -= cc; 130221776Sbloom uio->uio_iov->iov_len += cc; 130321776Sbloom uio->uio_resid += cc; 130421776Sbloom uio->uio_offset -= cc; 130521776Sbloom } 130621776Sbloom goto loop; 13077502Sroot } 13089578Ssam cp++, cc--; 13099578Ssam if (tp->t_flags&FLUSHO || 13109578Ssam tp->t_outq.c_cc > hiwat) 13117502Sroot goto ovhiwat; 13129578Ssam continue; 13137502Sroot } 13147502Sroot } 13159578Ssam /* 13169578Ssam * A bunch of normal characters have been found, 13179578Ssam * transfer them en masse to the output queue and 13189578Ssam * continue processing at the top of the loop. 13199578Ssam * If there are any further characters in this 13209578Ssam * <= OBUFSIZ chunk, the first should be a character 13219578Ssam * requiring special handling by ttyoutput. 13229578Ssam */ 13237502Sroot tp->t_rocount = 0; 13249578Ssam i = b_to_q(cp, ce, &tp->t_outq); 13259578Ssam ce -= i; 13269578Ssam tp->t_col += ce; 13279578Ssam cp += ce, cc -= ce, tk_nout += ce; 13289578Ssam if (i > 0) { 13299578Ssam /* out of c-lists, wait a bit */ 13307502Sroot ttstart(tp); 13317502Sroot sleep((caddr_t)&lbolt, TTOPRI); 133221776Sbloom uio->uio_iov->iov_base -= cc; 133321776Sbloom uio->uio_iov->iov_len += cc; 133421776Sbloom uio->uio_resid += cc; 133521776Sbloom uio->uio_offset -= cc; 133621776Sbloom goto loop; 13377502Sroot } 13389578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 13397502Sroot goto ovhiwat; 13407502Sroot } 13417502Sroot } 13427502Sroot ttstart(tp); 13438520Sroot return (error); 13447502Sroot 13457502Sroot ovhiwat: 134617545Skarels s = spltty(); 13479578Ssam if (cc != 0) { 13489578Ssam uio->uio_iov->iov_base -= cc; 13499578Ssam uio->uio_iov->iov_len += cc; 13509578Ssam uio->uio_resid += cc; 13519578Ssam uio->uio_offset -= cc; 13529578Ssam } 13539578Ssam /* 13549578Ssam * This can only occur if FLUSHO 13559578Ssam * is also set in t_flags. 13569578Ssam */ 13577502Sroot if (tp->t_outq.c_cc <= hiwat) { 13589578Ssam splx(s); 13597502Sroot goto loop; 13607502Sroot } 13617502Sroot ttstart(tp); 13629578Ssam if (tp->t_state&TS_NBIO) { 136317545Skarels splx(s); 13647822Sroot if (uio->uio_resid == cnt) 13658520Sroot return (EWOULDBLOCK); 13668520Sroot return (0); 13677502Sroot } 13687502Sroot tp->t_state |= TS_ASLEEP; 13697502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 13709578Ssam splx(s); 13717502Sroot goto loop; 13727502Sroot } 13737502Sroot 13747502Sroot /* 13757502Sroot * Rubout one character from the rawq of tp 13767502Sroot * as cleanly as possible. 13777502Sroot */ 13787502Sroot ttyrub(c, tp) 13797625Ssam register c; 13807625Ssam register struct tty *tp; 13817502Sroot { 13827502Sroot register char *cp; 13837502Sroot register int savecol; 13847502Sroot int s; 13857502Sroot char *nextc(); 13867502Sroot 13879578Ssam if ((tp->t_flags&ECHO) == 0) 13887502Sroot return; 13899578Ssam tp->t_flags &= ~FLUSHO; 13907502Sroot c &= 0377; 13919578Ssam if (tp->t_flags&CRTBS) { 13927502Sroot if (tp->t_rocount == 0) { 13937502Sroot /* 13947502Sroot * Screwed by ttwrite; retype 13957502Sroot */ 13967502Sroot ttyretype(tp); 13977502Sroot return; 13987502Sroot } 13999578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14007502Sroot ttyrubo(tp, 2); 14019578Ssam else switch (partab[c&=0177]&0177) { 14027502Sroot 14037502Sroot case ORDINARY: 14047502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14057502Sroot ttyrubo(tp, 2); 14067502Sroot else 14077502Sroot ttyrubo(tp, 1); 14087502Sroot break; 14097502Sroot 14107502Sroot case VTAB: 14117502Sroot case BACKSPACE: 14127502Sroot case CONTROL: 14137502Sroot case RETURN: 14149578Ssam if (tp->t_flags&CTLECH) 14157502Sroot ttyrubo(tp, 2); 14167502Sroot break; 14177502Sroot 14187502Sroot case TAB: 14197502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14207502Sroot ttyretype(tp); 14217502Sroot return; 14227502Sroot } 142317545Skarels s = spltty(); 14247502Sroot savecol = tp->t_col; 14259578Ssam tp->t_state |= TS_CNTTB; 14269578Ssam tp->t_flags |= FLUSHO; 14277502Sroot tp->t_col = tp->t_rocol; 14289578Ssam cp = tp->t_rawq.c_cf; 14299578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 14307502Sroot ttyecho(*cp, tp); 14319578Ssam tp->t_flags &= ~FLUSHO; 14329578Ssam tp->t_state &= ~TS_CNTTB; 14337502Sroot splx(s); 14347502Sroot /* 14357502Sroot * savecol will now be length of the tab 14367502Sroot */ 14377502Sroot savecol -= tp->t_col; 14387502Sroot tp->t_col += savecol; 14397502Sroot if (savecol > 8) 14407502Sroot savecol = 8; /* overflow screw */ 14417502Sroot while (--savecol >= 0) 14427502Sroot (void) ttyoutput('\b', tp); 14437502Sroot break; 14447502Sroot 14457502Sroot default: 14467502Sroot panic("ttyrub"); 14477502Sroot } 14489578Ssam } else if (tp->t_flags&PRTERA) { 14499578Ssam if ((tp->t_state&TS_ERASE) == 0) { 14507502Sroot (void) ttyoutput('\\', tp); 14519578Ssam tp->t_state |= TS_ERASE; 14527502Sroot } 14537502Sroot ttyecho(c, tp); 14547502Sroot } else 14557502Sroot ttyecho(tp->t_erase, tp); 14567502Sroot tp->t_rocount--; 14577502Sroot } 14587502Sroot 14597502Sroot /* 14607502Sroot * Crt back over cnt chars perhaps 14617502Sroot * erasing them. 14627502Sroot */ 14637502Sroot ttyrubo(tp, cnt) 14647625Ssam register struct tty *tp; 14657625Ssam int cnt; 14667502Sroot { 14679578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 14687502Sroot 14697502Sroot while (--cnt >= 0) 14709578Ssam ttyout(rubostring, tp); 14717502Sroot } 14727502Sroot 14737502Sroot /* 14747502Sroot * Reprint the rawq line. 14757502Sroot * We assume c_cc has already been checked. 14767502Sroot */ 14777502Sroot ttyretype(tp) 14787625Ssam register struct tty *tp; 14797502Sroot { 14807502Sroot register char *cp; 14817502Sroot char *nextc(); 14827502Sroot int s; 14837502Sroot 14849578Ssam if (tp->t_rprntc != 0377) 14859578Ssam ttyecho(tp->t_rprntc, tp); 14867502Sroot (void) ttyoutput('\n', tp); 148717545Skarels s = spltty(); 14887502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 14897502Sroot ttyecho(*cp, tp); 14907502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 14917502Sroot ttyecho(*cp, tp); 14929578Ssam tp->t_state &= ~TS_ERASE; 14937502Sroot splx(s); 14947502Sroot tp->t_rocount = tp->t_rawq.c_cc; 14957502Sroot tp->t_rocol = 0; 14967502Sroot } 14977502Sroot 14987502Sroot /* 14997502Sroot * Echo a typed character to the terminal 15007502Sroot */ 15017502Sroot ttyecho(c, tp) 15027625Ssam register c; 15037625Ssam register struct tty *tp; 15047502Sroot { 15057502Sroot 15069578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15079578Ssam tp->t_flags &= ~FLUSHO; 15087502Sroot if ((tp->t_flags&ECHO) == 0) 15097502Sroot return; 15107502Sroot c &= 0377; 15117502Sroot if (tp->t_flags&RAW) { 15127502Sroot (void) ttyoutput(c, tp); 15137502Sroot return; 15147502Sroot } 15157502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15167502Sroot c = '\n'; 15179578Ssam if (tp->t_flags&CTLECH) { 15187502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15197502Sroot (void) ttyoutput('^', tp); 15207502Sroot c &= 0177; 15217502Sroot if (c == 0177) 15227502Sroot c = '?'; 15237502Sroot else if (tp->t_flags&LCASE) 15247502Sroot c += 'a' - 1; 15257502Sroot else 15267502Sroot c += 'A' - 1; 15277502Sroot } 15287502Sroot } 15299578Ssam (void) ttyoutput(c&0177, tp); 15307502Sroot } 15317502Sroot 15327502Sroot /* 15337502Sroot * Is c a break char for tp? 15347502Sroot */ 15357502Sroot ttbreakc(c, tp) 15367625Ssam register c; 15377625Ssam register struct tty *tp; 15387502Sroot { 15399578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 15407502Sroot c == '\r' && (tp->t_flags&CRMOD)); 15417502Sroot } 15427502Sroot 15437502Sroot /* 15447502Sroot * send string cp to tp 15457502Sroot */ 15467502Sroot ttyout(cp, tp) 15477625Ssam register char *cp; 15487625Ssam register struct tty *tp; 15497502Sroot { 15507502Sroot register char c; 15517502Sroot 15527502Sroot while (c = *cp++) 15537502Sroot (void) ttyoutput(c, tp); 15547502Sroot } 15557502Sroot 15567502Sroot ttwakeup(tp) 15577502Sroot struct tty *tp; 15587502Sroot { 15597502Sroot 15607502Sroot if (tp->t_rsel) { 15617502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 15627502Sroot tp->t_state &= ~TS_RCOLL; 15637502Sroot tp->t_rsel = 0; 15647502Sroot } 156512752Ssam if (tp->t_state & TS_ASYNC) 156612752Ssam gsignal(tp->t_pgrp, SIGIO); 15677502Sroot wakeup((caddr_t)&tp->t_rawq); 15687502Sroot } 1569