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*25584Skarels * @(#)tty.c 6.25 (Berkeley) 12/10/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) && 13525391Skarels tp->t_state&TS_CARR_ON) { 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 && 26824392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 26924392Skarels !(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); 293*25584Skarels if (t != tp->t_line) { 294*25584Skarels s = spltty(); 295*25584Skarels (*linesw[tp->t_line].l_close)(tp); 296*25584Skarels error = (*linesw[t].l_open)(dev, tp); 297*25584Skarels if (error) { 298*25584Skarels (void) (*linesw[tp->t_line].l_open)(dev, tp); 299*25584Skarels splx(s); 300*25584Skarels return (error); 301*25584Skarels } 302*25584Skarels tp->t_line = t; 30310851Ssam splx(s); 30410851Ssam } 30539Sbill break; 3067625Ssam } 30739Sbill 3088556Sroot /* prevent more opens on channel */ 3095614Swnj case TIOCEXCL: 3105614Swnj tp->t_state |= TS_XCLUDE; 3115614Swnj break; 3125614Swnj 3135614Swnj case TIOCNXCL: 3145614Swnj tp->t_state &= ~TS_XCLUDE; 3155614Swnj break; 3165614Swnj 3178556Sroot /* hang up line on last close */ 31839Sbill case TIOCHPCL: 3195408Swnj tp->t_state |= TS_HUPCLS; 32039Sbill break; 32139Sbill 3223942Sbugs case TIOCFLUSH: { 3237625Ssam register int flags = *(int *)data; 3247625Ssam 3257625Ssam if (flags == 0) 3263942Sbugs flags = FREAD|FWRITE; 3277625Ssam else 3287625Ssam flags &= FREAD|FWRITE; 32912752Ssam ttyflush(tp, flags); 33039Sbill break; 3313944Sbugs } 33239Sbill 3338556Sroot /* return number of characters immediately available */ 3347625Ssam case FIONREAD: 3357625Ssam *(off_t *)data = ttnread(tp); 336174Sbill break; 337174Sbill 33813077Ssam case TIOCOUTQ: 33913077Ssam *(int *)data = tp->t_outq.c_cc; 34013077Ssam break; 34113077Ssam 3428589Sroot case TIOCSTOP: 34317545Skarels s = spltty(); 3449578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3455573Swnj tp->t_state |= TS_TTSTOP; 3465573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3475573Swnj } 3487625Ssam splx(s); 3495573Swnj break; 3505573Swnj 3518589Sroot case TIOCSTART: 35217545Skarels s = spltty(); 3539578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3545573Swnj tp->t_state &= ~TS_TTSTOP; 3559578Ssam tp->t_flags &= ~FLUSHO; 3565573Swnj ttstart(tp); 3575573Swnj } 3587625Ssam splx(s); 3595573Swnj break; 3605573Swnj 3619325Ssam /* 3629325Ssam * Simulate typing of a character at the terminal. 3639325Ssam */ 3649325Ssam case TIOCSTI: 36517183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36617183Smckusick return (EPERM); 3679325Ssam if (u.u_uid && u.u_ttyp != tp) 3689325Ssam return (EACCES); 3699578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3709325Ssam break; 3719325Ssam 37212752Ssam case TIOCSETP: 37312752Ssam case TIOCSETN: { 37412752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37512752Ssam 37612752Ssam tp->t_erase = sg->sg_erase; 37712752Ssam tp->t_kill = sg->sg_kill; 37812752Ssam tp->t_ispeed = sg->sg_ispeed; 37912752Ssam tp->t_ospeed = sg->sg_ospeed; 38012752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 38117545Skarels s = spltty(); 38212752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38312752Ssam ttywait(tp); 38412752Ssam ttyflush(tp, FREAD); 38512752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38612752Ssam if (newflags&CBREAK) { 38712752Ssam struct clist tq; 38812752Ssam 38912752Ssam catq(&tp->t_rawq, &tp->t_canq); 39012752Ssam tq = tp->t_rawq; 39112752Ssam tp->t_rawq = tp->t_canq; 39212752Ssam tp->t_canq = tq; 39312752Ssam } else { 39412752Ssam tp->t_flags |= PENDIN; 39513801Ssam newflags |= PENDIN; 39612752Ssam ttwakeup(tp); 39712752Ssam } 39812752Ssam } 39912752Ssam tp->t_flags = newflags; 40012752Ssam if (tp->t_flags&RAW) { 40112752Ssam tp->t_state &= ~TS_TTSTOP; 40212752Ssam ttstart(tp); 40312752Ssam } 40412752Ssam splx(s); 40512752Ssam break; 40612752Ssam } 40712752Ssam 40812752Ssam /* send current parameters to user */ 40912752Ssam case TIOCGETP: { 41012752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 41112752Ssam 41212752Ssam sg->sg_ispeed = tp->t_ispeed; 41312752Ssam sg->sg_ospeed = tp->t_ospeed; 41412752Ssam sg->sg_erase = tp->t_erase; 41512752Ssam sg->sg_kill = tp->t_kill; 41612752Ssam sg->sg_flags = tp->t_flags; 41712752Ssam break; 41812752Ssam } 41912752Ssam 42012752Ssam case FIONBIO: 42112752Ssam if (*(int *)data) 42212752Ssam tp->t_state |= TS_NBIO; 42312752Ssam else 42412752Ssam tp->t_state &= ~TS_NBIO; 42512752Ssam break; 42612752Ssam 42712752Ssam case FIOASYNC: 42812752Ssam if (*(int *)data) 42912752Ssam tp->t_state |= TS_ASYNC; 43012752Ssam else 43112752Ssam tp->t_state &= ~TS_ASYNC; 43212752Ssam break; 43312752Ssam 43413077Ssam case TIOCGETC: 43513077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43613077Ssam break; 43713077Ssam 43813077Ssam case TIOCSETC: 43913077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 44013077Ssam break; 44113077Ssam 44212752Ssam /* set/get local special characters */ 44312752Ssam case TIOCSLTC: 44412752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44512752Ssam break; 44612752Ssam 44712752Ssam case TIOCGLTC: 44812752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44912752Ssam break; 45012752Ssam 45112752Ssam /* 45212752Ssam * Modify local mode word. 45312752Ssam */ 45412752Ssam case TIOCLBIS: 45512752Ssam tp->t_flags |= *(int *)data << 16; 45612752Ssam break; 45712752Ssam 45812752Ssam case TIOCLBIC: 45912752Ssam tp->t_flags &= ~(*(int *)data << 16); 46012752Ssam break; 46112752Ssam 46212752Ssam case TIOCLSET: 46312752Ssam tp->t_flags &= 0xffff; 46412752Ssam tp->t_flags |= *(int *)data << 16; 46512752Ssam break; 46612752Ssam 46712752Ssam case TIOCLGET: 46815720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46912752Ssam break; 47012752Ssam 47117545Skarels /* 47217932Skarels * Allow SPGRP only if tty is open for reading. 47317598Sbloom * Quick check: if we can find a process in the new pgrp, 47417598Sbloom * this user must own that process. 47517598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47617545Skarels */ 47718650Sbloom case TIOCSPGRP: { 47817545Skarels struct proc *p; 47917545Skarels int pgrp = *(int *)data; 48017545Skarels 48117545Skarels if (u.u_uid && (flag & FREAD) == 0) 48217545Skarels return (EPERM); 48317598Sbloom p = pfind(pgrp); 48417598Sbloom if (p && p->p_pgrp == pgrp && 48517598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48617598Sbloom return (EPERM); 48717545Skarels tp->t_pgrp = pgrp; 48812752Ssam break; 48918650Sbloom } 49012752Ssam 49112752Ssam case TIOCGPGRP: 49212752Ssam *(int *)data = tp->t_pgrp; 49312752Ssam break; 49412752Ssam 49517598Sbloom case TIOCSWINSZ: 49618650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 49718650Sbloom sizeof (struct winsize))) { 49817598Sbloom tp->t_winsize = *(struct winsize *)data; 49917598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 50017598Sbloom } 50117598Sbloom break; 50217598Sbloom 50317598Sbloom case TIOCGWINSZ: 50417598Sbloom *(struct winsize *)data = tp->t_winsize; 50517598Sbloom break; 50617598Sbloom 50739Sbill default: 5088556Sroot return (-1); 50939Sbill } 5108556Sroot return (0); 51139Sbill } 5124484Swnj 5134484Swnj ttnread(tp) 5144484Swnj struct tty *tp; 5154484Swnj { 5164484Swnj int nread = 0; 5174484Swnj 5189578Ssam if (tp->t_flags & PENDIN) 5194484Swnj ttypend(tp); 5204484Swnj nread = tp->t_canq.c_cc; 5214484Swnj if (tp->t_flags & (RAW|CBREAK)) 5224484Swnj nread += tp->t_rawq.c_cc; 5234484Swnj return (nread); 5244484Swnj } 5254484Swnj 5265408Swnj ttselect(dev, rw) 5274484Swnj dev_t dev; 5285408Swnj int rw; 5294484Swnj { 5304484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5314484Swnj int nread; 53217545Skarels int s = spltty(); 5334484Swnj 5345408Swnj switch (rw) { 5354484Swnj 5364484Swnj case FREAD: 5374484Swnj nread = ttnread(tp); 53821776Sbloom if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0)) 5395408Swnj goto win; 5404938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5415408Swnj tp->t_state |= TS_RCOLL; 5424484Swnj else 5434484Swnj tp->t_rsel = u.u_procp; 5445408Swnj break; 5454484Swnj 5465408Swnj case FWRITE: 5475408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5485408Swnj goto win; 5495408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5505408Swnj tp->t_state |= TS_WCOLL; 5515408Swnj else 5525408Swnj tp->t_wsel = u.u_procp; 5535408Swnj break; 5544484Swnj } 5555408Swnj splx(s); 5565408Swnj return (0); 5575408Swnj win: 5585408Swnj splx(s); 5595408Swnj return (1); 5604484Swnj } 5617436Skre 5627502Sroot /* 56325391Skarels * Initial open of tty, or (re)entry to line discipline. 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 /* 59325391Skarels * "close" a line discipline 59425391Skarels */ 59525391Skarels ttylclose(tp) 59625391Skarels register struct tty *tp; 59725391Skarels { 59825391Skarels 59925391Skarels ttywflush(tp); 60025391Skarels tp->t_line = 0; 60125391Skarels } 60225391Skarels 60325391Skarels /* 6047502Sroot * clean tp on last close 6057502Sroot */ 6067502Sroot ttyclose(tp) 6077625Ssam register struct tty *tp; 6087502Sroot { 6097502Sroot 61025391Skarels ttyflush(tp, FREAD|FWRITE); 6117502Sroot tp->t_pgrp = 0; 6127502Sroot tp->t_state = 0; 6137502Sroot } 6147502Sroot 6157502Sroot /* 61625391Skarels * Handle modem control transition on a tty. 61725391Skarels * Flag indicates new state of carrier. 61825391Skarels * Returns 0 if the line should be turned off, otherwise 1. 61925391Skarels */ 62025391Skarels ttymodem(tp, flag) 62125391Skarels register struct tty *tp; 62225391Skarels { 62325391Skarels 62425391Skarels if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { 62525391Skarels /* 62625391Skarels * MDMBUF: do flow control according to carrier flag 62725391Skarels */ 62825391Skarels if (flag) { 62925391Skarels tp->t_state &= ~TS_TTSTOP; 63025391Skarels ttstart(tp); 63125391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 63225391Skarels tp->t_state |= TS_TTSTOP; 63325391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 63425391Skarels } 63525391Skarels } else if (flag == 0) { 63625391Skarels /* 63725391Skarels * Lost carrier. 63825391Skarels */ 63925391Skarels tp->t_state &= ~TS_CARR_ON; 64025391Skarels if (tp->t_state & TS_ISOPEN) { 64125391Skarels if ((tp->t_flags & NOHANG) == 0) { 64225391Skarels gsignal(tp->t_pgrp, SIGHUP); 64325391Skarels gsignal(tp->t_pgrp, SIGCONT); 64425391Skarels ttyflush(tp, FREAD|FWRITE); 64525391Skarels return (0); 64625391Skarels } 64725391Skarels } 64825391Skarels } else { 64925391Skarels /* 65025391Skarels * Carrier now on. 65125391Skarels */ 65225391Skarels tp->t_state |= TS_CARR_ON; 65325391Skarels wakeup((caddr_t)&tp->t_rawq); 65425391Skarels } 65525391Skarels return (1); 65625391Skarels } 65725391Skarels 65825391Skarels /* 65925404Skarels * Default modem control routine (for other line disciplines). 66025404Skarels * Return argument flag, to turn off device on carrier drop. 66125404Skarels */ 66225415Skarels nullmodem(tp, flag) 66325415Skarels register struct tty *tp; 66425404Skarels int flag; 66525404Skarels { 66625404Skarels 66725404Skarels if (flag) 66825404Skarels tp->t_state |= TS_CARR_ON; 66925404Skarels else 67025404Skarels tp->t_state &= ~TS_CARR_ON; 67125404Skarels return (flag); 67225404Skarels } 67325404Skarels 67425404Skarels /* 6757502Sroot * reinput pending characters after state switch 67617545Skarels * call at spltty(). 6777502Sroot */ 6787502Sroot ttypend(tp) 6797625Ssam register struct tty *tp; 6807502Sroot { 6817502Sroot struct clist tq; 6827502Sroot register c; 6837502Sroot 6849578Ssam tp->t_flags &= ~PENDIN; 6859578Ssam tp->t_state |= TS_TYPEN; 6867502Sroot tq = tp->t_rawq; 6877502Sroot tp->t_rawq.c_cc = 0; 6887502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6897502Sroot while ((c = getc(&tq)) >= 0) 6907502Sroot ttyinput(c, tp); 6919578Ssam tp->t_state &= ~TS_TYPEN; 6927502Sroot } 6937502Sroot 6947502Sroot /* 6959578Ssam * Place a character on raw TTY input queue, 6969578Ssam * putting in delimiters and waking up top 6979578Ssam * half as needed. Also echo if required. 6989578Ssam * The arguments are the character and the 6999578Ssam * appropriate tty structure. 7007502Sroot */ 7017502Sroot ttyinput(c, tp) 7027625Ssam register c; 7037625Ssam register struct tty *tp; 7047502Sroot { 7059578Ssam register int t_flags = tp->t_flags; 7067502Sroot int i; 7077502Sroot 7089578Ssam /* 7099578Ssam * If input is pending take it first. 7109578Ssam */ 7119578Ssam if (t_flags&PENDIN) 7127502Sroot ttypend(tp); 7137502Sroot tk_nin++; 7147502Sroot c &= 0377; 7159578Ssam 7169578Ssam /* 7179578Ssam * In tandem mode, check high water mark. 7189578Ssam */ 7197502Sroot if (t_flags&TANDEM) 7207502Sroot ttyblock(tp); 7219578Ssam 7229578Ssam if (t_flags&RAW) { 7239578Ssam /* 7249578Ssam * Raw mode, just put character 7259578Ssam * in input q w/o interpretation. 7269578Ssam */ 7279578Ssam if (tp->t_rawq.c_cc > TTYHOG) 72812752Ssam ttyflush(tp, FREAD|FWRITE); 7299578Ssam else { 7309578Ssam if (putc(c, &tp->t_rawq) >= 0) 7319578Ssam ttwakeup(tp); 7329578Ssam ttyecho(c, tp); 7337502Sroot } 7349578Ssam goto endcase; 7359578Ssam } 7369578Ssam 7379578Ssam /* 7389578Ssam * Ignore any high bit added during 7399578Ssam * previous ttyinput processing. 7409578Ssam */ 74124273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 7429578Ssam c &= 0177; 7439578Ssam /* 7449578Ssam * Check for literal nexting very first 7459578Ssam */ 7469578Ssam if (tp->t_state&TS_LNCH) { 7479578Ssam c |= 0200; 7489578Ssam tp->t_state &= ~TS_LNCH; 7499578Ssam } 7509578Ssam 7519578Ssam /* 7529578Ssam * Scan for special characters. This code 7539578Ssam * is really just a big case statement with 7549578Ssam * non-constant cases. The bottom of the 7559578Ssam * case statement is labeled ``endcase'', so goto 7569578Ssam * it after a case match, or similar. 7579578Ssam */ 7589578Ssam if (tp->t_line == NTTYDISC) { 7599578Ssam if (c == tp->t_lnextc) { 76021776Sbloom if (t_flags&ECHO) 7617502Sroot ttyout("^\b", tp); 7629578Ssam tp->t_state |= TS_LNCH; 7639578Ssam goto endcase; 7649578Ssam } 7659578Ssam if (c == tp->t_flushc) { 76621776Sbloom if (t_flags&FLUSHO) 7679578Ssam tp->t_flags &= ~FLUSHO; 7687502Sroot else { 76912752Ssam ttyflush(tp, FWRITE); 7707502Sroot ttyecho(c, tp); 7719578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7727502Sroot ttyretype(tp); 7739578Ssam tp->t_flags |= FLUSHO; 7747502Sroot } 7759578Ssam goto startoutput; 7769578Ssam } 7779578Ssam if (c == tp->t_suspc) { 77821776Sbloom if ((t_flags&NOFLSH) == 0) 77912752Ssam ttyflush(tp, FREAD); 7809578Ssam ttyecho(c, tp); 7819578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7829578Ssam goto endcase; 7839578Ssam } 7849578Ssam } 7859578Ssam 7869578Ssam /* 7879578Ssam * Handle start/stop characters. 7889578Ssam */ 7899578Ssam if (c == tp->t_stopc) { 7909578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7919578Ssam tp->t_state |= TS_TTSTOP; 7929578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7937502Sroot return; 7949578Ssam } 7959578Ssam if (c != tp->t_startc) 7969578Ssam return; 7979578Ssam goto endcase; 7989578Ssam } 7999578Ssam if (c == tp->t_startc) 8009578Ssam goto restartoutput; 8019578Ssam 8029578Ssam /* 8039578Ssam * Look for interrupt/quit chars. 8049578Ssam */ 8059578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 80621776Sbloom if ((t_flags&NOFLSH) == 0) 80712752Ssam ttyflush(tp, FREAD|FWRITE); 8089578Ssam ttyecho(c, tp); 8099578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 8109578Ssam goto endcase; 8119578Ssam } 8129578Ssam 81323165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 81423165Sbloom if (tp->t_state&TS_BKSL) { 81523165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 81623165Sbloom if (maptab[c]) 81723165Sbloom c = maptab[c]; 81823165Sbloom c |= 0200; 81923165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 82023165Sbloom } else if (c >= 'A' && c <= 'Z') 82123165Sbloom c += 'a' - 'A'; 82223165Sbloom else if (c == '\\') 82323165Sbloom tp->t_state |= TS_BKSL; 82423165Sbloom } 82523165Sbloom 8269578Ssam /* 8279578Ssam * Cbreak mode, don't process line editing 8289578Ssam * characters; check high water mark for wakeup. 8299578Ssam */ 8309578Ssam if (t_flags&CBREAK) { 8319578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 8327502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 8337502Sroot tp->t_line == NTTYDISC) 8347502Sroot (void) ttyoutput(CTRL(g), tp); 8357502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 8367502Sroot ttwakeup(tp); 8377502Sroot ttyecho(c, tp); 8387502Sroot } 8399578Ssam goto endcase; 8409578Ssam } 8419578Ssam 8429578Ssam /* 8439578Ssam * From here on down cooked mode character 8449578Ssam * processing takes place. 8459578Ssam */ 8469578Ssam if ((tp->t_state&TS_QUOT) && 8479578Ssam (c == tp->t_erase || c == tp->t_kill)) { 8489578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8499578Ssam c |= 0200; 8509578Ssam } 8519578Ssam if (c == tp->t_erase) { 8529578Ssam if (tp->t_rawq.c_cc) 8539578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8549578Ssam goto endcase; 8559578Ssam } 8569578Ssam if (c == tp->t_kill) { 85721776Sbloom if (t_flags&CRTKIL && 8589578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8599578Ssam while (tp->t_rawq.c_cc) 8609578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8619578Ssam } else { 8629578Ssam ttyecho(c, tp); 8639578Ssam ttyecho('\n', tp); 8649578Ssam while (getc(&tp->t_rawq) > 0) 8659578Ssam ; 8669578Ssam tp->t_rocount = 0; 8679578Ssam } 8689578Ssam tp->t_state &= ~TS_LOCAL; 8699578Ssam goto endcase; 8709578Ssam } 8719578Ssam 8729578Ssam /* 8739578Ssam * New line discipline, 8749578Ssam * check word erase/reprint line. 8759578Ssam */ 8769578Ssam if (tp->t_line == NTTYDISC) { 8779578Ssam if (c == tp->t_werasc) { 8789578Ssam if (tp->t_rawq.c_cc == 0) 8799578Ssam goto endcase; 8809578Ssam do { 8819578Ssam c = unputc(&tp->t_rawq); 8829578Ssam if (c != ' ' && c != '\t') 8839578Ssam goto erasenb; 8849578Ssam ttyrub(c, tp); 8859578Ssam } while (tp->t_rawq.c_cc); 8869578Ssam goto endcase; 8879578Ssam erasenb: 8889578Ssam do { 8899578Ssam ttyrub(c, tp); 8909578Ssam if (tp->t_rawq.c_cc == 0) 8919578Ssam goto endcase; 8929578Ssam c = unputc(&tp->t_rawq); 8939578Ssam } while (c != ' ' && c != '\t'); 8949578Ssam (void) putc(c, &tp->t_rawq); 8959578Ssam goto endcase; 8969578Ssam } 8979578Ssam if (c == tp->t_rprntc) { 8989578Ssam ttyretype(tp); 8999578Ssam goto endcase; 9009578Ssam } 9019578Ssam } 9029578Ssam 9039578Ssam /* 9049578Ssam * Check for input buffer overflow 9059578Ssam */ 90610391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 90710391Ssam if (tp->t_line == NTTYDISC) 90810391Ssam (void) ttyoutput(CTRL(g), tp); 9099578Ssam goto endcase; 91010391Ssam } 9119578Ssam 9129578Ssam /* 9139578Ssam * Put data char in q for user and 9149578Ssam * wakeup on seeing a line delimiter. 9159578Ssam */ 9169578Ssam if (putc(c, &tp->t_rawq) >= 0) { 9179578Ssam if (ttbreakc(c, tp)) { 9189578Ssam tp->t_rocount = 0; 9199578Ssam catq(&tp->t_rawq, &tp->t_canq); 9207502Sroot ttwakeup(tp); 9219578Ssam } else if (tp->t_rocount++ == 0) 9229578Ssam tp->t_rocol = tp->t_col; 9239578Ssam tp->t_state &= ~TS_QUOT; 9249578Ssam if (c == '\\') 9259578Ssam tp->t_state |= TS_QUOT; 9269578Ssam if (tp->t_state&TS_ERASE) { 9279578Ssam tp->t_state &= ~TS_ERASE; 9289578Ssam (void) ttyoutput('/', tp); 9299578Ssam } 9309578Ssam i = tp->t_col; 9317502Sroot ttyecho(c, tp); 93221776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 9339578Ssam i = MIN(2, tp->t_col - i); 9349578Ssam while (i > 0) { 9359578Ssam (void) ttyoutput('\b', tp); 9369578Ssam i--; 9379578Ssam } 9389578Ssam } 9397502Sroot } 9409578Ssam endcase: 9419578Ssam /* 9429578Ssam * If DEC-style start/stop is enabled don't restart 9439578Ssam * output until seeing the start character. 9449578Ssam */ 94521776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 9469578Ssam tp->t_startc != tp->t_stopc) 9477502Sroot return; 9489578Ssam restartoutput: 9497502Sroot tp->t_state &= ~TS_TTSTOP; 9509578Ssam tp->t_flags &= ~FLUSHO; 9519578Ssam startoutput: 9527502Sroot ttstart(tp); 9537502Sroot } 9547502Sroot 9557502Sroot /* 9569578Ssam * Put character on TTY output queue, adding delays, 9577502Sroot * expanding tabs, and handling the CR/NL bit. 9589578Ssam * This is called both from the top half for output, 9599578Ssam * and from interrupt level for echoing. 9607502Sroot * The arguments are the character and the tty structure. 9617502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 9627502Sroot * Must be recursive. 9637502Sroot */ 9647502Sroot ttyoutput(c, tp) 9657502Sroot register c; 9667502Sroot register struct tty *tp; 9677502Sroot { 9687502Sroot register char *colp; 9697502Sroot register ctype; 9707502Sroot 9719578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9729578Ssam if (tp->t_flags&FLUSHO) 9737502Sroot return (-1); 9747502Sroot if (putc(c, &tp->t_outq)) 9757625Ssam return (c); 9767502Sroot tk_nout++; 9777502Sroot return (-1); 9787502Sroot } 9799578Ssam 9807502Sroot /* 9819578Ssam * Ignore EOT in normal mode to avoid 9829578Ssam * hanging up certain terminals. 9837502Sroot */ 9847502Sroot c &= 0177; 9859578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9867502Sroot return (-1); 9877502Sroot /* 9887502Sroot * Turn tabs to spaces as required 9897502Sroot */ 9909578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9917502Sroot register int s; 9927502Sroot 9937502Sroot c = 8 - (tp->t_col&7); 9949578Ssam if ((tp->t_flags&FLUSHO) == 0) { 99517545Skarels s = spltty(); /* don't interrupt tabs */ 9967502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9977502Sroot tk_nout += c; 9987502Sroot splx(s); 9997502Sroot } 10007502Sroot tp->t_col += c; 10017502Sroot return (c ? -1 : '\t'); 10027502Sroot } 10037502Sroot tk_nout++; 10047502Sroot /* 10057502Sroot * for upper-case-only terminals, 10067502Sroot * generate escapes. 10077502Sroot */ 10087502Sroot if (tp->t_flags&LCASE) { 10097502Sroot colp = "({)}!|^~'`"; 10107625Ssam while (*colp++) 10117625Ssam if (c == *colp++) { 10127502Sroot if (ttyoutput('\\', tp) >= 0) 10137502Sroot return (c); 10147502Sroot c = colp[-2]; 10157502Sroot break; 10167502Sroot } 10179578Ssam if ('A' <= c && c <= 'Z') { 10187502Sroot if (ttyoutput('\\', tp) >= 0) 10197502Sroot return (c); 10209578Ssam } else if ('a' <= c && c <= 'z') 10217502Sroot c += 'A' - 'a'; 10227502Sroot } 10239578Ssam 10247502Sroot /* 10257502Sroot * turn <nl> to <cr><lf> if desired. 10267502Sroot */ 10279578Ssam if (c == '\n' && tp->t_flags&CRMOD) 10287502Sroot if (ttyoutput('\r', tp) >= 0) 10297502Sroot return (c); 10309578Ssam if (c == '~' && tp->t_flags&TILDE) 10317502Sroot c = '`'; 10329578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 10337502Sroot return (c); 10347502Sroot /* 10357502Sroot * Calculate delays. 10367502Sroot * The numbers here represent clock ticks 10377502Sroot * and are not necessarily optimal for all terminals. 10387502Sroot * The delays are indicated by characters above 0200. 10397502Sroot * In raw mode there are no delays and the 10407502Sroot * transmission path is 8 bits wide. 10419578Ssam * 10429578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 10437502Sroot */ 10447502Sroot colp = &tp->t_col; 10457502Sroot ctype = partab[c]; 10467502Sroot c = 0; 10477502Sroot switch (ctype&077) { 10487502Sroot 10497502Sroot case ORDINARY: 10507502Sroot (*colp)++; 10517502Sroot 10527502Sroot case CONTROL: 10537502Sroot break; 10547502Sroot 10557502Sroot case BACKSPACE: 10567502Sroot if (*colp) 10577502Sroot (*colp)--; 10587502Sroot break; 10597502Sroot 106013821Ssam /* 106113821Ssam * This macro is close enough to the correct thing; 106213821Ssam * it should be replaced by real user settable delays 106313821Ssam * in any event... 106413821Ssam */ 106513821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10667502Sroot case NEWLINE: 10677502Sroot ctype = (tp->t_flags >> 8) & 03; 10687625Ssam if (ctype == 1) { /* tty 37 */ 106912752Ssam if (*colp > 0) 107013863Ssam c = max((((unsigned)*colp) >> 4) + 3, 107113863Ssam (unsigned)6); 10729578Ssam } else if (ctype == 2) /* vt05 */ 107313821Ssam c = mstohz(100); 10747502Sroot *colp = 0; 10757502Sroot break; 10767502Sroot 10777502Sroot case TAB: 10787502Sroot ctype = (tp->t_flags >> 10) & 03; 10797625Ssam if (ctype == 1) { /* tty 37 */ 10807502Sroot c = 1 - (*colp | ~07); 10817625Ssam if (c < 5) 10827502Sroot c = 0; 10837502Sroot } 10847502Sroot *colp |= 07; 10857502Sroot (*colp)++; 10867502Sroot break; 10877502Sroot 10887502Sroot case VTAB: 10899578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10907502Sroot c = 0177; 10917502Sroot break; 10927502Sroot 10937502Sroot case RETURN: 10947502Sroot ctype = (tp->t_flags >> 12) & 03; 10959578Ssam if (ctype == 1) /* tn 300 */ 109613821Ssam c = mstohz(83); 10979578Ssam else if (ctype == 2) /* ti 700 */ 109813821Ssam c = mstohz(166); 10999578Ssam else if (ctype == 3) { /* concept 100 */ 11007502Sroot int i; 11019578Ssam 11027502Sroot if ((i = *colp) >= 0) 11039578Ssam for (; i < 9; i++) 11047502Sroot (void) putc(0177, &tp->t_outq); 11057502Sroot } 11067502Sroot *colp = 0; 11077502Sroot } 11089578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 11097502Sroot (void) putc(c|0200, &tp->t_outq); 11107502Sroot return (-1); 11117502Sroot } 111213821Ssam #undef mstohz 11137502Sroot 11147502Sroot /* 11157502Sroot * Called from device's read routine after it has 11167502Sroot * calculated the tty-structure given as argument. 11177502Sroot */ 11187722Swnj ttread(tp, uio) 11197625Ssam register struct tty *tp; 11207722Swnj struct uio *uio; 11217502Sroot { 11227502Sroot register struct clist *qp; 11239578Ssam register c, t_flags; 11249859Ssam int s, first, error = 0; 11257502Sroot 11267502Sroot loop: 11279578Ssam /* 11289578Ssam * Take any pending input first. 11299578Ssam */ 113017545Skarels s = spltty(); 11319578Ssam if (tp->t_flags&PENDIN) 11327502Sroot ttypend(tp); 11339859Ssam splx(s); 11349578Ssam 113523165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 113623165Sbloom return (EIO); 113723165Sbloom 11389578Ssam /* 11399578Ssam * Hang process if it's in the background. 11409578Ssam */ 114123165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 114224392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 114324392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11447502Sroot u.u_procp->p_flag&SVFORK) 11458520Sroot return (EIO); 11467502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11477502Sroot sleep((caddr_t)&lbolt, TTIPRI); 114823165Sbloom goto loop; 11497502Sroot } 11509578Ssam t_flags = tp->t_flags; 11519578Ssam 11529578Ssam /* 11539578Ssam * In raw mode take characters directly from the 11549578Ssam * raw queue w/o processing. Interlock against 11559578Ssam * device interrupts when interrogating rawq. 11569578Ssam */ 11579578Ssam if (t_flags&RAW) { 115817545Skarels s = spltty(); 11597502Sroot if (tp->t_rawq.c_cc <= 0) { 11609578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11617502Sroot (tp->t_state&TS_NBIO)) { 11629859Ssam splx(s); 116315094Skarels return (EWOULDBLOCK); 11647502Sroot } 11657502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11669859Ssam splx(s); 11677502Sroot goto loop; 11687502Sroot } 11699859Ssam splx(s); 117014938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 117114938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11729859Ssam goto checktandem; 11739578Ssam } 11749578Ssam 11759578Ssam /* 11769578Ssam * In cbreak mode use the rawq, otherwise 11779578Ssam * take characters from the canonicalized q. 11789578Ssam */ 11799578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11809578Ssam 11819578Ssam /* 11829578Ssam * No input, sleep on rawq awaiting hardware 11839578Ssam * receipt and notification. 11849578Ssam */ 118517545Skarels s = spltty(); 11869578Ssam if (qp->c_cc <= 0) { 11879578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11889578Ssam (tp->t_state&TS_NBIO)) { 11899859Ssam splx(s); 11909578Ssam return (EWOULDBLOCK); 11917502Sroot } 11929578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11939859Ssam splx(s); 11949578Ssam goto loop; 11959578Ssam } 11969859Ssam splx(s); 11979578Ssam 11989578Ssam /* 11999578Ssam * Input present, perform input mapping 12009578Ssam * and processing (we're not in raw mode). 12019578Ssam */ 12029578Ssam first = 1; 12039578Ssam while ((c = getc(qp)) >= 0) { 12049578Ssam if (t_flags&CRMOD && c == '\r') 12059578Ssam c = '\n'; 12069578Ssam /* 12079578Ssam * Check for delayed suspend character. 12089578Ssam */ 12099578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 12109578Ssam gsignal(tp->t_pgrp, SIGTSTP); 12119578Ssam if (first) { 12129578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12139578Ssam goto loop; 12149578Ssam } 12159578Ssam break; 12167502Sroot } 12179578Ssam /* 12189578Ssam * Interpret EOF only in cooked mode. 12199578Ssam */ 12209578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12219578Ssam break; 12229578Ssam /* 12239578Ssam * Give user character. 12249578Ssam */ 122524273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12269578Ssam if (error) 12279578Ssam break; 122814938Smckusick if (uio->uio_resid == 0) 12299578Ssam break; 12309578Ssam /* 12319578Ssam * In cooked mode check for a "break character" 12329578Ssam * marking the end of a "line of input". 12339578Ssam */ 12349578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12359578Ssam break; 12369578Ssam first = 0; 12377502Sroot } 12389578Ssam 12399859Ssam checktandem: 12409578Ssam /* 12419578Ssam * Look to unblock output now that (presumably) 12429578Ssam * the input queue has gone down. 12439578Ssam */ 12449859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 12459578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 12467502Sroot tp->t_state &= ~TS_TBLOCK; 12477502Sroot ttstart(tp); 12487502Sroot } 12498520Sroot return (error); 12507502Sroot } 12517502Sroot 12527502Sroot /* 125325391Skarels * Check the output queue on tp for space for a kernel message 125425391Skarels * (from uprintf/tprintf). Allow some space over the normal 125525391Skarels * hiwater mark so we don't lose messages due to normal flow 125625391Skarels * control, but don't let the tty run amok. 125725391Skarels */ 125825391Skarels ttycheckoutq(tp, wait) 125925391Skarels register struct tty *tp; 126025391Skarels int wait; 126125391Skarels { 126225391Skarels int hiwat, s; 126325391Skarels 126425391Skarels hiwat = TTHIWAT(tp); 126525391Skarels s = spltty(); 126625391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126725391Skarels while (tp->t_outq.c_cc > hiwat) { 126825391Skarels ttstart(tp); 126925391Skarels if (wait == 0) { 127025391Skarels splx(s); 127125391Skarels return (0); 127225391Skarels } 127325391Skarels tp->t_state |= TS_ASLEEP; 127425391Skarels sleep((caddr_t)&tp->t_outq, TTOPRI); 127525391Skarels } 127625391Skarels splx(s); 127725391Skarels return (1); 127825391Skarels } 127925391Skarels 128025391Skarels /* 12817502Sroot * Called from the device's write routine after it has 12827502Sroot * calculated the tty-structure given as argument. 12837502Sroot */ 12847822Sroot ttwrite(tp, uio) 12857625Ssam register struct tty *tp; 12869578Ssam register struct uio *uio; 12877502Sroot { 12887502Sroot register char *cp; 12899578Ssam register int cc, ce, c; 12909578Ssam int i, hiwat, cnt, error, s; 12917502Sroot char obuf[OBUFSIZ]; 12927502Sroot 12939578Ssam hiwat = TTHIWAT(tp); 12949578Ssam cnt = uio->uio_resid; 12959578Ssam error = 0; 12967502Sroot loop: 129721776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 129821776Sbloom return (EIO); 12999578Ssam /* 13009578Ssam * Hang the process if it's in the background. 13019578Ssam */ 130221776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 13039578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 130424392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 130524392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 13067502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 13077502Sroot sleep((caddr_t)&lbolt, TTIPRI); 130821776Sbloom goto loop; 13097502Sroot } 13109578Ssam 13119578Ssam /* 13129578Ssam * Process the user's data in at most OBUFSIZ 13139578Ssam * chunks. Perform lower case simulation and 13149578Ssam * similar hacks. Keep track of high water 13159578Ssam * mark, sleep on overflow awaiting device aid 13169578Ssam * in acquiring new space. 13179578Ssam */ 13187822Sroot while (uio->uio_resid > 0) { 13199578Ssam /* 13209578Ssam * Grab a hunk of data from the user. 13219578Ssam */ 13227822Sroot cc = uio->uio_iov->iov_len; 13237822Sroot if (cc == 0) { 13247822Sroot uio->uio_iovcnt--; 13257822Sroot uio->uio_iov++; 132621776Sbloom if (uio->uio_iovcnt <= 0) 13277822Sroot panic("ttwrite"); 13287822Sroot continue; 13297822Sroot } 13307822Sroot if (cc > OBUFSIZ) 13317822Sroot cc = OBUFSIZ; 13327502Sroot cp = obuf; 133312752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13348520Sroot if (error) 13357502Sroot break; 13367502Sroot if (tp->t_outq.c_cc > hiwat) 13377502Sroot goto ovhiwat; 13389578Ssam if (tp->t_flags&FLUSHO) 13397502Sroot continue; 13409578Ssam /* 13419578Ssam * If we're mapping lower case or kludging tildes, 13429578Ssam * then we've got to look at each character, so 13439578Ssam * just feed the stuff to ttyoutput... 13449578Ssam */ 13459578Ssam if (tp->t_flags & (LCASE|TILDE)) { 13469578Ssam while (cc > 0) { 13477502Sroot c = *cp++; 13487502Sroot tp->t_rocount = 0; 13497625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 13507502Sroot /* out of clists, wait a bit */ 13517502Sroot ttstart(tp); 13527502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13537502Sroot tp->t_rocount = 0; 135421776Sbloom if (cc != 0) { 135521776Sbloom uio->uio_iov->iov_base -= cc; 135621776Sbloom uio->uio_iov->iov_len += cc; 135721776Sbloom uio->uio_resid += cc; 135821776Sbloom uio->uio_offset -= cc; 135921776Sbloom } 136021776Sbloom goto loop; 13617502Sroot } 13627502Sroot --cc; 13637502Sroot if (tp->t_outq.c_cc > hiwat) 13647502Sroot goto ovhiwat; 13657502Sroot } 13667502Sroot continue; 13677502Sroot } 13689578Ssam /* 13699578Ssam * If nothing fancy need be done, grab those characters we 13709578Ssam * can handle without any of ttyoutput's processing and 13719578Ssam * just transfer them to the output q. For those chars 13729578Ssam * which require special processing (as indicated by the 13739578Ssam * bits in partab), call ttyoutput. After processing 13749578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13759578Ssam * immediately. 13769578Ssam */ 13779578Ssam while (cc > 0) { 13789578Ssam if (tp->t_flags & (RAW|LITOUT)) 13797502Sroot ce = cc; 13807502Sroot else { 138112752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 138212752Ssam (caddr_t)partab, 077); 13839578Ssam /* 13849578Ssam * If ce is zero, then we're processing 13859578Ssam * a special character through ttyoutput. 13869578Ssam */ 13879578Ssam if (ce == 0) { 13887502Sroot tp->t_rocount = 0; 13897502Sroot if (ttyoutput(*cp, tp) >= 0) { 139021776Sbloom /* no c-lists, wait a bit */ 139121776Sbloom ttstart(tp); 139221776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 139321776Sbloom if (cc != 0) { 139421776Sbloom uio->uio_iov->iov_base -= cc; 139521776Sbloom uio->uio_iov->iov_len += cc; 139621776Sbloom uio->uio_resid += cc; 139721776Sbloom uio->uio_offset -= cc; 139821776Sbloom } 139921776Sbloom goto loop; 14007502Sroot } 14019578Ssam cp++, cc--; 14029578Ssam if (tp->t_flags&FLUSHO || 14039578Ssam tp->t_outq.c_cc > hiwat) 14047502Sroot goto ovhiwat; 14059578Ssam continue; 14067502Sroot } 14077502Sroot } 14089578Ssam /* 14099578Ssam * A bunch of normal characters have been found, 14109578Ssam * transfer them en masse to the output queue and 14119578Ssam * continue processing at the top of the loop. 14129578Ssam * If there are any further characters in this 14139578Ssam * <= OBUFSIZ chunk, the first should be a character 14149578Ssam * requiring special handling by ttyoutput. 14159578Ssam */ 14167502Sroot tp->t_rocount = 0; 14179578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14189578Ssam ce -= i; 14199578Ssam tp->t_col += ce; 14209578Ssam cp += ce, cc -= ce, tk_nout += ce; 14219578Ssam if (i > 0) { 14229578Ssam /* out of c-lists, wait a bit */ 14237502Sroot ttstart(tp); 14247502Sroot sleep((caddr_t)&lbolt, TTOPRI); 142521776Sbloom uio->uio_iov->iov_base -= cc; 142621776Sbloom uio->uio_iov->iov_len += cc; 142721776Sbloom uio->uio_resid += cc; 142821776Sbloom uio->uio_offset -= cc; 142921776Sbloom goto loop; 14307502Sroot } 14319578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14327502Sroot goto ovhiwat; 14337502Sroot } 14347502Sroot } 14357502Sroot ttstart(tp); 14368520Sroot return (error); 14377502Sroot 14387502Sroot ovhiwat: 143917545Skarels s = spltty(); 14409578Ssam if (cc != 0) { 14419578Ssam uio->uio_iov->iov_base -= cc; 14429578Ssam uio->uio_iov->iov_len += cc; 14439578Ssam uio->uio_resid += cc; 14449578Ssam uio->uio_offset -= cc; 14459578Ssam } 14469578Ssam /* 14479578Ssam * This can only occur if FLUSHO 14489578Ssam * is also set in t_flags. 14499578Ssam */ 14507502Sroot if (tp->t_outq.c_cc <= hiwat) { 14519578Ssam splx(s); 14527502Sroot goto loop; 14537502Sroot } 14547502Sroot ttstart(tp); 14559578Ssam if (tp->t_state&TS_NBIO) { 145617545Skarels splx(s); 14577822Sroot if (uio->uio_resid == cnt) 14588520Sroot return (EWOULDBLOCK); 14598520Sroot return (0); 14607502Sroot } 14617502Sroot tp->t_state |= TS_ASLEEP; 14627502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14639578Ssam splx(s); 14647502Sroot goto loop; 14657502Sroot } 14667502Sroot 14677502Sroot /* 14687502Sroot * Rubout one character from the rawq of tp 14697502Sroot * as cleanly as possible. 14707502Sroot */ 14717502Sroot ttyrub(c, tp) 14727625Ssam register c; 14737625Ssam register struct tty *tp; 14747502Sroot { 14757502Sroot register char *cp; 14767502Sroot register int savecol; 14777502Sroot int s; 14787502Sroot char *nextc(); 14797502Sroot 14809578Ssam if ((tp->t_flags&ECHO) == 0) 14817502Sroot return; 14829578Ssam tp->t_flags &= ~FLUSHO; 14837502Sroot c &= 0377; 14849578Ssam if (tp->t_flags&CRTBS) { 14857502Sroot if (tp->t_rocount == 0) { 14867502Sroot /* 14877502Sroot * Screwed by ttwrite; retype 14887502Sroot */ 14897502Sroot ttyretype(tp); 14907502Sroot return; 14917502Sroot } 14929578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14937502Sroot ttyrubo(tp, 2); 14949578Ssam else switch (partab[c&=0177]&0177) { 14957502Sroot 14967502Sroot case ORDINARY: 14977502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14987502Sroot ttyrubo(tp, 2); 14997502Sroot else 15007502Sroot ttyrubo(tp, 1); 15017502Sroot break; 15027502Sroot 15037502Sroot case VTAB: 15047502Sroot case BACKSPACE: 15057502Sroot case CONTROL: 15067502Sroot case RETURN: 15079578Ssam if (tp->t_flags&CTLECH) 15087502Sroot ttyrubo(tp, 2); 15097502Sroot break; 15107502Sroot 15117502Sroot case TAB: 15127502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15137502Sroot ttyretype(tp); 15147502Sroot return; 15157502Sroot } 151617545Skarels s = spltty(); 15177502Sroot savecol = tp->t_col; 15189578Ssam tp->t_state |= TS_CNTTB; 15199578Ssam tp->t_flags |= FLUSHO; 15207502Sroot tp->t_col = tp->t_rocol; 15219578Ssam cp = tp->t_rawq.c_cf; 15229578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 15237502Sroot ttyecho(*cp, tp); 15249578Ssam tp->t_flags &= ~FLUSHO; 15259578Ssam tp->t_state &= ~TS_CNTTB; 15267502Sroot splx(s); 15277502Sroot /* 15287502Sroot * savecol will now be length of the tab 15297502Sroot */ 15307502Sroot savecol -= tp->t_col; 15317502Sroot tp->t_col += savecol; 15327502Sroot if (savecol > 8) 15337502Sroot savecol = 8; /* overflow screw */ 15347502Sroot while (--savecol >= 0) 15357502Sroot (void) ttyoutput('\b', tp); 15367502Sroot break; 15377502Sroot 15387502Sroot default: 15397502Sroot panic("ttyrub"); 15407502Sroot } 15419578Ssam } else if (tp->t_flags&PRTERA) { 15429578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15437502Sroot (void) ttyoutput('\\', tp); 15449578Ssam tp->t_state |= TS_ERASE; 15457502Sroot } 15467502Sroot ttyecho(c, tp); 15477502Sroot } else 15487502Sroot ttyecho(tp->t_erase, tp); 15497502Sroot tp->t_rocount--; 15507502Sroot } 15517502Sroot 15527502Sroot /* 15537502Sroot * Crt back over cnt chars perhaps 15547502Sroot * erasing them. 15557502Sroot */ 15567502Sroot ttyrubo(tp, cnt) 15577625Ssam register struct tty *tp; 15587625Ssam int cnt; 15597502Sroot { 15609578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 15617502Sroot 15627502Sroot while (--cnt >= 0) 15639578Ssam ttyout(rubostring, tp); 15647502Sroot } 15657502Sroot 15667502Sroot /* 15677502Sroot * Reprint the rawq line. 15687502Sroot * We assume c_cc has already been checked. 15697502Sroot */ 15707502Sroot ttyretype(tp) 15717625Ssam register struct tty *tp; 15727502Sroot { 15737502Sroot register char *cp; 15747502Sroot char *nextc(); 15757502Sroot int s; 15767502Sroot 15779578Ssam if (tp->t_rprntc != 0377) 15789578Ssam ttyecho(tp->t_rprntc, tp); 15797502Sroot (void) ttyoutput('\n', tp); 158017545Skarels s = spltty(); 15817502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 15827502Sroot ttyecho(*cp, tp); 15837502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 15847502Sroot ttyecho(*cp, tp); 15859578Ssam tp->t_state &= ~TS_ERASE; 15867502Sroot splx(s); 15877502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15887502Sroot tp->t_rocol = 0; 15897502Sroot } 15907502Sroot 15917502Sroot /* 15927502Sroot * Echo a typed character to the terminal 15937502Sroot */ 15947502Sroot ttyecho(c, tp) 15957625Ssam register c; 15967625Ssam register struct tty *tp; 15977502Sroot { 15987502Sroot 15999578Ssam if ((tp->t_state&TS_CNTTB) == 0) 16009578Ssam tp->t_flags &= ~FLUSHO; 16017502Sroot if ((tp->t_flags&ECHO) == 0) 16027502Sroot return; 16037502Sroot c &= 0377; 16047502Sroot if (tp->t_flags&RAW) { 16057502Sroot (void) ttyoutput(c, tp); 16067502Sroot return; 16077502Sroot } 16087502Sroot if (c == '\r' && tp->t_flags&CRMOD) 16097502Sroot c = '\n'; 16109578Ssam if (tp->t_flags&CTLECH) { 16117502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 16127502Sroot (void) ttyoutput('^', tp); 16137502Sroot c &= 0177; 16147502Sroot if (c == 0177) 16157502Sroot c = '?'; 16167502Sroot else if (tp->t_flags&LCASE) 16177502Sroot c += 'a' - 1; 16187502Sroot else 16197502Sroot c += 'A' - 1; 16207502Sroot } 16217502Sroot } 16229578Ssam (void) ttyoutput(c&0177, tp); 16237502Sroot } 16247502Sroot 16257502Sroot /* 16267502Sroot * Is c a break char for tp? 16277502Sroot */ 16287502Sroot ttbreakc(c, tp) 16297625Ssam register c; 16307625Ssam register struct tty *tp; 16317502Sroot { 16329578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 16337502Sroot c == '\r' && (tp->t_flags&CRMOD)); 16347502Sroot } 16357502Sroot 16367502Sroot /* 16377502Sroot * send string cp to tp 16387502Sroot */ 16397502Sroot ttyout(cp, tp) 16407625Ssam register char *cp; 16417625Ssam register struct tty *tp; 16427502Sroot { 16437502Sroot register char c; 16447502Sroot 16457502Sroot while (c = *cp++) 16467502Sroot (void) ttyoutput(c, tp); 16477502Sroot } 16487502Sroot 16497502Sroot ttwakeup(tp) 16507502Sroot struct tty *tp; 16517502Sroot { 16527502Sroot 16537502Sroot if (tp->t_rsel) { 16547502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16557502Sroot tp->t_state &= ~TS_RCOLL; 16567502Sroot tp->t_rsel = 0; 16577502Sroot } 165812752Ssam if (tp->t_state & TS_ASYNC) 165912752Ssam gsignal(tp->t_pgrp, SIGIO); 16607502Sroot wakeup((caddr_t)&tp->t_rawq); 16617502Sroot } 1662