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*25404Skarels * @(#)tty.c 6.23 (Berkeley) 11/06/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); 29317545Skarels s = spltty(); 29425391Skarels (*linesw[tp->t_line].l_close)(tp); 29525391Skarels error = (*linesw[t].l_open)(dev, tp); 29610851Ssam if (error) { 29725391Skarels (void) (*linesw[tp->t_line].l_open)(dev, tp); 29810851Ssam splx(s); 2998556Sroot return (error); 30010851Ssam } 3018556Sroot tp->t_line = t; 30218650Sbloom splx(s); 30339Sbill break; 3047625Ssam } 30539Sbill 3068556Sroot /* prevent more opens on channel */ 3075614Swnj case TIOCEXCL: 3085614Swnj tp->t_state |= TS_XCLUDE; 3095614Swnj break; 3105614Swnj 3115614Swnj case TIOCNXCL: 3125614Swnj tp->t_state &= ~TS_XCLUDE; 3135614Swnj break; 3145614Swnj 3158556Sroot /* hang up line on last close */ 31639Sbill case TIOCHPCL: 3175408Swnj tp->t_state |= TS_HUPCLS; 31839Sbill break; 31939Sbill 3203942Sbugs case TIOCFLUSH: { 3217625Ssam register int flags = *(int *)data; 3227625Ssam 3237625Ssam if (flags == 0) 3243942Sbugs flags = FREAD|FWRITE; 3257625Ssam else 3267625Ssam flags &= FREAD|FWRITE; 32712752Ssam ttyflush(tp, flags); 32839Sbill break; 3293944Sbugs } 33039Sbill 3318556Sroot /* return number of characters immediately available */ 3327625Ssam case FIONREAD: 3337625Ssam *(off_t *)data = ttnread(tp); 334174Sbill break; 335174Sbill 33613077Ssam case TIOCOUTQ: 33713077Ssam *(int *)data = tp->t_outq.c_cc; 33813077Ssam break; 33913077Ssam 3408589Sroot case TIOCSTOP: 34117545Skarels s = spltty(); 3429578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3435573Swnj tp->t_state |= TS_TTSTOP; 3445573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3455573Swnj } 3467625Ssam splx(s); 3475573Swnj break; 3485573Swnj 3498589Sroot case TIOCSTART: 35017545Skarels s = spltty(); 3519578Ssam if ((tp->t_state&TS_TTSTOP) || (tp->t_flags&FLUSHO)) { 3525573Swnj tp->t_state &= ~TS_TTSTOP; 3539578Ssam tp->t_flags &= ~FLUSHO; 3545573Swnj ttstart(tp); 3555573Swnj } 3567625Ssam splx(s); 3575573Swnj break; 3585573Swnj 3599325Ssam /* 3609325Ssam * Simulate typing of a character at the terminal. 3619325Ssam */ 3629325Ssam case TIOCSTI: 36317183Smckusick if (u.u_uid && (flag & FREAD) == 0) 36417183Smckusick return (EPERM); 3659325Ssam if (u.u_uid && u.u_ttyp != tp) 3669325Ssam return (EACCES); 3679578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3689325Ssam break; 3699325Ssam 37012752Ssam case TIOCSETP: 37112752Ssam case TIOCSETN: { 37212752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 37312752Ssam 37412752Ssam tp->t_erase = sg->sg_erase; 37512752Ssam tp->t_kill = sg->sg_kill; 37612752Ssam tp->t_ispeed = sg->sg_ispeed; 37712752Ssam tp->t_ospeed = sg->sg_ospeed; 37812752Ssam newflags = (tp->t_flags&0xffff0000) | (sg->sg_flags&0xffff); 37917545Skarels s = spltty(); 38012752Ssam if (tp->t_flags&RAW || newflags&RAW || com == TIOCSETP) { 38112752Ssam ttywait(tp); 38212752Ssam ttyflush(tp, FREAD); 38312752Ssam } else if ((tp->t_flags&CBREAK) != (newflags&CBREAK)) { 38412752Ssam if (newflags&CBREAK) { 38512752Ssam struct clist tq; 38612752Ssam 38712752Ssam catq(&tp->t_rawq, &tp->t_canq); 38812752Ssam tq = tp->t_rawq; 38912752Ssam tp->t_rawq = tp->t_canq; 39012752Ssam tp->t_canq = tq; 39112752Ssam } else { 39212752Ssam tp->t_flags |= PENDIN; 39313801Ssam newflags |= PENDIN; 39412752Ssam ttwakeup(tp); 39512752Ssam } 39612752Ssam } 39712752Ssam tp->t_flags = newflags; 39812752Ssam if (tp->t_flags&RAW) { 39912752Ssam tp->t_state &= ~TS_TTSTOP; 40012752Ssam ttstart(tp); 40112752Ssam } 40212752Ssam splx(s); 40312752Ssam break; 40412752Ssam } 40512752Ssam 40612752Ssam /* send current parameters to user */ 40712752Ssam case TIOCGETP: { 40812752Ssam register struct sgttyb *sg = (struct sgttyb *)data; 40912752Ssam 41012752Ssam sg->sg_ispeed = tp->t_ispeed; 41112752Ssam sg->sg_ospeed = tp->t_ospeed; 41212752Ssam sg->sg_erase = tp->t_erase; 41312752Ssam sg->sg_kill = tp->t_kill; 41412752Ssam sg->sg_flags = tp->t_flags; 41512752Ssam break; 41612752Ssam } 41712752Ssam 41812752Ssam case FIONBIO: 41912752Ssam if (*(int *)data) 42012752Ssam tp->t_state |= TS_NBIO; 42112752Ssam else 42212752Ssam tp->t_state &= ~TS_NBIO; 42312752Ssam break; 42412752Ssam 42512752Ssam case FIOASYNC: 42612752Ssam if (*(int *)data) 42712752Ssam tp->t_state |= TS_ASYNC; 42812752Ssam else 42912752Ssam tp->t_state &= ~TS_ASYNC; 43012752Ssam break; 43112752Ssam 43213077Ssam case TIOCGETC: 43313077Ssam bcopy((caddr_t)&tp->t_intrc, data, sizeof (struct tchars)); 43413077Ssam break; 43513077Ssam 43613077Ssam case TIOCSETC: 43713077Ssam bcopy(data, (caddr_t)&tp->t_intrc, sizeof (struct tchars)); 43813077Ssam break; 43913077Ssam 44012752Ssam /* set/get local special characters */ 44112752Ssam case TIOCSLTC: 44212752Ssam bcopy(data, (caddr_t)&tp->t_suspc, sizeof (struct ltchars)); 44312752Ssam break; 44412752Ssam 44512752Ssam case TIOCGLTC: 44612752Ssam bcopy((caddr_t)&tp->t_suspc, data, sizeof (struct ltchars)); 44712752Ssam break; 44812752Ssam 44912752Ssam /* 45012752Ssam * Modify local mode word. 45112752Ssam */ 45212752Ssam case TIOCLBIS: 45312752Ssam tp->t_flags |= *(int *)data << 16; 45412752Ssam break; 45512752Ssam 45612752Ssam case TIOCLBIC: 45712752Ssam tp->t_flags &= ~(*(int *)data << 16); 45812752Ssam break; 45912752Ssam 46012752Ssam case TIOCLSET: 46112752Ssam tp->t_flags &= 0xffff; 46212752Ssam tp->t_flags |= *(int *)data << 16; 46312752Ssam break; 46412752Ssam 46512752Ssam case TIOCLGET: 46615720Skarels *(int *)data = ((unsigned) tp->t_flags) >> 16; 46712752Ssam break; 46812752Ssam 46917545Skarels /* 47017932Skarels * Allow SPGRP only if tty is open for reading. 47117598Sbloom * Quick check: if we can find a process in the new pgrp, 47217598Sbloom * this user must own that process. 47317598Sbloom * SHOULD VERIFY THAT PGRP IS IN USE AND IS THIS USER'S. 47417545Skarels */ 47518650Sbloom case TIOCSPGRP: { 47617545Skarels struct proc *p; 47717545Skarels int pgrp = *(int *)data; 47817545Skarels 47917545Skarels if (u.u_uid && (flag & FREAD) == 0) 48017545Skarels return (EPERM); 48117598Sbloom p = pfind(pgrp); 48217598Sbloom if (p && p->p_pgrp == pgrp && 48317598Sbloom p->p_uid != u.u_uid && u.u_uid && !inferior(p)) 48417598Sbloom return (EPERM); 48517545Skarels tp->t_pgrp = pgrp; 48612752Ssam break; 48718650Sbloom } 48812752Ssam 48912752Ssam case TIOCGPGRP: 49012752Ssam *(int *)data = tp->t_pgrp; 49112752Ssam break; 49212752Ssam 49317598Sbloom case TIOCSWINSZ: 49418650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 49518650Sbloom sizeof (struct winsize))) { 49617598Sbloom tp->t_winsize = *(struct winsize *)data; 49717598Sbloom gsignal(tp->t_pgrp, SIGWINCH); 49817598Sbloom } 49917598Sbloom break; 50017598Sbloom 50117598Sbloom case TIOCGWINSZ: 50217598Sbloom *(struct winsize *)data = tp->t_winsize; 50317598Sbloom break; 50417598Sbloom 50539Sbill default: 5068556Sroot return (-1); 50739Sbill } 5088556Sroot return (0); 50939Sbill } 5104484Swnj 5114484Swnj ttnread(tp) 5124484Swnj struct tty *tp; 5134484Swnj { 5144484Swnj int nread = 0; 5154484Swnj 5169578Ssam if (tp->t_flags & PENDIN) 5174484Swnj ttypend(tp); 5184484Swnj nread = tp->t_canq.c_cc; 5194484Swnj if (tp->t_flags & (RAW|CBREAK)) 5204484Swnj nread += tp->t_rawq.c_cc; 5214484Swnj return (nread); 5224484Swnj } 5234484Swnj 5245408Swnj ttselect(dev, rw) 5254484Swnj dev_t dev; 5265408Swnj int rw; 5274484Swnj { 5284484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5294484Swnj int nread; 53017545Skarels int s = spltty(); 5314484Swnj 5325408Swnj switch (rw) { 5334484Swnj 5344484Swnj case FREAD: 5354484Swnj nread = ttnread(tp); 53621776Sbloom if ((nread > 0) || ((tp->t_state & TS_CARR_ON) == 0)) 5375408Swnj goto win; 5384938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5395408Swnj tp->t_state |= TS_RCOLL; 5404484Swnj else 5414484Swnj tp->t_rsel = u.u_procp; 5425408Swnj break; 5434484Swnj 5445408Swnj case FWRITE: 5455408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) 5465408Swnj goto win; 5475408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5485408Swnj tp->t_state |= TS_WCOLL; 5495408Swnj else 5505408Swnj tp->t_wsel = u.u_procp; 5515408Swnj break; 5524484Swnj } 5535408Swnj splx(s); 5545408Swnj return (0); 5555408Swnj win: 5565408Swnj splx(s); 5575408Swnj return (1); 5584484Swnj } 5597436Skre 5607502Sroot /* 56125391Skarels * Initial open of tty, or (re)entry to line discipline. 5629578Ssam * Establish a process group for distribution of 5637502Sroot * quits and interrupts from the tty. 5647502Sroot */ 5657502Sroot ttyopen(dev, tp) 5667625Ssam dev_t dev; 5677625Ssam register struct tty *tp; 5687502Sroot { 5697502Sroot register struct proc *pp; 5707502Sroot 5717502Sroot pp = u.u_procp; 5727502Sroot tp->t_dev = dev; 5737625Ssam if (pp->p_pgrp == 0) { 5747502Sroot u.u_ttyp = tp; 5757502Sroot u.u_ttyd = dev; 5767502Sroot if (tp->t_pgrp == 0) 5777502Sroot tp->t_pgrp = pp->p_pid; 5787502Sroot pp->p_pgrp = tp->t_pgrp; 5797502Sroot } 5807502Sroot tp->t_state &= ~TS_WOPEN; 58117545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 58217545Skarels tp->t_state |= TS_ISOPEN; 58317598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 58417545Skarels if (tp->t_line != NTTYDISC) 58517545Skarels ttywflush(tp); 58617545Skarels } 5878556Sroot return (0); 5887502Sroot } 5897502Sroot 5907502Sroot /* 59125391Skarels * "close" a line discipline 59225391Skarels */ 59325391Skarels ttylclose(tp) 59425391Skarels register struct tty *tp; 59525391Skarels { 59625391Skarels 59725391Skarels ttywflush(tp); 59825391Skarels tp->t_line = 0; 59925391Skarels } 60025391Skarels 60125391Skarels /* 6027502Sroot * clean tp on last close 6037502Sroot */ 6047502Sroot ttyclose(tp) 6057625Ssam register struct tty *tp; 6067502Sroot { 6077502Sroot 60825391Skarels ttyflush(tp, FREAD|FWRITE); 6097502Sroot tp->t_pgrp = 0; 6107502Sroot tp->t_state = 0; 6117502Sroot } 6127502Sroot 6137502Sroot /* 61425391Skarels * Handle modem control transition on a tty. 61525391Skarels * Flag indicates new state of carrier. 61625391Skarels * Returns 0 if the line should be turned off, otherwise 1. 61725391Skarels */ 61825391Skarels ttymodem(tp, flag) 61925391Skarels register struct tty *tp; 62025391Skarels { 62125391Skarels 62225391Skarels if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { 62325391Skarels /* 62425391Skarels * MDMBUF: do flow control according to carrier flag 62525391Skarels */ 62625391Skarels if (flag) { 62725391Skarels tp->t_state &= ~TS_TTSTOP; 62825391Skarels ttstart(tp); 62925391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 63025391Skarels tp->t_state |= TS_TTSTOP; 63125391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 63225391Skarels } 63325391Skarels } else if (flag == 0) { 63425391Skarels /* 63525391Skarels * Lost carrier. 63625391Skarels */ 63725391Skarels tp->t_state &= ~TS_CARR_ON; 63825391Skarels if (tp->t_state & TS_ISOPEN) { 63925391Skarels if ((tp->t_flags & NOHANG) == 0) { 64025391Skarels gsignal(tp->t_pgrp, SIGHUP); 64125391Skarels gsignal(tp->t_pgrp, SIGCONT); 64225391Skarels ttyflush(tp, FREAD|FWRITE); 64325391Skarels return (0); 64425391Skarels } 64525391Skarels } 64625391Skarels } else { 64725391Skarels /* 64825391Skarels * Carrier now on. 64925391Skarels */ 65025391Skarels tp->t_state |= TS_CARR_ON; 65125391Skarels wakeup((caddr_t)&tp->t_rawq); 65225391Skarels } 65325391Skarels return (1); 65425391Skarels } 65525391Skarels 65625391Skarels /* 657*25404Skarels * Default modem control routine (for other line disciplines). 658*25404Skarels * Return argument flag, to turn off device on carrier drop. 659*25404Skarels */ 660*25404Skarels nullmodem(flag) 661*25404Skarels int flag; 662*25404Skarels { 663*25404Skarels 664*25404Skarels if (flag) 665*25404Skarels tp->t_state |= TS_CARR_ON; 666*25404Skarels else 667*25404Skarels tp->t_state &= ~TS_CARR_ON; 668*25404Skarels return (flag); 669*25404Skarels } 670*25404Skarels 671*25404Skarels /* 6727502Sroot * reinput pending characters after state switch 67317545Skarels * call at spltty(). 6747502Sroot */ 6757502Sroot ttypend(tp) 6767625Ssam register struct tty *tp; 6777502Sroot { 6787502Sroot struct clist tq; 6797502Sroot register c; 6807502Sroot 6819578Ssam tp->t_flags &= ~PENDIN; 6829578Ssam tp->t_state |= TS_TYPEN; 6837502Sroot tq = tp->t_rawq; 6847502Sroot tp->t_rawq.c_cc = 0; 6857502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6867502Sroot while ((c = getc(&tq)) >= 0) 6877502Sroot ttyinput(c, tp); 6889578Ssam tp->t_state &= ~TS_TYPEN; 6897502Sroot } 6907502Sroot 6917502Sroot /* 6929578Ssam * Place a character on raw TTY input queue, 6939578Ssam * putting in delimiters and waking up top 6949578Ssam * half as needed. Also echo if required. 6959578Ssam * The arguments are the character and the 6969578Ssam * appropriate tty structure. 6977502Sroot */ 6987502Sroot ttyinput(c, tp) 6997625Ssam register c; 7007625Ssam register struct tty *tp; 7017502Sroot { 7029578Ssam register int t_flags = tp->t_flags; 7037502Sroot int i; 7047502Sroot 7059578Ssam /* 7069578Ssam * If input is pending take it first. 7079578Ssam */ 7089578Ssam if (t_flags&PENDIN) 7097502Sroot ttypend(tp); 7107502Sroot tk_nin++; 7117502Sroot c &= 0377; 7129578Ssam 7139578Ssam /* 7149578Ssam * In tandem mode, check high water mark. 7159578Ssam */ 7167502Sroot if (t_flags&TANDEM) 7177502Sroot ttyblock(tp); 7189578Ssam 7199578Ssam if (t_flags&RAW) { 7209578Ssam /* 7219578Ssam * Raw mode, just put character 7229578Ssam * in input q w/o interpretation. 7239578Ssam */ 7249578Ssam if (tp->t_rawq.c_cc > TTYHOG) 72512752Ssam ttyflush(tp, FREAD|FWRITE); 7269578Ssam else { 7279578Ssam if (putc(c, &tp->t_rawq) >= 0) 7289578Ssam ttwakeup(tp); 7299578Ssam ttyecho(c, tp); 7307502Sroot } 7319578Ssam goto endcase; 7329578Ssam } 7339578Ssam 7349578Ssam /* 7359578Ssam * Ignore any high bit added during 7369578Ssam * previous ttyinput processing. 7379578Ssam */ 73824273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 7399578Ssam c &= 0177; 7409578Ssam /* 7419578Ssam * Check for literal nexting very first 7429578Ssam */ 7439578Ssam if (tp->t_state&TS_LNCH) { 7449578Ssam c |= 0200; 7459578Ssam tp->t_state &= ~TS_LNCH; 7469578Ssam } 7479578Ssam 7489578Ssam /* 7499578Ssam * Scan for special characters. This code 7509578Ssam * is really just a big case statement with 7519578Ssam * non-constant cases. The bottom of the 7529578Ssam * case statement is labeled ``endcase'', so goto 7539578Ssam * it after a case match, or similar. 7549578Ssam */ 7559578Ssam if (tp->t_line == NTTYDISC) { 7569578Ssam if (c == tp->t_lnextc) { 75721776Sbloom if (t_flags&ECHO) 7587502Sroot ttyout("^\b", tp); 7599578Ssam tp->t_state |= TS_LNCH; 7609578Ssam goto endcase; 7619578Ssam } 7629578Ssam if (c == tp->t_flushc) { 76321776Sbloom if (t_flags&FLUSHO) 7649578Ssam tp->t_flags &= ~FLUSHO; 7657502Sroot else { 76612752Ssam ttyflush(tp, FWRITE); 7677502Sroot ttyecho(c, tp); 7689578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7697502Sroot ttyretype(tp); 7709578Ssam tp->t_flags |= FLUSHO; 7717502Sroot } 7729578Ssam goto startoutput; 7739578Ssam } 7749578Ssam if (c == tp->t_suspc) { 77521776Sbloom if ((t_flags&NOFLSH) == 0) 77612752Ssam ttyflush(tp, FREAD); 7779578Ssam ttyecho(c, tp); 7789578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7799578Ssam goto endcase; 7809578Ssam } 7819578Ssam } 7829578Ssam 7839578Ssam /* 7849578Ssam * Handle start/stop characters. 7859578Ssam */ 7869578Ssam if (c == tp->t_stopc) { 7879578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7889578Ssam tp->t_state |= TS_TTSTOP; 7899578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7907502Sroot return; 7919578Ssam } 7929578Ssam if (c != tp->t_startc) 7939578Ssam return; 7949578Ssam goto endcase; 7959578Ssam } 7969578Ssam if (c == tp->t_startc) 7979578Ssam goto restartoutput; 7989578Ssam 7999578Ssam /* 8009578Ssam * Look for interrupt/quit chars. 8019578Ssam */ 8029578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 80321776Sbloom if ((t_flags&NOFLSH) == 0) 80412752Ssam ttyflush(tp, FREAD|FWRITE); 8059578Ssam ttyecho(c, tp); 8069578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 8079578Ssam goto endcase; 8089578Ssam } 8099578Ssam 81023165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 81123165Sbloom if (tp->t_state&TS_BKSL) { 81223165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 81323165Sbloom if (maptab[c]) 81423165Sbloom c = maptab[c]; 81523165Sbloom c |= 0200; 81623165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 81723165Sbloom } else if (c >= 'A' && c <= 'Z') 81823165Sbloom c += 'a' - 'A'; 81923165Sbloom else if (c == '\\') 82023165Sbloom tp->t_state |= TS_BKSL; 82123165Sbloom } 82223165Sbloom 8239578Ssam /* 8249578Ssam * Cbreak mode, don't process line editing 8259578Ssam * characters; check high water mark for wakeup. 8269578Ssam */ 8279578Ssam if (t_flags&CBREAK) { 8289578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 8297502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 8307502Sroot tp->t_line == NTTYDISC) 8317502Sroot (void) ttyoutput(CTRL(g), tp); 8327502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 8337502Sroot ttwakeup(tp); 8347502Sroot ttyecho(c, tp); 8357502Sroot } 8369578Ssam goto endcase; 8379578Ssam } 8389578Ssam 8399578Ssam /* 8409578Ssam * From here on down cooked mode character 8419578Ssam * processing takes place. 8429578Ssam */ 8439578Ssam if ((tp->t_state&TS_QUOT) && 8449578Ssam (c == tp->t_erase || c == tp->t_kill)) { 8459578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8469578Ssam c |= 0200; 8479578Ssam } 8489578Ssam if (c == tp->t_erase) { 8499578Ssam if (tp->t_rawq.c_cc) 8509578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8519578Ssam goto endcase; 8529578Ssam } 8539578Ssam if (c == tp->t_kill) { 85421776Sbloom if (t_flags&CRTKIL && 8559578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8569578Ssam while (tp->t_rawq.c_cc) 8579578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8589578Ssam } else { 8599578Ssam ttyecho(c, tp); 8609578Ssam ttyecho('\n', tp); 8619578Ssam while (getc(&tp->t_rawq) > 0) 8629578Ssam ; 8639578Ssam tp->t_rocount = 0; 8649578Ssam } 8659578Ssam tp->t_state &= ~TS_LOCAL; 8669578Ssam goto endcase; 8679578Ssam } 8689578Ssam 8699578Ssam /* 8709578Ssam * New line discipline, 8719578Ssam * check word erase/reprint line. 8729578Ssam */ 8739578Ssam if (tp->t_line == NTTYDISC) { 8749578Ssam if (c == tp->t_werasc) { 8759578Ssam if (tp->t_rawq.c_cc == 0) 8769578Ssam goto endcase; 8779578Ssam do { 8789578Ssam c = unputc(&tp->t_rawq); 8799578Ssam if (c != ' ' && c != '\t') 8809578Ssam goto erasenb; 8819578Ssam ttyrub(c, tp); 8829578Ssam } while (tp->t_rawq.c_cc); 8839578Ssam goto endcase; 8849578Ssam erasenb: 8859578Ssam do { 8869578Ssam ttyrub(c, tp); 8879578Ssam if (tp->t_rawq.c_cc == 0) 8889578Ssam goto endcase; 8899578Ssam c = unputc(&tp->t_rawq); 8909578Ssam } while (c != ' ' && c != '\t'); 8919578Ssam (void) putc(c, &tp->t_rawq); 8929578Ssam goto endcase; 8939578Ssam } 8949578Ssam if (c == tp->t_rprntc) { 8959578Ssam ttyretype(tp); 8969578Ssam goto endcase; 8979578Ssam } 8989578Ssam } 8999578Ssam 9009578Ssam /* 9019578Ssam * Check for input buffer overflow 9029578Ssam */ 90310391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 90410391Ssam if (tp->t_line == NTTYDISC) 90510391Ssam (void) ttyoutput(CTRL(g), tp); 9069578Ssam goto endcase; 90710391Ssam } 9089578Ssam 9099578Ssam /* 9109578Ssam * Put data char in q for user and 9119578Ssam * wakeup on seeing a line delimiter. 9129578Ssam */ 9139578Ssam if (putc(c, &tp->t_rawq) >= 0) { 9149578Ssam if (ttbreakc(c, tp)) { 9159578Ssam tp->t_rocount = 0; 9169578Ssam catq(&tp->t_rawq, &tp->t_canq); 9177502Sroot ttwakeup(tp); 9189578Ssam } else if (tp->t_rocount++ == 0) 9199578Ssam tp->t_rocol = tp->t_col; 9209578Ssam tp->t_state &= ~TS_QUOT; 9219578Ssam if (c == '\\') 9229578Ssam tp->t_state |= TS_QUOT; 9239578Ssam if (tp->t_state&TS_ERASE) { 9249578Ssam tp->t_state &= ~TS_ERASE; 9259578Ssam (void) ttyoutput('/', tp); 9269578Ssam } 9279578Ssam i = tp->t_col; 9287502Sroot ttyecho(c, tp); 92921776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 9309578Ssam i = MIN(2, tp->t_col - i); 9319578Ssam while (i > 0) { 9329578Ssam (void) ttyoutput('\b', tp); 9339578Ssam i--; 9349578Ssam } 9359578Ssam } 9367502Sroot } 9379578Ssam endcase: 9389578Ssam /* 9399578Ssam * If DEC-style start/stop is enabled don't restart 9409578Ssam * output until seeing the start character. 9419578Ssam */ 94221776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 9439578Ssam tp->t_startc != tp->t_stopc) 9447502Sroot return; 9459578Ssam restartoutput: 9467502Sroot tp->t_state &= ~TS_TTSTOP; 9479578Ssam tp->t_flags &= ~FLUSHO; 9489578Ssam startoutput: 9497502Sroot ttstart(tp); 9507502Sroot } 9517502Sroot 9527502Sroot /* 9539578Ssam * Put character on TTY output queue, adding delays, 9547502Sroot * expanding tabs, and handling the CR/NL bit. 9559578Ssam * This is called both from the top half for output, 9569578Ssam * and from interrupt level for echoing. 9577502Sroot * The arguments are the character and the tty structure. 9587502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 9597502Sroot * Must be recursive. 9607502Sroot */ 9617502Sroot ttyoutput(c, tp) 9627502Sroot register c; 9637502Sroot register struct tty *tp; 9647502Sroot { 9657502Sroot register char *colp; 9667502Sroot register ctype; 9677502Sroot 9689578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9699578Ssam if (tp->t_flags&FLUSHO) 9707502Sroot return (-1); 9717502Sroot if (putc(c, &tp->t_outq)) 9727625Ssam return (c); 9737502Sroot tk_nout++; 9747502Sroot return (-1); 9757502Sroot } 9769578Ssam 9777502Sroot /* 9789578Ssam * Ignore EOT in normal mode to avoid 9799578Ssam * hanging up certain terminals. 9807502Sroot */ 9817502Sroot c &= 0177; 9829578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9837502Sroot return (-1); 9847502Sroot /* 9857502Sroot * Turn tabs to spaces as required 9867502Sroot */ 9879578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9887502Sroot register int s; 9897502Sroot 9907502Sroot c = 8 - (tp->t_col&7); 9919578Ssam if ((tp->t_flags&FLUSHO) == 0) { 99217545Skarels s = spltty(); /* don't interrupt tabs */ 9937502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9947502Sroot tk_nout += c; 9957502Sroot splx(s); 9967502Sroot } 9977502Sroot tp->t_col += c; 9987502Sroot return (c ? -1 : '\t'); 9997502Sroot } 10007502Sroot tk_nout++; 10017502Sroot /* 10027502Sroot * for upper-case-only terminals, 10037502Sroot * generate escapes. 10047502Sroot */ 10057502Sroot if (tp->t_flags&LCASE) { 10067502Sroot colp = "({)}!|^~'`"; 10077625Ssam while (*colp++) 10087625Ssam if (c == *colp++) { 10097502Sroot if (ttyoutput('\\', tp) >= 0) 10107502Sroot return (c); 10117502Sroot c = colp[-2]; 10127502Sroot break; 10137502Sroot } 10149578Ssam if ('A' <= c && c <= 'Z') { 10157502Sroot if (ttyoutput('\\', tp) >= 0) 10167502Sroot return (c); 10179578Ssam } else if ('a' <= c && c <= 'z') 10187502Sroot c += 'A' - 'a'; 10197502Sroot } 10209578Ssam 10217502Sroot /* 10227502Sroot * turn <nl> to <cr><lf> if desired. 10237502Sroot */ 10249578Ssam if (c == '\n' && tp->t_flags&CRMOD) 10257502Sroot if (ttyoutput('\r', tp) >= 0) 10267502Sroot return (c); 10279578Ssam if (c == '~' && tp->t_flags&TILDE) 10287502Sroot c = '`'; 10299578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 10307502Sroot return (c); 10317502Sroot /* 10327502Sroot * Calculate delays. 10337502Sroot * The numbers here represent clock ticks 10347502Sroot * and are not necessarily optimal for all terminals. 10357502Sroot * The delays are indicated by characters above 0200. 10367502Sroot * In raw mode there are no delays and the 10377502Sroot * transmission path is 8 bits wide. 10389578Ssam * 10399578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 10407502Sroot */ 10417502Sroot colp = &tp->t_col; 10427502Sroot ctype = partab[c]; 10437502Sroot c = 0; 10447502Sroot switch (ctype&077) { 10457502Sroot 10467502Sroot case ORDINARY: 10477502Sroot (*colp)++; 10487502Sroot 10497502Sroot case CONTROL: 10507502Sroot break; 10517502Sroot 10527502Sroot case BACKSPACE: 10537502Sroot if (*colp) 10547502Sroot (*colp)--; 10557502Sroot break; 10567502Sroot 105713821Ssam /* 105813821Ssam * This macro is close enough to the correct thing; 105913821Ssam * it should be replaced by real user settable delays 106013821Ssam * in any event... 106113821Ssam */ 106213821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10637502Sroot case NEWLINE: 10647502Sroot ctype = (tp->t_flags >> 8) & 03; 10657625Ssam if (ctype == 1) { /* tty 37 */ 106612752Ssam if (*colp > 0) 106713863Ssam c = max((((unsigned)*colp) >> 4) + 3, 106813863Ssam (unsigned)6); 10699578Ssam } else if (ctype == 2) /* vt05 */ 107013821Ssam c = mstohz(100); 10717502Sroot *colp = 0; 10727502Sroot break; 10737502Sroot 10747502Sroot case TAB: 10757502Sroot ctype = (tp->t_flags >> 10) & 03; 10767625Ssam if (ctype == 1) { /* tty 37 */ 10777502Sroot c = 1 - (*colp | ~07); 10787625Ssam if (c < 5) 10797502Sroot c = 0; 10807502Sroot } 10817502Sroot *colp |= 07; 10827502Sroot (*colp)++; 10837502Sroot break; 10847502Sroot 10857502Sroot case VTAB: 10869578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10877502Sroot c = 0177; 10887502Sroot break; 10897502Sroot 10907502Sroot case RETURN: 10917502Sroot ctype = (tp->t_flags >> 12) & 03; 10929578Ssam if (ctype == 1) /* tn 300 */ 109313821Ssam c = mstohz(83); 10949578Ssam else if (ctype == 2) /* ti 700 */ 109513821Ssam c = mstohz(166); 10969578Ssam else if (ctype == 3) { /* concept 100 */ 10977502Sroot int i; 10989578Ssam 10997502Sroot if ((i = *colp) >= 0) 11009578Ssam for (; i < 9; i++) 11017502Sroot (void) putc(0177, &tp->t_outq); 11027502Sroot } 11037502Sroot *colp = 0; 11047502Sroot } 11059578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 11067502Sroot (void) putc(c|0200, &tp->t_outq); 11077502Sroot return (-1); 11087502Sroot } 110913821Ssam #undef mstohz 11107502Sroot 11117502Sroot /* 11127502Sroot * Called from device's read routine after it has 11137502Sroot * calculated the tty-structure given as argument. 11147502Sroot */ 11157722Swnj ttread(tp, uio) 11167625Ssam register struct tty *tp; 11177722Swnj struct uio *uio; 11187502Sroot { 11197502Sroot register struct clist *qp; 11209578Ssam register c, t_flags; 11219859Ssam int s, first, error = 0; 11227502Sroot 11237502Sroot loop: 11249578Ssam /* 11259578Ssam * Take any pending input first. 11269578Ssam */ 112717545Skarels s = spltty(); 11289578Ssam if (tp->t_flags&PENDIN) 11297502Sroot ttypend(tp); 11309859Ssam splx(s); 11319578Ssam 113223165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 113323165Sbloom return (EIO); 113423165Sbloom 11359578Ssam /* 11369578Ssam * Hang process if it's in the background. 11379578Ssam */ 113823165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 113924392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 114024392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11417502Sroot u.u_procp->p_flag&SVFORK) 11428520Sroot return (EIO); 11437502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11447502Sroot sleep((caddr_t)&lbolt, TTIPRI); 114523165Sbloom goto loop; 11467502Sroot } 11479578Ssam t_flags = tp->t_flags; 11489578Ssam 11499578Ssam /* 11509578Ssam * In raw mode take characters directly from the 11519578Ssam * raw queue w/o processing. Interlock against 11529578Ssam * device interrupts when interrogating rawq. 11539578Ssam */ 11549578Ssam if (t_flags&RAW) { 115517545Skarels s = spltty(); 11567502Sroot if (tp->t_rawq.c_cc <= 0) { 11579578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11587502Sroot (tp->t_state&TS_NBIO)) { 11599859Ssam splx(s); 116015094Skarels return (EWOULDBLOCK); 11617502Sroot } 11627502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11639859Ssam splx(s); 11647502Sroot goto loop; 11657502Sroot } 11669859Ssam splx(s); 116714938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 116814938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11699859Ssam goto checktandem; 11709578Ssam } 11719578Ssam 11729578Ssam /* 11739578Ssam * In cbreak mode use the rawq, otherwise 11749578Ssam * take characters from the canonicalized q. 11759578Ssam */ 11769578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11779578Ssam 11789578Ssam /* 11799578Ssam * No input, sleep on rawq awaiting hardware 11809578Ssam * receipt and notification. 11819578Ssam */ 118217545Skarels s = spltty(); 11839578Ssam if (qp->c_cc <= 0) { 11849578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11859578Ssam (tp->t_state&TS_NBIO)) { 11869859Ssam splx(s); 11879578Ssam return (EWOULDBLOCK); 11887502Sroot } 11899578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11909859Ssam splx(s); 11919578Ssam goto loop; 11929578Ssam } 11939859Ssam splx(s); 11949578Ssam 11959578Ssam /* 11969578Ssam * Input present, perform input mapping 11979578Ssam * and processing (we're not in raw mode). 11989578Ssam */ 11999578Ssam first = 1; 12009578Ssam while ((c = getc(qp)) >= 0) { 12019578Ssam if (t_flags&CRMOD && c == '\r') 12029578Ssam c = '\n'; 12039578Ssam /* 12049578Ssam * Check for delayed suspend character. 12059578Ssam */ 12069578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 12079578Ssam gsignal(tp->t_pgrp, SIGTSTP); 12089578Ssam if (first) { 12099578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12109578Ssam goto loop; 12119578Ssam } 12129578Ssam break; 12137502Sroot } 12149578Ssam /* 12159578Ssam * Interpret EOF only in cooked mode. 12169578Ssam */ 12179578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12189578Ssam break; 12199578Ssam /* 12209578Ssam * Give user character. 12219578Ssam */ 122224273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12239578Ssam if (error) 12249578Ssam break; 122514938Smckusick if (uio->uio_resid == 0) 12269578Ssam break; 12279578Ssam /* 12289578Ssam * In cooked mode check for a "break character" 12299578Ssam * marking the end of a "line of input". 12309578Ssam */ 12319578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12329578Ssam break; 12339578Ssam first = 0; 12347502Sroot } 12359578Ssam 12369859Ssam checktandem: 12379578Ssam /* 12389578Ssam * Look to unblock output now that (presumably) 12399578Ssam * the input queue has gone down. 12409578Ssam */ 12419859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 12429578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 12437502Sroot tp->t_state &= ~TS_TBLOCK; 12447502Sroot ttstart(tp); 12457502Sroot } 12468520Sroot return (error); 12477502Sroot } 12487502Sroot 12497502Sroot /* 125025391Skarels * Check the output queue on tp for space for a kernel message 125125391Skarels * (from uprintf/tprintf). Allow some space over the normal 125225391Skarels * hiwater mark so we don't lose messages due to normal flow 125325391Skarels * control, but don't let the tty run amok. 125425391Skarels */ 125525391Skarels ttycheckoutq(tp, wait) 125625391Skarels register struct tty *tp; 125725391Skarels int wait; 125825391Skarels { 125925391Skarels int hiwat, s; 126025391Skarels 126125391Skarels hiwat = TTHIWAT(tp); 126225391Skarels s = spltty(); 126325391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126425391Skarels while (tp->t_outq.c_cc > hiwat) { 126525391Skarels ttstart(tp); 126625391Skarels if (wait == 0) { 126725391Skarels splx(s); 126825391Skarels return (0); 126925391Skarels } 127025391Skarels tp->t_state |= TS_ASLEEP; 127125391Skarels sleep((caddr_t)&tp->t_outq, TTOPRI); 127225391Skarels } 127325391Skarels splx(s); 127425391Skarels return (1); 127525391Skarels } 127625391Skarels 127725391Skarels /* 12787502Sroot * Called from the device's write routine after it has 12797502Sroot * calculated the tty-structure given as argument. 12807502Sroot */ 12817822Sroot ttwrite(tp, uio) 12827625Ssam register struct tty *tp; 12839578Ssam register struct uio *uio; 12847502Sroot { 12857502Sroot register char *cp; 12869578Ssam register int cc, ce, c; 12879578Ssam int i, hiwat, cnt, error, s; 12887502Sroot char obuf[OBUFSIZ]; 12897502Sroot 12909578Ssam hiwat = TTHIWAT(tp); 12919578Ssam cnt = uio->uio_resid; 12929578Ssam error = 0; 12937502Sroot loop: 129421776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 129521776Sbloom return (EIO); 12969578Ssam /* 12979578Ssam * Hang the process if it's in the background. 12989578Ssam */ 129921776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 13009578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 130124392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 130224392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 13037502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 13047502Sroot sleep((caddr_t)&lbolt, TTIPRI); 130521776Sbloom goto loop; 13067502Sroot } 13079578Ssam 13089578Ssam /* 13099578Ssam * Process the user's data in at most OBUFSIZ 13109578Ssam * chunks. Perform lower case simulation and 13119578Ssam * similar hacks. Keep track of high water 13129578Ssam * mark, sleep on overflow awaiting device aid 13139578Ssam * in acquiring new space. 13149578Ssam */ 13157822Sroot while (uio->uio_resid > 0) { 13169578Ssam /* 13179578Ssam * Grab a hunk of data from the user. 13189578Ssam */ 13197822Sroot cc = uio->uio_iov->iov_len; 13207822Sroot if (cc == 0) { 13217822Sroot uio->uio_iovcnt--; 13227822Sroot uio->uio_iov++; 132321776Sbloom if (uio->uio_iovcnt <= 0) 13247822Sroot panic("ttwrite"); 13257822Sroot continue; 13267822Sroot } 13277822Sroot if (cc > OBUFSIZ) 13287822Sroot cc = OBUFSIZ; 13297502Sroot cp = obuf; 133012752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13318520Sroot if (error) 13327502Sroot break; 13337502Sroot if (tp->t_outq.c_cc > hiwat) 13347502Sroot goto ovhiwat; 13359578Ssam if (tp->t_flags&FLUSHO) 13367502Sroot continue; 13379578Ssam /* 13389578Ssam * If we're mapping lower case or kludging tildes, 13399578Ssam * then we've got to look at each character, so 13409578Ssam * just feed the stuff to ttyoutput... 13419578Ssam */ 13429578Ssam if (tp->t_flags & (LCASE|TILDE)) { 13439578Ssam while (cc > 0) { 13447502Sroot c = *cp++; 13457502Sroot tp->t_rocount = 0; 13467625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 13477502Sroot /* out of clists, wait a bit */ 13487502Sroot ttstart(tp); 13497502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13507502Sroot tp->t_rocount = 0; 135121776Sbloom if (cc != 0) { 135221776Sbloom uio->uio_iov->iov_base -= cc; 135321776Sbloom uio->uio_iov->iov_len += cc; 135421776Sbloom uio->uio_resid += cc; 135521776Sbloom uio->uio_offset -= cc; 135621776Sbloom } 135721776Sbloom goto loop; 13587502Sroot } 13597502Sroot --cc; 13607502Sroot if (tp->t_outq.c_cc > hiwat) 13617502Sroot goto ovhiwat; 13627502Sroot } 13637502Sroot continue; 13647502Sroot } 13659578Ssam /* 13669578Ssam * If nothing fancy need be done, grab those characters we 13679578Ssam * can handle without any of ttyoutput's processing and 13689578Ssam * just transfer them to the output q. For those chars 13699578Ssam * which require special processing (as indicated by the 13709578Ssam * bits in partab), call ttyoutput. After processing 13719578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13729578Ssam * immediately. 13739578Ssam */ 13749578Ssam while (cc > 0) { 13759578Ssam if (tp->t_flags & (RAW|LITOUT)) 13767502Sroot ce = cc; 13777502Sroot else { 137812752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 137912752Ssam (caddr_t)partab, 077); 13809578Ssam /* 13819578Ssam * If ce is zero, then we're processing 13829578Ssam * a special character through ttyoutput. 13839578Ssam */ 13849578Ssam if (ce == 0) { 13857502Sroot tp->t_rocount = 0; 13867502Sroot if (ttyoutput(*cp, tp) >= 0) { 138721776Sbloom /* no c-lists, wait a bit */ 138821776Sbloom ttstart(tp); 138921776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 139021776Sbloom if (cc != 0) { 139121776Sbloom uio->uio_iov->iov_base -= cc; 139221776Sbloom uio->uio_iov->iov_len += cc; 139321776Sbloom uio->uio_resid += cc; 139421776Sbloom uio->uio_offset -= cc; 139521776Sbloom } 139621776Sbloom goto loop; 13977502Sroot } 13989578Ssam cp++, cc--; 13999578Ssam if (tp->t_flags&FLUSHO || 14009578Ssam tp->t_outq.c_cc > hiwat) 14017502Sroot goto ovhiwat; 14029578Ssam continue; 14037502Sroot } 14047502Sroot } 14059578Ssam /* 14069578Ssam * A bunch of normal characters have been found, 14079578Ssam * transfer them en masse to the output queue and 14089578Ssam * continue processing at the top of the loop. 14099578Ssam * If there are any further characters in this 14109578Ssam * <= OBUFSIZ chunk, the first should be a character 14119578Ssam * requiring special handling by ttyoutput. 14129578Ssam */ 14137502Sroot tp->t_rocount = 0; 14149578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14159578Ssam ce -= i; 14169578Ssam tp->t_col += ce; 14179578Ssam cp += ce, cc -= ce, tk_nout += ce; 14189578Ssam if (i > 0) { 14199578Ssam /* out of c-lists, wait a bit */ 14207502Sroot ttstart(tp); 14217502Sroot sleep((caddr_t)&lbolt, TTOPRI); 142221776Sbloom uio->uio_iov->iov_base -= cc; 142321776Sbloom uio->uio_iov->iov_len += cc; 142421776Sbloom uio->uio_resid += cc; 142521776Sbloom uio->uio_offset -= cc; 142621776Sbloom goto loop; 14277502Sroot } 14289578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14297502Sroot goto ovhiwat; 14307502Sroot } 14317502Sroot } 14327502Sroot ttstart(tp); 14338520Sroot return (error); 14347502Sroot 14357502Sroot ovhiwat: 143617545Skarels s = spltty(); 14379578Ssam if (cc != 0) { 14389578Ssam uio->uio_iov->iov_base -= cc; 14399578Ssam uio->uio_iov->iov_len += cc; 14409578Ssam uio->uio_resid += cc; 14419578Ssam uio->uio_offset -= cc; 14429578Ssam } 14439578Ssam /* 14449578Ssam * This can only occur if FLUSHO 14459578Ssam * is also set in t_flags. 14469578Ssam */ 14477502Sroot if (tp->t_outq.c_cc <= hiwat) { 14489578Ssam splx(s); 14497502Sroot goto loop; 14507502Sroot } 14517502Sroot ttstart(tp); 14529578Ssam if (tp->t_state&TS_NBIO) { 145317545Skarels splx(s); 14547822Sroot if (uio->uio_resid == cnt) 14558520Sroot return (EWOULDBLOCK); 14568520Sroot return (0); 14577502Sroot } 14587502Sroot tp->t_state |= TS_ASLEEP; 14597502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14609578Ssam splx(s); 14617502Sroot goto loop; 14627502Sroot } 14637502Sroot 14647502Sroot /* 14657502Sroot * Rubout one character from the rawq of tp 14667502Sroot * as cleanly as possible. 14677502Sroot */ 14687502Sroot ttyrub(c, tp) 14697625Ssam register c; 14707625Ssam register struct tty *tp; 14717502Sroot { 14727502Sroot register char *cp; 14737502Sroot register int savecol; 14747502Sroot int s; 14757502Sroot char *nextc(); 14767502Sroot 14779578Ssam if ((tp->t_flags&ECHO) == 0) 14787502Sroot return; 14799578Ssam tp->t_flags &= ~FLUSHO; 14807502Sroot c &= 0377; 14819578Ssam if (tp->t_flags&CRTBS) { 14827502Sroot if (tp->t_rocount == 0) { 14837502Sroot /* 14847502Sroot * Screwed by ttwrite; retype 14857502Sroot */ 14867502Sroot ttyretype(tp); 14877502Sroot return; 14887502Sroot } 14899578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14907502Sroot ttyrubo(tp, 2); 14919578Ssam else switch (partab[c&=0177]&0177) { 14927502Sroot 14937502Sroot case ORDINARY: 14947502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14957502Sroot ttyrubo(tp, 2); 14967502Sroot else 14977502Sroot ttyrubo(tp, 1); 14987502Sroot break; 14997502Sroot 15007502Sroot case VTAB: 15017502Sroot case BACKSPACE: 15027502Sroot case CONTROL: 15037502Sroot case RETURN: 15049578Ssam if (tp->t_flags&CTLECH) 15057502Sroot ttyrubo(tp, 2); 15067502Sroot break; 15077502Sroot 15087502Sroot case TAB: 15097502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15107502Sroot ttyretype(tp); 15117502Sroot return; 15127502Sroot } 151317545Skarels s = spltty(); 15147502Sroot savecol = tp->t_col; 15159578Ssam tp->t_state |= TS_CNTTB; 15169578Ssam tp->t_flags |= FLUSHO; 15177502Sroot tp->t_col = tp->t_rocol; 15189578Ssam cp = tp->t_rawq.c_cf; 15199578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 15207502Sroot ttyecho(*cp, tp); 15219578Ssam tp->t_flags &= ~FLUSHO; 15229578Ssam tp->t_state &= ~TS_CNTTB; 15237502Sroot splx(s); 15247502Sroot /* 15257502Sroot * savecol will now be length of the tab 15267502Sroot */ 15277502Sroot savecol -= tp->t_col; 15287502Sroot tp->t_col += savecol; 15297502Sroot if (savecol > 8) 15307502Sroot savecol = 8; /* overflow screw */ 15317502Sroot while (--savecol >= 0) 15327502Sroot (void) ttyoutput('\b', tp); 15337502Sroot break; 15347502Sroot 15357502Sroot default: 15367502Sroot panic("ttyrub"); 15377502Sroot } 15389578Ssam } else if (tp->t_flags&PRTERA) { 15399578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15407502Sroot (void) ttyoutput('\\', tp); 15419578Ssam tp->t_state |= TS_ERASE; 15427502Sroot } 15437502Sroot ttyecho(c, tp); 15447502Sroot } else 15457502Sroot ttyecho(tp->t_erase, tp); 15467502Sroot tp->t_rocount--; 15477502Sroot } 15487502Sroot 15497502Sroot /* 15507502Sroot * Crt back over cnt chars perhaps 15517502Sroot * erasing them. 15527502Sroot */ 15537502Sroot ttyrubo(tp, cnt) 15547625Ssam register struct tty *tp; 15557625Ssam int cnt; 15567502Sroot { 15579578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 15587502Sroot 15597502Sroot while (--cnt >= 0) 15609578Ssam ttyout(rubostring, tp); 15617502Sroot } 15627502Sroot 15637502Sroot /* 15647502Sroot * Reprint the rawq line. 15657502Sroot * We assume c_cc has already been checked. 15667502Sroot */ 15677502Sroot ttyretype(tp) 15687625Ssam register struct tty *tp; 15697502Sroot { 15707502Sroot register char *cp; 15717502Sroot char *nextc(); 15727502Sroot int s; 15737502Sroot 15749578Ssam if (tp->t_rprntc != 0377) 15759578Ssam ttyecho(tp->t_rprntc, tp); 15767502Sroot (void) ttyoutput('\n', tp); 157717545Skarels s = spltty(); 15787502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 15797502Sroot ttyecho(*cp, tp); 15807502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 15817502Sroot ttyecho(*cp, tp); 15829578Ssam tp->t_state &= ~TS_ERASE; 15837502Sroot splx(s); 15847502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15857502Sroot tp->t_rocol = 0; 15867502Sroot } 15877502Sroot 15887502Sroot /* 15897502Sroot * Echo a typed character to the terminal 15907502Sroot */ 15917502Sroot ttyecho(c, tp) 15927625Ssam register c; 15937625Ssam register struct tty *tp; 15947502Sroot { 15957502Sroot 15969578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15979578Ssam tp->t_flags &= ~FLUSHO; 15987502Sroot if ((tp->t_flags&ECHO) == 0) 15997502Sroot return; 16007502Sroot c &= 0377; 16017502Sroot if (tp->t_flags&RAW) { 16027502Sroot (void) ttyoutput(c, tp); 16037502Sroot return; 16047502Sroot } 16057502Sroot if (c == '\r' && tp->t_flags&CRMOD) 16067502Sroot c = '\n'; 16079578Ssam if (tp->t_flags&CTLECH) { 16087502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 16097502Sroot (void) ttyoutput('^', tp); 16107502Sroot c &= 0177; 16117502Sroot if (c == 0177) 16127502Sroot c = '?'; 16137502Sroot else if (tp->t_flags&LCASE) 16147502Sroot c += 'a' - 1; 16157502Sroot else 16167502Sroot c += 'A' - 1; 16177502Sroot } 16187502Sroot } 16199578Ssam (void) ttyoutput(c&0177, tp); 16207502Sroot } 16217502Sroot 16227502Sroot /* 16237502Sroot * Is c a break char for tp? 16247502Sroot */ 16257502Sroot ttbreakc(c, tp) 16267625Ssam register c; 16277625Ssam register struct tty *tp; 16287502Sroot { 16299578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 16307502Sroot c == '\r' && (tp->t_flags&CRMOD)); 16317502Sroot } 16327502Sroot 16337502Sroot /* 16347502Sroot * send string cp to tp 16357502Sroot */ 16367502Sroot ttyout(cp, tp) 16377625Ssam register char *cp; 16387625Ssam register struct tty *tp; 16397502Sroot { 16407502Sroot register char c; 16417502Sroot 16427502Sroot while (c = *cp++) 16437502Sroot (void) ttyoutput(c, tp); 16447502Sroot } 16457502Sroot 16467502Sroot ttwakeup(tp) 16477502Sroot struct tty *tp; 16487502Sroot { 16497502Sroot 16507502Sroot if (tp->t_rsel) { 16517502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16527502Sroot tp->t_state &= ~TS_RCOLL; 16537502Sroot tp->t_rsel = 0; 16547502Sroot } 165512752Ssam if (tp->t_state & TS_ASYNC) 165612752Ssam gsignal(tp->t_pgrp, SIGIO); 16577502Sroot wakeup((caddr_t)&tp->t_rawq); 16587502Sroot } 1659