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*25391Skarels * @(#)tty.c 6.22 (Berkeley) 11/04/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) && 135*25391Skarels 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(); 294*25391Skarels (*linesw[tp->t_line].l_close)(tp); 295*25391Skarels error = (*linesw[t].l_open)(dev, tp); 29610851Ssam if (error) { 297*25391Skarels (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 /* 561*25391Skarels * 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 /* 591*25391Skarels * "close" a line discipline 592*25391Skarels */ 593*25391Skarels ttylclose(tp) 594*25391Skarels register struct tty *tp; 595*25391Skarels { 596*25391Skarels 597*25391Skarels ttywflush(tp); 598*25391Skarels tp->t_line = 0; 599*25391Skarels } 600*25391Skarels 601*25391Skarels /* 6027502Sroot * clean tp on last close 6037502Sroot */ 6047502Sroot ttyclose(tp) 6057625Ssam register struct tty *tp; 6067502Sroot { 6077502Sroot 608*25391Skarels ttyflush(tp, FREAD|FWRITE); 6097502Sroot tp->t_pgrp = 0; 6107502Sroot tp->t_state = 0; 6117502Sroot } 6127502Sroot 6137502Sroot /* 614*25391Skarels * Handle modem control transition on a tty. 615*25391Skarels * Flag indicates new state of carrier. 616*25391Skarels * Returns 0 if the line should be turned off, otherwise 1. 617*25391Skarels */ 618*25391Skarels ttymodem(tp, flag) 619*25391Skarels register struct tty *tp; 620*25391Skarels { 621*25391Skarels 622*25391Skarels if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { 623*25391Skarels /* 624*25391Skarels * MDMBUF: do flow control according to carrier flag 625*25391Skarels */ 626*25391Skarels if (flag) { 627*25391Skarels tp->t_state &= ~TS_TTSTOP; 628*25391Skarels ttstart(tp); 629*25391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 630*25391Skarels tp->t_state |= TS_TTSTOP; 631*25391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 632*25391Skarels } 633*25391Skarels } else if (flag == 0) { 634*25391Skarels /* 635*25391Skarels * Lost carrier. 636*25391Skarels */ 637*25391Skarels tp->t_state &= ~TS_CARR_ON; 638*25391Skarels if (tp->t_state & TS_ISOPEN) { 639*25391Skarels if ((tp->t_flags & NOHANG) == 0) { 640*25391Skarels gsignal(tp->t_pgrp, SIGHUP); 641*25391Skarels gsignal(tp->t_pgrp, SIGCONT); 642*25391Skarels ttyflush(tp, FREAD|FWRITE); 643*25391Skarels return (0); 644*25391Skarels } 645*25391Skarels } 646*25391Skarels } else { 647*25391Skarels /* 648*25391Skarels * Carrier now on. 649*25391Skarels */ 650*25391Skarels tp->t_state |= TS_CARR_ON; 651*25391Skarels wakeup((caddr_t)&tp->t_rawq); 652*25391Skarels } 653*25391Skarels return (1); 654*25391Skarels } 655*25391Skarels 656*25391Skarels /* 6577502Sroot * reinput pending characters after state switch 65817545Skarels * call at spltty(). 6597502Sroot */ 6607502Sroot ttypend(tp) 6617625Ssam register struct tty *tp; 6627502Sroot { 6637502Sroot struct clist tq; 6647502Sroot register c; 6657502Sroot 6669578Ssam tp->t_flags &= ~PENDIN; 6679578Ssam tp->t_state |= TS_TYPEN; 6687502Sroot tq = tp->t_rawq; 6697502Sroot tp->t_rawq.c_cc = 0; 6707502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6717502Sroot while ((c = getc(&tq)) >= 0) 6727502Sroot ttyinput(c, tp); 6739578Ssam tp->t_state &= ~TS_TYPEN; 6747502Sroot } 6757502Sroot 6767502Sroot /* 6779578Ssam * Place a character on raw TTY input queue, 6789578Ssam * putting in delimiters and waking up top 6799578Ssam * half as needed. Also echo if required. 6809578Ssam * The arguments are the character and the 6819578Ssam * appropriate tty structure. 6827502Sroot */ 6837502Sroot ttyinput(c, tp) 6847625Ssam register c; 6857625Ssam register struct tty *tp; 6867502Sroot { 6879578Ssam register int t_flags = tp->t_flags; 6887502Sroot int i; 6897502Sroot 6909578Ssam /* 6919578Ssam * If input is pending take it first. 6929578Ssam */ 6939578Ssam if (t_flags&PENDIN) 6947502Sroot ttypend(tp); 6957502Sroot tk_nin++; 6967502Sroot c &= 0377; 6979578Ssam 6989578Ssam /* 6999578Ssam * In tandem mode, check high water mark. 7009578Ssam */ 7017502Sroot if (t_flags&TANDEM) 7027502Sroot ttyblock(tp); 7039578Ssam 7049578Ssam if (t_flags&RAW) { 7059578Ssam /* 7069578Ssam * Raw mode, just put character 7079578Ssam * in input q w/o interpretation. 7089578Ssam */ 7099578Ssam if (tp->t_rawq.c_cc > TTYHOG) 71012752Ssam ttyflush(tp, FREAD|FWRITE); 7119578Ssam else { 7129578Ssam if (putc(c, &tp->t_rawq) >= 0) 7139578Ssam ttwakeup(tp); 7149578Ssam ttyecho(c, tp); 7157502Sroot } 7169578Ssam goto endcase; 7179578Ssam } 7189578Ssam 7199578Ssam /* 7209578Ssam * Ignore any high bit added during 7219578Ssam * previous ttyinput processing. 7229578Ssam */ 72324273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 7249578Ssam c &= 0177; 7259578Ssam /* 7269578Ssam * Check for literal nexting very first 7279578Ssam */ 7289578Ssam if (tp->t_state&TS_LNCH) { 7299578Ssam c |= 0200; 7309578Ssam tp->t_state &= ~TS_LNCH; 7319578Ssam } 7329578Ssam 7339578Ssam /* 7349578Ssam * Scan for special characters. This code 7359578Ssam * is really just a big case statement with 7369578Ssam * non-constant cases. The bottom of the 7379578Ssam * case statement is labeled ``endcase'', so goto 7389578Ssam * it after a case match, or similar. 7399578Ssam */ 7409578Ssam if (tp->t_line == NTTYDISC) { 7419578Ssam if (c == tp->t_lnextc) { 74221776Sbloom if (t_flags&ECHO) 7437502Sroot ttyout("^\b", tp); 7449578Ssam tp->t_state |= TS_LNCH; 7459578Ssam goto endcase; 7469578Ssam } 7479578Ssam if (c == tp->t_flushc) { 74821776Sbloom if (t_flags&FLUSHO) 7499578Ssam tp->t_flags &= ~FLUSHO; 7507502Sroot else { 75112752Ssam ttyflush(tp, FWRITE); 7527502Sroot ttyecho(c, tp); 7539578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7547502Sroot ttyretype(tp); 7559578Ssam tp->t_flags |= FLUSHO; 7567502Sroot } 7579578Ssam goto startoutput; 7589578Ssam } 7599578Ssam if (c == tp->t_suspc) { 76021776Sbloom if ((t_flags&NOFLSH) == 0) 76112752Ssam ttyflush(tp, FREAD); 7629578Ssam ttyecho(c, tp); 7639578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7649578Ssam goto endcase; 7659578Ssam } 7669578Ssam } 7679578Ssam 7689578Ssam /* 7699578Ssam * Handle start/stop characters. 7709578Ssam */ 7719578Ssam if (c == tp->t_stopc) { 7729578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7739578Ssam tp->t_state |= TS_TTSTOP; 7749578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7757502Sroot return; 7769578Ssam } 7779578Ssam if (c != tp->t_startc) 7789578Ssam return; 7799578Ssam goto endcase; 7809578Ssam } 7819578Ssam if (c == tp->t_startc) 7829578Ssam goto restartoutput; 7839578Ssam 7849578Ssam /* 7859578Ssam * Look for interrupt/quit chars. 7869578Ssam */ 7879578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 78821776Sbloom if ((t_flags&NOFLSH) == 0) 78912752Ssam ttyflush(tp, FREAD|FWRITE); 7909578Ssam ttyecho(c, tp); 7919578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 7929578Ssam goto endcase; 7939578Ssam } 7949578Ssam 79523165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 79623165Sbloom if (tp->t_state&TS_BKSL) { 79723165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 79823165Sbloom if (maptab[c]) 79923165Sbloom c = maptab[c]; 80023165Sbloom c |= 0200; 80123165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 80223165Sbloom } else if (c >= 'A' && c <= 'Z') 80323165Sbloom c += 'a' - 'A'; 80423165Sbloom else if (c == '\\') 80523165Sbloom tp->t_state |= TS_BKSL; 80623165Sbloom } 80723165Sbloom 8089578Ssam /* 8099578Ssam * Cbreak mode, don't process line editing 8109578Ssam * characters; check high water mark for wakeup. 8119578Ssam */ 8129578Ssam if (t_flags&CBREAK) { 8139578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 8147502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 8157502Sroot tp->t_line == NTTYDISC) 8167502Sroot (void) ttyoutput(CTRL(g), tp); 8177502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 8187502Sroot ttwakeup(tp); 8197502Sroot ttyecho(c, tp); 8207502Sroot } 8219578Ssam goto endcase; 8229578Ssam } 8239578Ssam 8249578Ssam /* 8259578Ssam * From here on down cooked mode character 8269578Ssam * processing takes place. 8279578Ssam */ 8289578Ssam if ((tp->t_state&TS_QUOT) && 8299578Ssam (c == tp->t_erase || c == tp->t_kill)) { 8309578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8319578Ssam c |= 0200; 8329578Ssam } 8339578Ssam if (c == tp->t_erase) { 8349578Ssam if (tp->t_rawq.c_cc) 8359578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8369578Ssam goto endcase; 8379578Ssam } 8389578Ssam if (c == tp->t_kill) { 83921776Sbloom if (t_flags&CRTKIL && 8409578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8419578Ssam while (tp->t_rawq.c_cc) 8429578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8439578Ssam } else { 8449578Ssam ttyecho(c, tp); 8459578Ssam ttyecho('\n', tp); 8469578Ssam while (getc(&tp->t_rawq) > 0) 8479578Ssam ; 8489578Ssam tp->t_rocount = 0; 8499578Ssam } 8509578Ssam tp->t_state &= ~TS_LOCAL; 8519578Ssam goto endcase; 8529578Ssam } 8539578Ssam 8549578Ssam /* 8559578Ssam * New line discipline, 8569578Ssam * check word erase/reprint line. 8579578Ssam */ 8589578Ssam if (tp->t_line == NTTYDISC) { 8599578Ssam if (c == tp->t_werasc) { 8609578Ssam if (tp->t_rawq.c_cc == 0) 8619578Ssam goto endcase; 8629578Ssam do { 8639578Ssam c = unputc(&tp->t_rawq); 8649578Ssam if (c != ' ' && c != '\t') 8659578Ssam goto erasenb; 8669578Ssam ttyrub(c, tp); 8679578Ssam } while (tp->t_rawq.c_cc); 8689578Ssam goto endcase; 8699578Ssam erasenb: 8709578Ssam do { 8719578Ssam ttyrub(c, tp); 8729578Ssam if (tp->t_rawq.c_cc == 0) 8739578Ssam goto endcase; 8749578Ssam c = unputc(&tp->t_rawq); 8759578Ssam } while (c != ' ' && c != '\t'); 8769578Ssam (void) putc(c, &tp->t_rawq); 8779578Ssam goto endcase; 8789578Ssam } 8799578Ssam if (c == tp->t_rprntc) { 8809578Ssam ttyretype(tp); 8819578Ssam goto endcase; 8829578Ssam } 8839578Ssam } 8849578Ssam 8859578Ssam /* 8869578Ssam * Check for input buffer overflow 8879578Ssam */ 88810391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 88910391Ssam if (tp->t_line == NTTYDISC) 89010391Ssam (void) ttyoutput(CTRL(g), tp); 8919578Ssam goto endcase; 89210391Ssam } 8939578Ssam 8949578Ssam /* 8959578Ssam * Put data char in q for user and 8969578Ssam * wakeup on seeing a line delimiter. 8979578Ssam */ 8989578Ssam if (putc(c, &tp->t_rawq) >= 0) { 8999578Ssam if (ttbreakc(c, tp)) { 9009578Ssam tp->t_rocount = 0; 9019578Ssam catq(&tp->t_rawq, &tp->t_canq); 9027502Sroot ttwakeup(tp); 9039578Ssam } else if (tp->t_rocount++ == 0) 9049578Ssam tp->t_rocol = tp->t_col; 9059578Ssam tp->t_state &= ~TS_QUOT; 9069578Ssam if (c == '\\') 9079578Ssam tp->t_state |= TS_QUOT; 9089578Ssam if (tp->t_state&TS_ERASE) { 9099578Ssam tp->t_state &= ~TS_ERASE; 9109578Ssam (void) ttyoutput('/', tp); 9119578Ssam } 9129578Ssam i = tp->t_col; 9137502Sroot ttyecho(c, tp); 91421776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 9159578Ssam i = MIN(2, tp->t_col - i); 9169578Ssam while (i > 0) { 9179578Ssam (void) ttyoutput('\b', tp); 9189578Ssam i--; 9199578Ssam } 9209578Ssam } 9217502Sroot } 9229578Ssam endcase: 9239578Ssam /* 9249578Ssam * If DEC-style start/stop is enabled don't restart 9259578Ssam * output until seeing the start character. 9269578Ssam */ 92721776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 9289578Ssam tp->t_startc != tp->t_stopc) 9297502Sroot return; 9309578Ssam restartoutput: 9317502Sroot tp->t_state &= ~TS_TTSTOP; 9329578Ssam tp->t_flags &= ~FLUSHO; 9339578Ssam startoutput: 9347502Sroot ttstart(tp); 9357502Sroot } 9367502Sroot 9377502Sroot /* 9389578Ssam * Put character on TTY output queue, adding delays, 9397502Sroot * expanding tabs, and handling the CR/NL bit. 9409578Ssam * This is called both from the top half for output, 9419578Ssam * and from interrupt level for echoing. 9427502Sroot * The arguments are the character and the tty structure. 9437502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 9447502Sroot * Must be recursive. 9457502Sroot */ 9467502Sroot ttyoutput(c, tp) 9477502Sroot register c; 9487502Sroot register struct tty *tp; 9497502Sroot { 9507502Sroot register char *colp; 9517502Sroot register ctype; 9527502Sroot 9539578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9549578Ssam if (tp->t_flags&FLUSHO) 9557502Sroot return (-1); 9567502Sroot if (putc(c, &tp->t_outq)) 9577625Ssam return (c); 9587502Sroot tk_nout++; 9597502Sroot return (-1); 9607502Sroot } 9619578Ssam 9627502Sroot /* 9639578Ssam * Ignore EOT in normal mode to avoid 9649578Ssam * hanging up certain terminals. 9657502Sroot */ 9667502Sroot c &= 0177; 9679578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9687502Sroot return (-1); 9697502Sroot /* 9707502Sroot * Turn tabs to spaces as required 9717502Sroot */ 9729578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9737502Sroot register int s; 9747502Sroot 9757502Sroot c = 8 - (tp->t_col&7); 9769578Ssam if ((tp->t_flags&FLUSHO) == 0) { 97717545Skarels s = spltty(); /* don't interrupt tabs */ 9787502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9797502Sroot tk_nout += c; 9807502Sroot splx(s); 9817502Sroot } 9827502Sroot tp->t_col += c; 9837502Sroot return (c ? -1 : '\t'); 9847502Sroot } 9857502Sroot tk_nout++; 9867502Sroot /* 9877502Sroot * for upper-case-only terminals, 9887502Sroot * generate escapes. 9897502Sroot */ 9907502Sroot if (tp->t_flags&LCASE) { 9917502Sroot colp = "({)}!|^~'`"; 9927625Ssam while (*colp++) 9937625Ssam if (c == *colp++) { 9947502Sroot if (ttyoutput('\\', tp) >= 0) 9957502Sroot return (c); 9967502Sroot c = colp[-2]; 9977502Sroot break; 9987502Sroot } 9999578Ssam if ('A' <= c && c <= 'Z') { 10007502Sroot if (ttyoutput('\\', tp) >= 0) 10017502Sroot return (c); 10029578Ssam } else if ('a' <= c && c <= 'z') 10037502Sroot c += 'A' - 'a'; 10047502Sroot } 10059578Ssam 10067502Sroot /* 10077502Sroot * turn <nl> to <cr><lf> if desired. 10087502Sroot */ 10099578Ssam if (c == '\n' && tp->t_flags&CRMOD) 10107502Sroot if (ttyoutput('\r', tp) >= 0) 10117502Sroot return (c); 10129578Ssam if (c == '~' && tp->t_flags&TILDE) 10137502Sroot c = '`'; 10149578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 10157502Sroot return (c); 10167502Sroot /* 10177502Sroot * Calculate delays. 10187502Sroot * The numbers here represent clock ticks 10197502Sroot * and are not necessarily optimal for all terminals. 10207502Sroot * The delays are indicated by characters above 0200. 10217502Sroot * In raw mode there are no delays and the 10227502Sroot * transmission path is 8 bits wide. 10239578Ssam * 10249578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 10257502Sroot */ 10267502Sroot colp = &tp->t_col; 10277502Sroot ctype = partab[c]; 10287502Sroot c = 0; 10297502Sroot switch (ctype&077) { 10307502Sroot 10317502Sroot case ORDINARY: 10327502Sroot (*colp)++; 10337502Sroot 10347502Sroot case CONTROL: 10357502Sroot break; 10367502Sroot 10377502Sroot case BACKSPACE: 10387502Sroot if (*colp) 10397502Sroot (*colp)--; 10407502Sroot break; 10417502Sroot 104213821Ssam /* 104313821Ssam * This macro is close enough to the correct thing; 104413821Ssam * it should be replaced by real user settable delays 104513821Ssam * in any event... 104613821Ssam */ 104713821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10487502Sroot case NEWLINE: 10497502Sroot ctype = (tp->t_flags >> 8) & 03; 10507625Ssam if (ctype == 1) { /* tty 37 */ 105112752Ssam if (*colp > 0) 105213863Ssam c = max((((unsigned)*colp) >> 4) + 3, 105313863Ssam (unsigned)6); 10549578Ssam } else if (ctype == 2) /* vt05 */ 105513821Ssam c = mstohz(100); 10567502Sroot *colp = 0; 10577502Sroot break; 10587502Sroot 10597502Sroot case TAB: 10607502Sroot ctype = (tp->t_flags >> 10) & 03; 10617625Ssam if (ctype == 1) { /* tty 37 */ 10627502Sroot c = 1 - (*colp | ~07); 10637625Ssam if (c < 5) 10647502Sroot c = 0; 10657502Sroot } 10667502Sroot *colp |= 07; 10677502Sroot (*colp)++; 10687502Sroot break; 10697502Sroot 10707502Sroot case VTAB: 10719578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10727502Sroot c = 0177; 10737502Sroot break; 10747502Sroot 10757502Sroot case RETURN: 10767502Sroot ctype = (tp->t_flags >> 12) & 03; 10779578Ssam if (ctype == 1) /* tn 300 */ 107813821Ssam c = mstohz(83); 10799578Ssam else if (ctype == 2) /* ti 700 */ 108013821Ssam c = mstohz(166); 10819578Ssam else if (ctype == 3) { /* concept 100 */ 10827502Sroot int i; 10839578Ssam 10847502Sroot if ((i = *colp) >= 0) 10859578Ssam for (; i < 9; i++) 10867502Sroot (void) putc(0177, &tp->t_outq); 10877502Sroot } 10887502Sroot *colp = 0; 10897502Sroot } 10909578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 10917502Sroot (void) putc(c|0200, &tp->t_outq); 10927502Sroot return (-1); 10937502Sroot } 109413821Ssam #undef mstohz 10957502Sroot 10967502Sroot /* 10977502Sroot * Called from device's read routine after it has 10987502Sroot * calculated the tty-structure given as argument. 10997502Sroot */ 11007722Swnj ttread(tp, uio) 11017625Ssam register struct tty *tp; 11027722Swnj struct uio *uio; 11037502Sroot { 11047502Sroot register struct clist *qp; 11059578Ssam register c, t_flags; 11069859Ssam int s, first, error = 0; 11077502Sroot 11087502Sroot loop: 11099578Ssam /* 11109578Ssam * Take any pending input first. 11119578Ssam */ 111217545Skarels s = spltty(); 11139578Ssam if (tp->t_flags&PENDIN) 11147502Sroot ttypend(tp); 11159859Ssam splx(s); 11169578Ssam 111723165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 111823165Sbloom return (EIO); 111923165Sbloom 11209578Ssam /* 11219578Ssam * Hang process if it's in the background. 11229578Ssam */ 112323165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 112424392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 112524392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11267502Sroot u.u_procp->p_flag&SVFORK) 11278520Sroot return (EIO); 11287502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11297502Sroot sleep((caddr_t)&lbolt, TTIPRI); 113023165Sbloom goto loop; 11317502Sroot } 11329578Ssam t_flags = tp->t_flags; 11339578Ssam 11349578Ssam /* 11359578Ssam * In raw mode take characters directly from the 11369578Ssam * raw queue w/o processing. Interlock against 11379578Ssam * device interrupts when interrogating rawq. 11389578Ssam */ 11399578Ssam if (t_flags&RAW) { 114017545Skarels s = spltty(); 11417502Sroot if (tp->t_rawq.c_cc <= 0) { 11429578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11437502Sroot (tp->t_state&TS_NBIO)) { 11449859Ssam splx(s); 114515094Skarels return (EWOULDBLOCK); 11467502Sroot } 11477502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11489859Ssam splx(s); 11497502Sroot goto loop; 11507502Sroot } 11519859Ssam splx(s); 115214938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 115314938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11549859Ssam goto checktandem; 11559578Ssam } 11569578Ssam 11579578Ssam /* 11589578Ssam * In cbreak mode use the rawq, otherwise 11599578Ssam * take characters from the canonicalized q. 11609578Ssam */ 11619578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11629578Ssam 11639578Ssam /* 11649578Ssam * No input, sleep on rawq awaiting hardware 11659578Ssam * receipt and notification. 11669578Ssam */ 116717545Skarels s = spltty(); 11689578Ssam if (qp->c_cc <= 0) { 11699578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11709578Ssam (tp->t_state&TS_NBIO)) { 11719859Ssam splx(s); 11729578Ssam return (EWOULDBLOCK); 11737502Sroot } 11749578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11759859Ssam splx(s); 11769578Ssam goto loop; 11779578Ssam } 11789859Ssam splx(s); 11799578Ssam 11809578Ssam /* 11819578Ssam * Input present, perform input mapping 11829578Ssam * and processing (we're not in raw mode). 11839578Ssam */ 11849578Ssam first = 1; 11859578Ssam while ((c = getc(qp)) >= 0) { 11869578Ssam if (t_flags&CRMOD && c == '\r') 11879578Ssam c = '\n'; 11889578Ssam /* 11899578Ssam * Check for delayed suspend character. 11909578Ssam */ 11919578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 11929578Ssam gsignal(tp->t_pgrp, SIGTSTP); 11939578Ssam if (first) { 11949578Ssam sleep((caddr_t)&lbolt, TTIPRI); 11959578Ssam goto loop; 11969578Ssam } 11979578Ssam break; 11987502Sroot } 11999578Ssam /* 12009578Ssam * Interpret EOF only in cooked mode. 12019578Ssam */ 12029578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12039578Ssam break; 12049578Ssam /* 12059578Ssam * Give user character. 12069578Ssam */ 120724273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12089578Ssam if (error) 12099578Ssam break; 121014938Smckusick if (uio->uio_resid == 0) 12119578Ssam break; 12129578Ssam /* 12139578Ssam * In cooked mode check for a "break character" 12149578Ssam * marking the end of a "line of input". 12159578Ssam */ 12169578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12179578Ssam break; 12189578Ssam first = 0; 12197502Sroot } 12209578Ssam 12219859Ssam checktandem: 12229578Ssam /* 12239578Ssam * Look to unblock output now that (presumably) 12249578Ssam * the input queue has gone down. 12259578Ssam */ 12269859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 12279578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 12287502Sroot tp->t_state &= ~TS_TBLOCK; 12297502Sroot ttstart(tp); 12307502Sroot } 12318520Sroot return (error); 12327502Sroot } 12337502Sroot 12347502Sroot /* 1235*25391Skarels * Check the output queue on tp for space for a kernel message 1236*25391Skarels * (from uprintf/tprintf). Allow some space over the normal 1237*25391Skarels * hiwater mark so we don't lose messages due to normal flow 1238*25391Skarels * control, but don't let the tty run amok. 1239*25391Skarels */ 1240*25391Skarels ttycheckoutq(tp, wait) 1241*25391Skarels register struct tty *tp; 1242*25391Skarels int wait; 1243*25391Skarels { 1244*25391Skarels int hiwat, s; 1245*25391Skarels 1246*25391Skarels hiwat = TTHIWAT(tp); 1247*25391Skarels s = spltty(); 1248*25391Skarels if (tp->t_outq.c_cc > hiwat + 200) 1249*25391Skarels while (tp->t_outq.c_cc > hiwat) { 1250*25391Skarels ttstart(tp); 1251*25391Skarels if (wait == 0) { 1252*25391Skarels splx(s); 1253*25391Skarels return (0); 1254*25391Skarels } 1255*25391Skarels tp->t_state |= TS_ASLEEP; 1256*25391Skarels sleep((caddr_t)&tp->t_outq, TTOPRI); 1257*25391Skarels } 1258*25391Skarels splx(s); 1259*25391Skarels return (1); 1260*25391Skarels } 1261*25391Skarels 1262*25391Skarels /* 12637502Sroot * Called from the device's write routine after it has 12647502Sroot * calculated the tty-structure given as argument. 12657502Sroot */ 12667822Sroot ttwrite(tp, uio) 12677625Ssam register struct tty *tp; 12689578Ssam register struct uio *uio; 12697502Sroot { 12707502Sroot register char *cp; 12719578Ssam register int cc, ce, c; 12729578Ssam int i, hiwat, cnt, error, s; 12737502Sroot char obuf[OBUFSIZ]; 12747502Sroot 12759578Ssam hiwat = TTHIWAT(tp); 12769578Ssam cnt = uio->uio_resid; 12779578Ssam error = 0; 12787502Sroot loop: 127921776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 128021776Sbloom return (EIO); 12819578Ssam /* 12829578Ssam * Hang the process if it's in the background. 12839578Ssam */ 128421776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 12859578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 128624392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 128724392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 12887502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 12897502Sroot sleep((caddr_t)&lbolt, TTIPRI); 129021776Sbloom goto loop; 12917502Sroot } 12929578Ssam 12939578Ssam /* 12949578Ssam * Process the user's data in at most OBUFSIZ 12959578Ssam * chunks. Perform lower case simulation and 12969578Ssam * similar hacks. Keep track of high water 12979578Ssam * mark, sleep on overflow awaiting device aid 12989578Ssam * in acquiring new space. 12999578Ssam */ 13007822Sroot while (uio->uio_resid > 0) { 13019578Ssam /* 13029578Ssam * Grab a hunk of data from the user. 13039578Ssam */ 13047822Sroot cc = uio->uio_iov->iov_len; 13057822Sroot if (cc == 0) { 13067822Sroot uio->uio_iovcnt--; 13077822Sroot uio->uio_iov++; 130821776Sbloom if (uio->uio_iovcnt <= 0) 13097822Sroot panic("ttwrite"); 13107822Sroot continue; 13117822Sroot } 13127822Sroot if (cc > OBUFSIZ) 13137822Sroot cc = OBUFSIZ; 13147502Sroot cp = obuf; 131512752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13168520Sroot if (error) 13177502Sroot break; 13187502Sroot if (tp->t_outq.c_cc > hiwat) 13197502Sroot goto ovhiwat; 13209578Ssam if (tp->t_flags&FLUSHO) 13217502Sroot continue; 13229578Ssam /* 13239578Ssam * If we're mapping lower case or kludging tildes, 13249578Ssam * then we've got to look at each character, so 13259578Ssam * just feed the stuff to ttyoutput... 13269578Ssam */ 13279578Ssam if (tp->t_flags & (LCASE|TILDE)) { 13289578Ssam while (cc > 0) { 13297502Sroot c = *cp++; 13307502Sroot tp->t_rocount = 0; 13317625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 13327502Sroot /* out of clists, wait a bit */ 13337502Sroot ttstart(tp); 13347502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13357502Sroot tp->t_rocount = 0; 133621776Sbloom if (cc != 0) { 133721776Sbloom uio->uio_iov->iov_base -= cc; 133821776Sbloom uio->uio_iov->iov_len += cc; 133921776Sbloom uio->uio_resid += cc; 134021776Sbloom uio->uio_offset -= cc; 134121776Sbloom } 134221776Sbloom goto loop; 13437502Sroot } 13447502Sroot --cc; 13457502Sroot if (tp->t_outq.c_cc > hiwat) 13467502Sroot goto ovhiwat; 13477502Sroot } 13487502Sroot continue; 13497502Sroot } 13509578Ssam /* 13519578Ssam * If nothing fancy need be done, grab those characters we 13529578Ssam * can handle without any of ttyoutput's processing and 13539578Ssam * just transfer them to the output q. For those chars 13549578Ssam * which require special processing (as indicated by the 13559578Ssam * bits in partab), call ttyoutput. After processing 13569578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13579578Ssam * immediately. 13589578Ssam */ 13599578Ssam while (cc > 0) { 13609578Ssam if (tp->t_flags & (RAW|LITOUT)) 13617502Sroot ce = cc; 13627502Sroot else { 136312752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 136412752Ssam (caddr_t)partab, 077); 13659578Ssam /* 13669578Ssam * If ce is zero, then we're processing 13679578Ssam * a special character through ttyoutput. 13689578Ssam */ 13699578Ssam if (ce == 0) { 13707502Sroot tp->t_rocount = 0; 13717502Sroot if (ttyoutput(*cp, tp) >= 0) { 137221776Sbloom /* no c-lists, wait a bit */ 137321776Sbloom ttstart(tp); 137421776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 137521776Sbloom if (cc != 0) { 137621776Sbloom uio->uio_iov->iov_base -= cc; 137721776Sbloom uio->uio_iov->iov_len += cc; 137821776Sbloom uio->uio_resid += cc; 137921776Sbloom uio->uio_offset -= cc; 138021776Sbloom } 138121776Sbloom goto loop; 13827502Sroot } 13839578Ssam cp++, cc--; 13849578Ssam if (tp->t_flags&FLUSHO || 13859578Ssam tp->t_outq.c_cc > hiwat) 13867502Sroot goto ovhiwat; 13879578Ssam continue; 13887502Sroot } 13897502Sroot } 13909578Ssam /* 13919578Ssam * A bunch of normal characters have been found, 13929578Ssam * transfer them en masse to the output queue and 13939578Ssam * continue processing at the top of the loop. 13949578Ssam * If there are any further characters in this 13959578Ssam * <= OBUFSIZ chunk, the first should be a character 13969578Ssam * requiring special handling by ttyoutput. 13979578Ssam */ 13987502Sroot tp->t_rocount = 0; 13999578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14009578Ssam ce -= i; 14019578Ssam tp->t_col += ce; 14029578Ssam cp += ce, cc -= ce, tk_nout += ce; 14039578Ssam if (i > 0) { 14049578Ssam /* out of c-lists, wait a bit */ 14057502Sroot ttstart(tp); 14067502Sroot sleep((caddr_t)&lbolt, TTOPRI); 140721776Sbloom uio->uio_iov->iov_base -= cc; 140821776Sbloom uio->uio_iov->iov_len += cc; 140921776Sbloom uio->uio_resid += cc; 141021776Sbloom uio->uio_offset -= cc; 141121776Sbloom goto loop; 14127502Sroot } 14139578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14147502Sroot goto ovhiwat; 14157502Sroot } 14167502Sroot } 14177502Sroot ttstart(tp); 14188520Sroot return (error); 14197502Sroot 14207502Sroot ovhiwat: 142117545Skarels s = spltty(); 14229578Ssam if (cc != 0) { 14239578Ssam uio->uio_iov->iov_base -= cc; 14249578Ssam uio->uio_iov->iov_len += cc; 14259578Ssam uio->uio_resid += cc; 14269578Ssam uio->uio_offset -= cc; 14279578Ssam } 14289578Ssam /* 14299578Ssam * This can only occur if FLUSHO 14309578Ssam * is also set in t_flags. 14319578Ssam */ 14327502Sroot if (tp->t_outq.c_cc <= hiwat) { 14339578Ssam splx(s); 14347502Sroot goto loop; 14357502Sroot } 14367502Sroot ttstart(tp); 14379578Ssam if (tp->t_state&TS_NBIO) { 143817545Skarels splx(s); 14397822Sroot if (uio->uio_resid == cnt) 14408520Sroot return (EWOULDBLOCK); 14418520Sroot return (0); 14427502Sroot } 14437502Sroot tp->t_state |= TS_ASLEEP; 14447502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14459578Ssam splx(s); 14467502Sroot goto loop; 14477502Sroot } 14487502Sroot 14497502Sroot /* 14507502Sroot * Rubout one character from the rawq of tp 14517502Sroot * as cleanly as possible. 14527502Sroot */ 14537502Sroot ttyrub(c, tp) 14547625Ssam register c; 14557625Ssam register struct tty *tp; 14567502Sroot { 14577502Sroot register char *cp; 14587502Sroot register int savecol; 14597502Sroot int s; 14607502Sroot char *nextc(); 14617502Sroot 14629578Ssam if ((tp->t_flags&ECHO) == 0) 14637502Sroot return; 14649578Ssam tp->t_flags &= ~FLUSHO; 14657502Sroot c &= 0377; 14669578Ssam if (tp->t_flags&CRTBS) { 14677502Sroot if (tp->t_rocount == 0) { 14687502Sroot /* 14697502Sroot * Screwed by ttwrite; retype 14707502Sroot */ 14717502Sroot ttyretype(tp); 14727502Sroot return; 14737502Sroot } 14749578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14757502Sroot ttyrubo(tp, 2); 14769578Ssam else switch (partab[c&=0177]&0177) { 14777502Sroot 14787502Sroot case ORDINARY: 14797502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14807502Sroot ttyrubo(tp, 2); 14817502Sroot else 14827502Sroot ttyrubo(tp, 1); 14837502Sroot break; 14847502Sroot 14857502Sroot case VTAB: 14867502Sroot case BACKSPACE: 14877502Sroot case CONTROL: 14887502Sroot case RETURN: 14899578Ssam if (tp->t_flags&CTLECH) 14907502Sroot ttyrubo(tp, 2); 14917502Sroot break; 14927502Sroot 14937502Sroot case TAB: 14947502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 14957502Sroot ttyretype(tp); 14967502Sroot return; 14977502Sroot } 149817545Skarels s = spltty(); 14997502Sroot savecol = tp->t_col; 15009578Ssam tp->t_state |= TS_CNTTB; 15019578Ssam tp->t_flags |= FLUSHO; 15027502Sroot tp->t_col = tp->t_rocol; 15039578Ssam cp = tp->t_rawq.c_cf; 15049578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 15057502Sroot ttyecho(*cp, tp); 15069578Ssam tp->t_flags &= ~FLUSHO; 15079578Ssam tp->t_state &= ~TS_CNTTB; 15087502Sroot splx(s); 15097502Sroot /* 15107502Sroot * savecol will now be length of the tab 15117502Sroot */ 15127502Sroot savecol -= tp->t_col; 15137502Sroot tp->t_col += savecol; 15147502Sroot if (savecol > 8) 15157502Sroot savecol = 8; /* overflow screw */ 15167502Sroot while (--savecol >= 0) 15177502Sroot (void) ttyoutput('\b', tp); 15187502Sroot break; 15197502Sroot 15207502Sroot default: 15217502Sroot panic("ttyrub"); 15227502Sroot } 15239578Ssam } else if (tp->t_flags&PRTERA) { 15249578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15257502Sroot (void) ttyoutput('\\', tp); 15269578Ssam tp->t_state |= TS_ERASE; 15277502Sroot } 15287502Sroot ttyecho(c, tp); 15297502Sroot } else 15307502Sroot ttyecho(tp->t_erase, tp); 15317502Sroot tp->t_rocount--; 15327502Sroot } 15337502Sroot 15347502Sroot /* 15357502Sroot * Crt back over cnt chars perhaps 15367502Sroot * erasing them. 15377502Sroot */ 15387502Sroot ttyrubo(tp, cnt) 15397625Ssam register struct tty *tp; 15407625Ssam int cnt; 15417502Sroot { 15429578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 15437502Sroot 15447502Sroot while (--cnt >= 0) 15459578Ssam ttyout(rubostring, tp); 15467502Sroot } 15477502Sroot 15487502Sroot /* 15497502Sroot * Reprint the rawq line. 15507502Sroot * We assume c_cc has already been checked. 15517502Sroot */ 15527502Sroot ttyretype(tp) 15537625Ssam register struct tty *tp; 15547502Sroot { 15557502Sroot register char *cp; 15567502Sroot char *nextc(); 15577502Sroot int s; 15587502Sroot 15599578Ssam if (tp->t_rprntc != 0377) 15609578Ssam ttyecho(tp->t_rprntc, tp); 15617502Sroot (void) ttyoutput('\n', tp); 156217545Skarels s = spltty(); 15637502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 15647502Sroot ttyecho(*cp, tp); 15657502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 15667502Sroot ttyecho(*cp, tp); 15679578Ssam tp->t_state &= ~TS_ERASE; 15687502Sroot splx(s); 15697502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15707502Sroot tp->t_rocol = 0; 15717502Sroot } 15727502Sroot 15737502Sroot /* 15747502Sroot * Echo a typed character to the terminal 15757502Sroot */ 15767502Sroot ttyecho(c, tp) 15777625Ssam register c; 15787625Ssam register struct tty *tp; 15797502Sroot { 15807502Sroot 15819578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15829578Ssam tp->t_flags &= ~FLUSHO; 15837502Sroot if ((tp->t_flags&ECHO) == 0) 15847502Sroot return; 15857502Sroot c &= 0377; 15867502Sroot if (tp->t_flags&RAW) { 15877502Sroot (void) ttyoutput(c, tp); 15887502Sroot return; 15897502Sroot } 15907502Sroot if (c == '\r' && tp->t_flags&CRMOD) 15917502Sroot c = '\n'; 15929578Ssam if (tp->t_flags&CTLECH) { 15937502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 15947502Sroot (void) ttyoutput('^', tp); 15957502Sroot c &= 0177; 15967502Sroot if (c == 0177) 15977502Sroot c = '?'; 15987502Sroot else if (tp->t_flags&LCASE) 15997502Sroot c += 'a' - 1; 16007502Sroot else 16017502Sroot c += 'A' - 1; 16027502Sroot } 16037502Sroot } 16049578Ssam (void) ttyoutput(c&0177, tp); 16057502Sroot } 16067502Sroot 16077502Sroot /* 16087502Sroot * Is c a break char for tp? 16097502Sroot */ 16107502Sroot ttbreakc(c, tp) 16117625Ssam register c; 16127625Ssam register struct tty *tp; 16137502Sroot { 16149578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 16157502Sroot c == '\r' && (tp->t_flags&CRMOD)); 16167502Sroot } 16177502Sroot 16187502Sroot /* 16197502Sroot * send string cp to tp 16207502Sroot */ 16217502Sroot ttyout(cp, tp) 16227625Ssam register char *cp; 16237625Ssam register struct tty *tp; 16247502Sroot { 16257502Sroot register char c; 16267502Sroot 16277502Sroot while (c = *cp++) 16287502Sroot (void) ttyoutput(c, tp); 16297502Sroot } 16307502Sroot 16317502Sroot ttwakeup(tp) 16327502Sroot struct tty *tp; 16337502Sroot { 16347502Sroot 16357502Sroot if (tp->t_rsel) { 16367502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16377502Sroot tp->t_state &= ~TS_RCOLL; 16387502Sroot tp->t_rsel = 0; 16397502Sroot } 164012752Ssam if (tp->t_state & TS_ASYNC) 164112752Ssam gsignal(tp->t_pgrp, SIGIO); 16427502Sroot wakeup((caddr_t)&tp->t_rawq); 16437502Sroot } 1644