123387Smckusick /* 2*29107Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323387Smckusick * All rights reserved. The Berkeley software License Agreement 423387Smckusick * specifies the terms and conditions for redistribution. 523387Smckusick * 6*29107Smckusick * @(#)tty.c 7.1 (Berkeley) 06/05/86 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); 29325584Skarels if (t != tp->t_line) { 29425584Skarels s = spltty(); 29525584Skarels (*linesw[tp->t_line].l_close)(tp); 29625584Skarels error = (*linesw[t].l_open)(dev, tp); 29725584Skarels if (error) { 29825584Skarels (void) (*linesw[tp->t_line].l_open)(dev, tp); 29925584Skarels splx(s); 30025584Skarels return (error); 30125584Skarels } 30225584Skarels 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 */ 106926357Skarels if (*colp > 0) { 107026357Skarels c = (((unsigned)*colp) >> 4) + 3; 107126357Skarels if ((unsigned)c > 6) 107226357Skarels c = 6; 107326357Skarels } 10749578Ssam } else if (ctype == 2) /* vt05 */ 107513821Ssam c = mstohz(100); 10767502Sroot *colp = 0; 10777502Sroot break; 10787502Sroot 10797502Sroot case TAB: 10807502Sroot ctype = (tp->t_flags >> 10) & 03; 10817625Ssam if (ctype == 1) { /* tty 37 */ 10827502Sroot c = 1 - (*colp | ~07); 10837625Ssam if (c < 5) 10847502Sroot c = 0; 10857502Sroot } 10867502Sroot *colp |= 07; 10877502Sroot (*colp)++; 10887502Sroot break; 10897502Sroot 10907502Sroot case VTAB: 10919578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10927502Sroot c = 0177; 10937502Sroot break; 10947502Sroot 10957502Sroot case RETURN: 10967502Sroot ctype = (tp->t_flags >> 12) & 03; 10979578Ssam if (ctype == 1) /* tn 300 */ 109813821Ssam c = mstohz(83); 10999578Ssam else if (ctype == 2) /* ti 700 */ 110013821Ssam c = mstohz(166); 11019578Ssam else if (ctype == 3) { /* concept 100 */ 11027502Sroot int i; 11039578Ssam 11047502Sroot if ((i = *colp) >= 0) 11059578Ssam for (; i < 9; i++) 11067502Sroot (void) putc(0177, &tp->t_outq); 11077502Sroot } 11087502Sroot *colp = 0; 11097502Sroot } 11109578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 11117502Sroot (void) putc(c|0200, &tp->t_outq); 11127502Sroot return (-1); 11137502Sroot } 111413821Ssam #undef mstohz 11157502Sroot 11167502Sroot /* 11177502Sroot * Called from device's read routine after it has 11187502Sroot * calculated the tty-structure given as argument. 11197502Sroot */ 11207722Swnj ttread(tp, uio) 11217625Ssam register struct tty *tp; 11227722Swnj struct uio *uio; 11237502Sroot { 11247502Sroot register struct clist *qp; 11259578Ssam register c, t_flags; 11269859Ssam int s, first, error = 0; 11277502Sroot 11287502Sroot loop: 11299578Ssam /* 11309578Ssam * Take any pending input first. 11319578Ssam */ 113217545Skarels s = spltty(); 11339578Ssam if (tp->t_flags&PENDIN) 11347502Sroot ttypend(tp); 11359859Ssam splx(s); 11369578Ssam 113723165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 113823165Sbloom return (EIO); 113923165Sbloom 11409578Ssam /* 11419578Ssam * Hang process if it's in the background. 11429578Ssam */ 114323165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 114424392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 114524392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11467502Sroot u.u_procp->p_flag&SVFORK) 11478520Sroot return (EIO); 11487502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11497502Sroot sleep((caddr_t)&lbolt, TTIPRI); 115023165Sbloom goto loop; 11517502Sroot } 11529578Ssam t_flags = tp->t_flags; 11539578Ssam 11549578Ssam /* 11559578Ssam * In raw mode take characters directly from the 11569578Ssam * raw queue w/o processing. Interlock against 11579578Ssam * device interrupts when interrogating rawq. 11589578Ssam */ 11599578Ssam if (t_flags&RAW) { 116017545Skarels s = spltty(); 11617502Sroot if (tp->t_rawq.c_cc <= 0) { 11629578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11637502Sroot (tp->t_state&TS_NBIO)) { 11649859Ssam splx(s); 116515094Skarels return (EWOULDBLOCK); 11667502Sroot } 11677502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11689859Ssam splx(s); 11697502Sroot goto loop; 11707502Sroot } 11719859Ssam splx(s); 117214938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 117314938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11749859Ssam goto checktandem; 11759578Ssam } 11769578Ssam 11779578Ssam /* 11789578Ssam * In cbreak mode use the rawq, otherwise 11799578Ssam * take characters from the canonicalized q. 11809578Ssam */ 11819578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11829578Ssam 11839578Ssam /* 11849578Ssam * No input, sleep on rawq awaiting hardware 11859578Ssam * receipt and notification. 11869578Ssam */ 118717545Skarels s = spltty(); 11889578Ssam if (qp->c_cc <= 0) { 11899578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11909578Ssam (tp->t_state&TS_NBIO)) { 11919859Ssam splx(s); 11929578Ssam return (EWOULDBLOCK); 11937502Sroot } 11949578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11959859Ssam splx(s); 11969578Ssam goto loop; 11979578Ssam } 11989859Ssam splx(s); 11999578Ssam 12009578Ssam /* 12019578Ssam * Input present, perform input mapping 12029578Ssam * and processing (we're not in raw mode). 12039578Ssam */ 12049578Ssam first = 1; 12059578Ssam while ((c = getc(qp)) >= 0) { 12069578Ssam if (t_flags&CRMOD && c == '\r') 12079578Ssam c = '\n'; 12089578Ssam /* 12099578Ssam * Check for delayed suspend character. 12109578Ssam */ 12119578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 12129578Ssam gsignal(tp->t_pgrp, SIGTSTP); 12139578Ssam if (first) { 12149578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12159578Ssam goto loop; 12169578Ssam } 12179578Ssam break; 12187502Sroot } 12199578Ssam /* 12209578Ssam * Interpret EOF only in cooked mode. 12219578Ssam */ 12229578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12239578Ssam break; 12249578Ssam /* 12259578Ssam * Give user character. 12269578Ssam */ 122724273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12289578Ssam if (error) 12299578Ssam break; 123014938Smckusick if (uio->uio_resid == 0) 12319578Ssam break; 12329578Ssam /* 12339578Ssam * In cooked mode check for a "break character" 12349578Ssam * marking the end of a "line of input". 12359578Ssam */ 12369578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12379578Ssam break; 12389578Ssam first = 0; 12397502Sroot } 12409578Ssam 12419859Ssam checktandem: 12429578Ssam /* 12439578Ssam * Look to unblock output now that (presumably) 12449578Ssam * the input queue has gone down. 12459578Ssam */ 12469859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 12479578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 12487502Sroot tp->t_state &= ~TS_TBLOCK; 12497502Sroot ttstart(tp); 12507502Sroot } 12518520Sroot return (error); 12527502Sroot } 12537502Sroot 12547502Sroot /* 125525391Skarels * Check the output queue on tp for space for a kernel message 125625391Skarels * (from uprintf/tprintf). Allow some space over the normal 125725391Skarels * hiwater mark so we don't lose messages due to normal flow 125825391Skarels * control, but don't let the tty run amok. 125925391Skarels */ 126025391Skarels ttycheckoutq(tp, wait) 126125391Skarels register struct tty *tp; 126225391Skarels int wait; 126325391Skarels { 126425391Skarels int hiwat, s; 126525391Skarels 126625391Skarels hiwat = TTHIWAT(tp); 126725391Skarels s = spltty(); 126825391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126925391Skarels while (tp->t_outq.c_cc > hiwat) { 127025391Skarels ttstart(tp); 127125391Skarels if (wait == 0) { 127225391Skarels splx(s); 127325391Skarels return (0); 127425391Skarels } 127525391Skarels tp->t_state |= TS_ASLEEP; 127625391Skarels sleep((caddr_t)&tp->t_outq, TTOPRI); 127725391Skarels } 127825391Skarels splx(s); 127925391Skarels return (1); 128025391Skarels } 128125391Skarels 128225391Skarels /* 12837502Sroot * Called from the device's write routine after it has 12847502Sroot * calculated the tty-structure given as argument. 12857502Sroot */ 12867822Sroot ttwrite(tp, uio) 12877625Ssam register struct tty *tp; 12889578Ssam register struct uio *uio; 12897502Sroot { 12907502Sroot register char *cp; 12919578Ssam register int cc, ce, c; 12929578Ssam int i, hiwat, cnt, error, s; 12937502Sroot char obuf[OBUFSIZ]; 12947502Sroot 12959578Ssam hiwat = TTHIWAT(tp); 12969578Ssam cnt = uio->uio_resid; 12979578Ssam error = 0; 12987502Sroot loop: 129921776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 130021776Sbloom return (EIO); 13019578Ssam /* 13029578Ssam * Hang the process if it's in the background. 13039578Ssam */ 130421776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 13059578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 130624392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 130724392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 13087502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 13097502Sroot sleep((caddr_t)&lbolt, TTIPRI); 131021776Sbloom goto loop; 13117502Sroot } 13129578Ssam 13139578Ssam /* 13149578Ssam * Process the user's data in at most OBUFSIZ 13159578Ssam * chunks. Perform lower case simulation and 13169578Ssam * similar hacks. Keep track of high water 13179578Ssam * mark, sleep on overflow awaiting device aid 13189578Ssam * in acquiring new space. 13199578Ssam */ 13207822Sroot while (uio->uio_resid > 0) { 13219578Ssam /* 13229578Ssam * Grab a hunk of data from the user. 13239578Ssam */ 13247822Sroot cc = uio->uio_iov->iov_len; 13257822Sroot if (cc == 0) { 13267822Sroot uio->uio_iovcnt--; 13277822Sroot uio->uio_iov++; 132821776Sbloom if (uio->uio_iovcnt <= 0) 13297822Sroot panic("ttwrite"); 13307822Sroot continue; 13317822Sroot } 13327822Sroot if (cc > OBUFSIZ) 13337822Sroot cc = OBUFSIZ; 13347502Sroot cp = obuf; 133512752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13368520Sroot if (error) 13377502Sroot break; 13387502Sroot if (tp->t_outq.c_cc > hiwat) 13397502Sroot goto ovhiwat; 13409578Ssam if (tp->t_flags&FLUSHO) 13417502Sroot continue; 13429578Ssam /* 13439578Ssam * If we're mapping lower case or kludging tildes, 13449578Ssam * then we've got to look at each character, so 13459578Ssam * just feed the stuff to ttyoutput... 13469578Ssam */ 13479578Ssam if (tp->t_flags & (LCASE|TILDE)) { 13489578Ssam while (cc > 0) { 13497502Sroot c = *cp++; 13507502Sroot tp->t_rocount = 0; 13517625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 13527502Sroot /* out of clists, wait a bit */ 13537502Sroot ttstart(tp); 13547502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13557502Sroot tp->t_rocount = 0; 135621776Sbloom if (cc != 0) { 135721776Sbloom uio->uio_iov->iov_base -= cc; 135821776Sbloom uio->uio_iov->iov_len += cc; 135921776Sbloom uio->uio_resid += cc; 136021776Sbloom uio->uio_offset -= cc; 136121776Sbloom } 136221776Sbloom goto loop; 13637502Sroot } 13647502Sroot --cc; 13657502Sroot if (tp->t_outq.c_cc > hiwat) 13667502Sroot goto ovhiwat; 13677502Sroot } 13687502Sroot continue; 13697502Sroot } 13709578Ssam /* 13719578Ssam * If nothing fancy need be done, grab those characters we 13729578Ssam * can handle without any of ttyoutput's processing and 13739578Ssam * just transfer them to the output q. For those chars 13749578Ssam * which require special processing (as indicated by the 13759578Ssam * bits in partab), call ttyoutput. After processing 13769578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13779578Ssam * immediately. 13789578Ssam */ 13799578Ssam while (cc > 0) { 13809578Ssam if (tp->t_flags & (RAW|LITOUT)) 13817502Sroot ce = cc; 13827502Sroot else { 138312752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 138412752Ssam (caddr_t)partab, 077); 13859578Ssam /* 13869578Ssam * If ce is zero, then we're processing 13879578Ssam * a special character through ttyoutput. 13889578Ssam */ 13899578Ssam if (ce == 0) { 13907502Sroot tp->t_rocount = 0; 13917502Sroot if (ttyoutput(*cp, tp) >= 0) { 139221776Sbloom /* no c-lists, wait a bit */ 139321776Sbloom ttstart(tp); 139421776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 139521776Sbloom if (cc != 0) { 139621776Sbloom uio->uio_iov->iov_base -= cc; 139721776Sbloom uio->uio_iov->iov_len += cc; 139821776Sbloom uio->uio_resid += cc; 139921776Sbloom uio->uio_offset -= cc; 140021776Sbloom } 140121776Sbloom goto loop; 14027502Sroot } 14039578Ssam cp++, cc--; 14049578Ssam if (tp->t_flags&FLUSHO || 14059578Ssam tp->t_outq.c_cc > hiwat) 14067502Sroot goto ovhiwat; 14079578Ssam continue; 14087502Sroot } 14097502Sroot } 14109578Ssam /* 14119578Ssam * A bunch of normal characters have been found, 14129578Ssam * transfer them en masse to the output queue and 14139578Ssam * continue processing at the top of the loop. 14149578Ssam * If there are any further characters in this 14159578Ssam * <= OBUFSIZ chunk, the first should be a character 14169578Ssam * requiring special handling by ttyoutput. 14179578Ssam */ 14187502Sroot tp->t_rocount = 0; 14199578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14209578Ssam ce -= i; 14219578Ssam tp->t_col += ce; 14229578Ssam cp += ce, cc -= ce, tk_nout += ce; 14239578Ssam if (i > 0) { 14249578Ssam /* out of c-lists, wait a bit */ 14257502Sroot ttstart(tp); 14267502Sroot sleep((caddr_t)&lbolt, TTOPRI); 142721776Sbloom uio->uio_iov->iov_base -= cc; 142821776Sbloom uio->uio_iov->iov_len += cc; 142921776Sbloom uio->uio_resid += cc; 143021776Sbloom uio->uio_offset -= cc; 143121776Sbloom goto loop; 14327502Sroot } 14339578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14347502Sroot goto ovhiwat; 14357502Sroot } 14367502Sroot } 14377502Sroot ttstart(tp); 14388520Sroot return (error); 14397502Sroot 14407502Sroot ovhiwat: 144117545Skarels s = spltty(); 14429578Ssam if (cc != 0) { 14439578Ssam uio->uio_iov->iov_base -= cc; 14449578Ssam uio->uio_iov->iov_len += cc; 14459578Ssam uio->uio_resid += cc; 14469578Ssam uio->uio_offset -= cc; 14479578Ssam } 14489578Ssam /* 14499578Ssam * This can only occur if FLUSHO 14509578Ssam * is also set in t_flags. 14519578Ssam */ 14527502Sroot if (tp->t_outq.c_cc <= hiwat) { 14539578Ssam splx(s); 14547502Sroot goto loop; 14557502Sroot } 14567502Sroot ttstart(tp); 14579578Ssam if (tp->t_state&TS_NBIO) { 145817545Skarels splx(s); 14597822Sroot if (uio->uio_resid == cnt) 14608520Sroot return (EWOULDBLOCK); 14618520Sroot return (0); 14627502Sroot } 14637502Sroot tp->t_state |= TS_ASLEEP; 14647502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14659578Ssam splx(s); 14667502Sroot goto loop; 14677502Sroot } 14687502Sroot 14697502Sroot /* 14707502Sroot * Rubout one character from the rawq of tp 14717502Sroot * as cleanly as possible. 14727502Sroot */ 14737502Sroot ttyrub(c, tp) 14747625Ssam register c; 14757625Ssam register struct tty *tp; 14767502Sroot { 14777502Sroot register char *cp; 14787502Sroot register int savecol; 14797502Sroot int s; 14807502Sroot char *nextc(); 14817502Sroot 14829578Ssam if ((tp->t_flags&ECHO) == 0) 14837502Sroot return; 14849578Ssam tp->t_flags &= ~FLUSHO; 14857502Sroot c &= 0377; 14869578Ssam if (tp->t_flags&CRTBS) { 14877502Sroot if (tp->t_rocount == 0) { 14887502Sroot /* 14897502Sroot * Screwed by ttwrite; retype 14907502Sroot */ 14917502Sroot ttyretype(tp); 14927502Sroot return; 14937502Sroot } 14949578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14957502Sroot ttyrubo(tp, 2); 14969578Ssam else switch (partab[c&=0177]&0177) { 14977502Sroot 14987502Sroot case ORDINARY: 14997502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 15007502Sroot ttyrubo(tp, 2); 15017502Sroot else 15027502Sroot ttyrubo(tp, 1); 15037502Sroot break; 15047502Sroot 15057502Sroot case VTAB: 15067502Sroot case BACKSPACE: 15077502Sroot case CONTROL: 15087502Sroot case RETURN: 15099578Ssam if (tp->t_flags&CTLECH) 15107502Sroot ttyrubo(tp, 2); 15117502Sroot break; 15127502Sroot 15137502Sroot case TAB: 15147502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15157502Sroot ttyretype(tp); 15167502Sroot return; 15177502Sroot } 151817545Skarels s = spltty(); 15197502Sroot savecol = tp->t_col; 15209578Ssam tp->t_state |= TS_CNTTB; 15219578Ssam tp->t_flags |= FLUSHO; 15227502Sroot tp->t_col = tp->t_rocol; 15239578Ssam cp = tp->t_rawq.c_cf; 15249578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 15257502Sroot ttyecho(*cp, tp); 15269578Ssam tp->t_flags &= ~FLUSHO; 15279578Ssam tp->t_state &= ~TS_CNTTB; 15287502Sroot splx(s); 15297502Sroot /* 15307502Sroot * savecol will now be length of the tab 15317502Sroot */ 15327502Sroot savecol -= tp->t_col; 15337502Sroot tp->t_col += savecol; 15347502Sroot if (savecol > 8) 15357502Sroot savecol = 8; /* overflow screw */ 15367502Sroot while (--savecol >= 0) 15377502Sroot (void) ttyoutput('\b', tp); 15387502Sroot break; 15397502Sroot 15407502Sroot default: 15417502Sroot panic("ttyrub"); 15427502Sroot } 15439578Ssam } else if (tp->t_flags&PRTERA) { 15449578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15457502Sroot (void) ttyoutput('\\', tp); 15469578Ssam tp->t_state |= TS_ERASE; 15477502Sroot } 15487502Sroot ttyecho(c, tp); 15497502Sroot } else 15507502Sroot ttyecho(tp->t_erase, tp); 15517502Sroot tp->t_rocount--; 15527502Sroot } 15537502Sroot 15547502Sroot /* 15557502Sroot * Crt back over cnt chars perhaps 15567502Sroot * erasing them. 15577502Sroot */ 15587502Sroot ttyrubo(tp, cnt) 15597625Ssam register struct tty *tp; 15607625Ssam int cnt; 15617502Sroot { 15629578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 15637502Sroot 15647502Sroot while (--cnt >= 0) 15659578Ssam ttyout(rubostring, tp); 15667502Sroot } 15677502Sroot 15687502Sroot /* 15697502Sroot * Reprint the rawq line. 15707502Sroot * We assume c_cc has already been checked. 15717502Sroot */ 15727502Sroot ttyretype(tp) 15737625Ssam register struct tty *tp; 15747502Sroot { 15757502Sroot register char *cp; 15767502Sroot char *nextc(); 15777502Sroot int s; 15787502Sroot 15799578Ssam if (tp->t_rprntc != 0377) 15809578Ssam ttyecho(tp->t_rprntc, tp); 15817502Sroot (void) ttyoutput('\n', tp); 158217545Skarels s = spltty(); 15837502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 15847502Sroot ttyecho(*cp, tp); 15857502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 15867502Sroot ttyecho(*cp, tp); 15879578Ssam tp->t_state &= ~TS_ERASE; 15887502Sroot splx(s); 15897502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15907502Sroot tp->t_rocol = 0; 15917502Sroot } 15927502Sroot 15937502Sroot /* 15947502Sroot * Echo a typed character to the terminal 15957502Sroot */ 15967502Sroot ttyecho(c, tp) 15977625Ssam register c; 15987625Ssam register struct tty *tp; 15997502Sroot { 16007502Sroot 16019578Ssam if ((tp->t_state&TS_CNTTB) == 0) 16029578Ssam tp->t_flags &= ~FLUSHO; 16037502Sroot if ((tp->t_flags&ECHO) == 0) 16047502Sroot return; 16057502Sroot c &= 0377; 16067502Sroot if (tp->t_flags&RAW) { 16077502Sroot (void) ttyoutput(c, tp); 16087502Sroot return; 16097502Sroot } 16107502Sroot if (c == '\r' && tp->t_flags&CRMOD) 16117502Sroot c = '\n'; 16129578Ssam if (tp->t_flags&CTLECH) { 16137502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 16147502Sroot (void) ttyoutput('^', tp); 16157502Sroot c &= 0177; 16167502Sroot if (c == 0177) 16177502Sroot c = '?'; 16187502Sroot else if (tp->t_flags&LCASE) 16197502Sroot c += 'a' - 1; 16207502Sroot else 16217502Sroot c += 'A' - 1; 16227502Sroot } 16237502Sroot } 16249578Ssam (void) ttyoutput(c&0177, tp); 16257502Sroot } 16267502Sroot 16277502Sroot /* 16287502Sroot * Is c a break char for tp? 16297502Sroot */ 16307502Sroot ttbreakc(c, tp) 16317625Ssam register c; 16327625Ssam register struct tty *tp; 16337502Sroot { 16349578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 16357502Sroot c == '\r' && (tp->t_flags&CRMOD)); 16367502Sroot } 16377502Sroot 16387502Sroot /* 16397502Sroot * send string cp to tp 16407502Sroot */ 16417502Sroot ttyout(cp, tp) 16427625Ssam register char *cp; 16437625Ssam register struct tty *tp; 16447502Sroot { 16457502Sroot register char c; 16467502Sroot 16477502Sroot while (c = *cp++) 16487502Sroot (void) ttyoutput(c, tp); 16497502Sroot } 16507502Sroot 16517502Sroot ttwakeup(tp) 16527502Sroot struct tty *tp; 16537502Sroot { 16547502Sroot 16557502Sroot if (tp->t_rsel) { 16567502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16577502Sroot tp->t_state &= ~TS_RCOLL; 16587502Sroot tp->t_rsel = 0; 16597502Sroot } 166012752Ssam if (tp->t_state & TS_ASYNC) 166112752Ssam gsignal(tp->t_pgrp, SIGIO); 16627502Sroot wakeup((caddr_t)&tp->t_rawq); 16637502Sroot } 1664