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*25415Skarels * @(#)tty.c 6.24 (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 /* 65725404Skarels * Default modem control routine (for other line disciplines). 65825404Skarels * Return argument flag, to turn off device on carrier drop. 65925404Skarels */ 660*25415Skarels nullmodem(tp, flag) 661*25415Skarels register struct tty *tp; 66225404Skarels int flag; 66325404Skarels { 66425404Skarels 66525404Skarels if (flag) 66625404Skarels tp->t_state |= TS_CARR_ON; 66725404Skarels else 66825404Skarels tp->t_state &= ~TS_CARR_ON; 66925404Skarels return (flag); 67025404Skarels } 67125404Skarels 67225404Skarels /* 6737502Sroot * reinput pending characters after state switch 67417545Skarels * call at spltty(). 6757502Sroot */ 6767502Sroot ttypend(tp) 6777625Ssam register struct tty *tp; 6787502Sroot { 6797502Sroot struct clist tq; 6807502Sroot register c; 6817502Sroot 6829578Ssam tp->t_flags &= ~PENDIN; 6839578Ssam tp->t_state |= TS_TYPEN; 6847502Sroot tq = tp->t_rawq; 6857502Sroot tp->t_rawq.c_cc = 0; 6867502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 6877502Sroot while ((c = getc(&tq)) >= 0) 6887502Sroot ttyinput(c, tp); 6899578Ssam tp->t_state &= ~TS_TYPEN; 6907502Sroot } 6917502Sroot 6927502Sroot /* 6939578Ssam * Place a character on raw TTY input queue, 6949578Ssam * putting in delimiters and waking up top 6959578Ssam * half as needed. Also echo if required. 6969578Ssam * The arguments are the character and the 6979578Ssam * appropriate tty structure. 6987502Sroot */ 6997502Sroot ttyinput(c, tp) 7007625Ssam register c; 7017625Ssam register struct tty *tp; 7027502Sroot { 7039578Ssam register int t_flags = tp->t_flags; 7047502Sroot int i; 7057502Sroot 7069578Ssam /* 7079578Ssam * If input is pending take it first. 7089578Ssam */ 7099578Ssam if (t_flags&PENDIN) 7107502Sroot ttypend(tp); 7117502Sroot tk_nin++; 7127502Sroot c &= 0377; 7139578Ssam 7149578Ssam /* 7159578Ssam * In tandem mode, check high water mark. 7169578Ssam */ 7177502Sroot if (t_flags&TANDEM) 7187502Sroot ttyblock(tp); 7199578Ssam 7209578Ssam if (t_flags&RAW) { 7219578Ssam /* 7229578Ssam * Raw mode, just put character 7239578Ssam * in input q w/o interpretation. 7249578Ssam */ 7259578Ssam if (tp->t_rawq.c_cc > TTYHOG) 72612752Ssam ttyflush(tp, FREAD|FWRITE); 7279578Ssam else { 7289578Ssam if (putc(c, &tp->t_rawq) >= 0) 7299578Ssam ttwakeup(tp); 7309578Ssam ttyecho(c, tp); 7317502Sroot } 7329578Ssam goto endcase; 7339578Ssam } 7349578Ssam 7359578Ssam /* 7369578Ssam * Ignore any high bit added during 7379578Ssam * previous ttyinput processing. 7389578Ssam */ 73924273Slepreau if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0) 7409578Ssam c &= 0177; 7419578Ssam /* 7429578Ssam * Check for literal nexting very first 7439578Ssam */ 7449578Ssam if (tp->t_state&TS_LNCH) { 7459578Ssam c |= 0200; 7469578Ssam tp->t_state &= ~TS_LNCH; 7479578Ssam } 7489578Ssam 7499578Ssam /* 7509578Ssam * Scan for special characters. This code 7519578Ssam * is really just a big case statement with 7529578Ssam * non-constant cases. The bottom of the 7539578Ssam * case statement is labeled ``endcase'', so goto 7549578Ssam * it after a case match, or similar. 7559578Ssam */ 7569578Ssam if (tp->t_line == NTTYDISC) { 7579578Ssam if (c == tp->t_lnextc) { 75821776Sbloom if (t_flags&ECHO) 7597502Sroot ttyout("^\b", tp); 7609578Ssam tp->t_state |= TS_LNCH; 7619578Ssam goto endcase; 7629578Ssam } 7639578Ssam if (c == tp->t_flushc) { 76421776Sbloom if (t_flags&FLUSHO) 7659578Ssam tp->t_flags &= ~FLUSHO; 7667502Sroot else { 76712752Ssam ttyflush(tp, FWRITE); 7687502Sroot ttyecho(c, tp); 7699578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 7707502Sroot ttyretype(tp); 7719578Ssam tp->t_flags |= FLUSHO; 7727502Sroot } 7739578Ssam goto startoutput; 7749578Ssam } 7759578Ssam if (c == tp->t_suspc) { 77621776Sbloom if ((t_flags&NOFLSH) == 0) 77712752Ssam ttyflush(tp, FREAD); 7789578Ssam ttyecho(c, tp); 7799578Ssam gsignal(tp->t_pgrp, SIGTSTP); 7809578Ssam goto endcase; 7819578Ssam } 7829578Ssam } 7839578Ssam 7849578Ssam /* 7859578Ssam * Handle start/stop characters. 7869578Ssam */ 7879578Ssam if (c == tp->t_stopc) { 7889578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 7899578Ssam tp->t_state |= TS_TTSTOP; 7909578Ssam (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 7917502Sroot return; 7929578Ssam } 7939578Ssam if (c != tp->t_startc) 7949578Ssam return; 7959578Ssam goto endcase; 7969578Ssam } 7979578Ssam if (c == tp->t_startc) 7989578Ssam goto restartoutput; 7999578Ssam 8009578Ssam /* 8019578Ssam * Look for interrupt/quit chars. 8029578Ssam */ 8039578Ssam if (c == tp->t_intrc || c == tp->t_quitc) { 80421776Sbloom if ((t_flags&NOFLSH) == 0) 80512752Ssam ttyflush(tp, FREAD|FWRITE); 8069578Ssam ttyecho(c, tp); 8079578Ssam gsignal(tp->t_pgrp, c == tp->t_intrc ? SIGINT : SIGQUIT); 8089578Ssam goto endcase; 8099578Ssam } 8109578Ssam 81123165Sbloom if (tp->t_flags & LCASE && c <= 0177) { 81223165Sbloom if (tp->t_state&TS_BKSL) { 81323165Sbloom ttyrub(unputc(&tp->t_rawq), tp); 81423165Sbloom if (maptab[c]) 81523165Sbloom c = maptab[c]; 81623165Sbloom c |= 0200; 81723165Sbloom tp->t_state &= ~(TS_BKSL|TS_QUOT); 81823165Sbloom } else if (c >= 'A' && c <= 'Z') 81923165Sbloom c += 'a' - 'A'; 82023165Sbloom else if (c == '\\') 82123165Sbloom tp->t_state |= TS_BKSL; 82223165Sbloom } 82323165Sbloom 8249578Ssam /* 8259578Ssam * Cbreak mode, don't process line editing 8269578Ssam * characters; check high water mark for wakeup. 8279578Ssam */ 8289578Ssam if (t_flags&CBREAK) { 8299578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 8307502Sroot if (tp->t_outq.c_cc < TTHIWAT(tp) && 8317502Sroot tp->t_line == NTTYDISC) 8327502Sroot (void) ttyoutput(CTRL(g), tp); 8337502Sroot } else if (putc(c, &tp->t_rawq) >= 0) { 8347502Sroot ttwakeup(tp); 8357502Sroot ttyecho(c, tp); 8367502Sroot } 8379578Ssam goto endcase; 8389578Ssam } 8399578Ssam 8409578Ssam /* 8419578Ssam * From here on down cooked mode character 8429578Ssam * processing takes place. 8439578Ssam */ 8449578Ssam if ((tp->t_state&TS_QUOT) && 8459578Ssam (c == tp->t_erase || c == tp->t_kill)) { 8469578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8479578Ssam c |= 0200; 8489578Ssam } 8499578Ssam if (c == tp->t_erase) { 8509578Ssam if (tp->t_rawq.c_cc) 8519578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8529578Ssam goto endcase; 8539578Ssam } 8549578Ssam if (c == tp->t_kill) { 85521776Sbloom if (t_flags&CRTKIL && 8569578Ssam tp->t_rawq.c_cc == tp->t_rocount) { 8579578Ssam while (tp->t_rawq.c_cc) 8589578Ssam ttyrub(unputc(&tp->t_rawq), tp); 8599578Ssam } else { 8609578Ssam ttyecho(c, tp); 8619578Ssam ttyecho('\n', tp); 8629578Ssam while (getc(&tp->t_rawq) > 0) 8639578Ssam ; 8649578Ssam tp->t_rocount = 0; 8659578Ssam } 8669578Ssam tp->t_state &= ~TS_LOCAL; 8679578Ssam goto endcase; 8689578Ssam } 8699578Ssam 8709578Ssam /* 8719578Ssam * New line discipline, 8729578Ssam * check word erase/reprint line. 8739578Ssam */ 8749578Ssam if (tp->t_line == NTTYDISC) { 8759578Ssam if (c == tp->t_werasc) { 8769578Ssam if (tp->t_rawq.c_cc == 0) 8779578Ssam goto endcase; 8789578Ssam do { 8799578Ssam c = unputc(&tp->t_rawq); 8809578Ssam if (c != ' ' && c != '\t') 8819578Ssam goto erasenb; 8829578Ssam ttyrub(c, tp); 8839578Ssam } while (tp->t_rawq.c_cc); 8849578Ssam goto endcase; 8859578Ssam erasenb: 8869578Ssam do { 8879578Ssam ttyrub(c, tp); 8889578Ssam if (tp->t_rawq.c_cc == 0) 8899578Ssam goto endcase; 8909578Ssam c = unputc(&tp->t_rawq); 8919578Ssam } while (c != ' ' && c != '\t'); 8929578Ssam (void) putc(c, &tp->t_rawq); 8939578Ssam goto endcase; 8949578Ssam } 8959578Ssam if (c == tp->t_rprntc) { 8969578Ssam ttyretype(tp); 8979578Ssam goto endcase; 8989578Ssam } 8999578Ssam } 9009578Ssam 9019578Ssam /* 9029578Ssam * Check for input buffer overflow 9039578Ssam */ 90410391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 90510391Ssam if (tp->t_line == NTTYDISC) 90610391Ssam (void) ttyoutput(CTRL(g), tp); 9079578Ssam goto endcase; 90810391Ssam } 9099578Ssam 9109578Ssam /* 9119578Ssam * Put data char in q for user and 9129578Ssam * wakeup on seeing a line delimiter. 9139578Ssam */ 9149578Ssam if (putc(c, &tp->t_rawq) >= 0) { 9159578Ssam if (ttbreakc(c, tp)) { 9169578Ssam tp->t_rocount = 0; 9179578Ssam catq(&tp->t_rawq, &tp->t_canq); 9187502Sroot ttwakeup(tp); 9199578Ssam } else if (tp->t_rocount++ == 0) 9209578Ssam tp->t_rocol = tp->t_col; 9219578Ssam tp->t_state &= ~TS_QUOT; 9229578Ssam if (c == '\\') 9239578Ssam tp->t_state |= TS_QUOT; 9249578Ssam if (tp->t_state&TS_ERASE) { 9259578Ssam tp->t_state &= ~TS_ERASE; 9269578Ssam (void) ttyoutput('/', tp); 9279578Ssam } 9289578Ssam i = tp->t_col; 9297502Sroot ttyecho(c, tp); 93021776Sbloom if (c == tp->t_eofc && t_flags&ECHO) { 9319578Ssam i = MIN(2, tp->t_col - i); 9329578Ssam while (i > 0) { 9339578Ssam (void) ttyoutput('\b', tp); 9349578Ssam i--; 9359578Ssam } 9369578Ssam } 9377502Sroot } 9389578Ssam endcase: 9399578Ssam /* 9409578Ssam * If DEC-style start/stop is enabled don't restart 9419578Ssam * output until seeing the start character. 9429578Ssam */ 94321776Sbloom if (t_flags&DECCTQ && tp->t_state&TS_TTSTOP && 9449578Ssam tp->t_startc != tp->t_stopc) 9457502Sroot return; 9469578Ssam restartoutput: 9477502Sroot tp->t_state &= ~TS_TTSTOP; 9489578Ssam tp->t_flags &= ~FLUSHO; 9499578Ssam startoutput: 9507502Sroot ttstart(tp); 9517502Sroot } 9527502Sroot 9537502Sroot /* 9549578Ssam * Put character on TTY output queue, adding delays, 9557502Sroot * expanding tabs, and handling the CR/NL bit. 9569578Ssam * This is called both from the top half for output, 9579578Ssam * and from interrupt level for echoing. 9587502Sroot * The arguments are the character and the tty structure. 9597502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 9607502Sroot * Must be recursive. 9617502Sroot */ 9627502Sroot ttyoutput(c, tp) 9637502Sroot register c; 9647502Sroot register struct tty *tp; 9657502Sroot { 9667502Sroot register char *colp; 9677502Sroot register ctype; 9687502Sroot 9699578Ssam if (tp->t_flags & (RAW|LITOUT)) { 9709578Ssam if (tp->t_flags&FLUSHO) 9717502Sroot return (-1); 9727502Sroot if (putc(c, &tp->t_outq)) 9737625Ssam return (c); 9747502Sroot tk_nout++; 9757502Sroot return (-1); 9767502Sroot } 9779578Ssam 9787502Sroot /* 9799578Ssam * Ignore EOT in normal mode to avoid 9809578Ssam * hanging up certain terminals. 9817502Sroot */ 9827502Sroot c &= 0177; 9839578Ssam if (c == CEOT && (tp->t_flags&CBREAK) == 0) 9847502Sroot return (-1); 9857502Sroot /* 9867502Sroot * Turn tabs to spaces as required 9877502Sroot */ 9889578Ssam if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) { 9897502Sroot register int s; 9907502Sroot 9917502Sroot c = 8 - (tp->t_col&7); 9929578Ssam if ((tp->t_flags&FLUSHO) == 0) { 99317545Skarels s = spltty(); /* don't interrupt tabs */ 9947502Sroot c -= b_to_q(" ", c, &tp->t_outq); 9957502Sroot tk_nout += c; 9967502Sroot splx(s); 9977502Sroot } 9987502Sroot tp->t_col += c; 9997502Sroot return (c ? -1 : '\t'); 10007502Sroot } 10017502Sroot tk_nout++; 10027502Sroot /* 10037502Sroot * for upper-case-only terminals, 10047502Sroot * generate escapes. 10057502Sroot */ 10067502Sroot if (tp->t_flags&LCASE) { 10077502Sroot colp = "({)}!|^~'`"; 10087625Ssam while (*colp++) 10097625Ssam if (c == *colp++) { 10107502Sroot if (ttyoutput('\\', tp) >= 0) 10117502Sroot return (c); 10127502Sroot c = colp[-2]; 10137502Sroot break; 10147502Sroot } 10159578Ssam if ('A' <= c && c <= 'Z') { 10167502Sroot if (ttyoutput('\\', tp) >= 0) 10177502Sroot return (c); 10189578Ssam } else if ('a' <= c && c <= 'z') 10197502Sroot c += 'A' - 'a'; 10207502Sroot } 10219578Ssam 10227502Sroot /* 10237502Sroot * turn <nl> to <cr><lf> if desired. 10247502Sroot */ 10259578Ssam if (c == '\n' && tp->t_flags&CRMOD) 10267502Sroot if (ttyoutput('\r', tp) >= 0) 10277502Sroot return (c); 10289578Ssam if (c == '~' && tp->t_flags&TILDE) 10297502Sroot c = '`'; 10309578Ssam if ((tp->t_flags&FLUSHO) == 0 && putc(c, &tp->t_outq)) 10317502Sroot return (c); 10327502Sroot /* 10337502Sroot * Calculate delays. 10347502Sroot * The numbers here represent clock ticks 10357502Sroot * and are not necessarily optimal for all terminals. 10367502Sroot * The delays are indicated by characters above 0200. 10377502Sroot * In raw mode there are no delays and the 10387502Sroot * transmission path is 8 bits wide. 10399578Ssam * 10409578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 10417502Sroot */ 10427502Sroot colp = &tp->t_col; 10437502Sroot ctype = partab[c]; 10447502Sroot c = 0; 10457502Sroot switch (ctype&077) { 10467502Sroot 10477502Sroot case ORDINARY: 10487502Sroot (*colp)++; 10497502Sroot 10507502Sroot case CONTROL: 10517502Sroot break; 10527502Sroot 10537502Sroot case BACKSPACE: 10547502Sroot if (*colp) 10557502Sroot (*colp)--; 10567502Sroot break; 10577502Sroot 105813821Ssam /* 105913821Ssam * This macro is close enough to the correct thing; 106013821Ssam * it should be replaced by real user settable delays 106113821Ssam * in any event... 106213821Ssam */ 106313821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 10647502Sroot case NEWLINE: 10657502Sroot ctype = (tp->t_flags >> 8) & 03; 10667625Ssam if (ctype == 1) { /* tty 37 */ 106712752Ssam if (*colp > 0) 106813863Ssam c = max((((unsigned)*colp) >> 4) + 3, 106913863Ssam (unsigned)6); 10709578Ssam } else if (ctype == 2) /* vt05 */ 107113821Ssam c = mstohz(100); 10727502Sroot *colp = 0; 10737502Sroot break; 10747502Sroot 10757502Sroot case TAB: 10767502Sroot ctype = (tp->t_flags >> 10) & 03; 10777625Ssam if (ctype == 1) { /* tty 37 */ 10787502Sroot c = 1 - (*colp | ~07); 10797625Ssam if (c < 5) 10807502Sroot c = 0; 10817502Sroot } 10827502Sroot *colp |= 07; 10837502Sroot (*colp)++; 10847502Sroot break; 10857502Sroot 10867502Sroot case VTAB: 10879578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 10887502Sroot c = 0177; 10897502Sroot break; 10907502Sroot 10917502Sroot case RETURN: 10927502Sroot ctype = (tp->t_flags >> 12) & 03; 10939578Ssam if (ctype == 1) /* tn 300 */ 109413821Ssam c = mstohz(83); 10959578Ssam else if (ctype == 2) /* ti 700 */ 109613821Ssam c = mstohz(166); 10979578Ssam else if (ctype == 3) { /* concept 100 */ 10987502Sroot int i; 10999578Ssam 11007502Sroot if ((i = *colp) >= 0) 11019578Ssam for (; i < 9; i++) 11027502Sroot (void) putc(0177, &tp->t_outq); 11037502Sroot } 11047502Sroot *colp = 0; 11057502Sroot } 11069578Ssam if (c && (tp->t_flags&FLUSHO) == 0) 11077502Sroot (void) putc(c|0200, &tp->t_outq); 11087502Sroot return (-1); 11097502Sroot } 111013821Ssam #undef mstohz 11117502Sroot 11127502Sroot /* 11137502Sroot * Called from device's read routine after it has 11147502Sroot * calculated the tty-structure given as argument. 11157502Sroot */ 11167722Swnj ttread(tp, uio) 11177625Ssam register struct tty *tp; 11187722Swnj struct uio *uio; 11197502Sroot { 11207502Sroot register struct clist *qp; 11219578Ssam register c, t_flags; 11229859Ssam int s, first, error = 0; 11237502Sroot 11247502Sroot loop: 11259578Ssam /* 11269578Ssam * Take any pending input first. 11279578Ssam */ 112817545Skarels s = spltty(); 11299578Ssam if (tp->t_flags&PENDIN) 11307502Sroot ttypend(tp); 11319859Ssam splx(s); 11329578Ssam 113323165Sbloom if ((tp->t_state&TS_CARR_ON)==0) 113423165Sbloom return (EIO); 113523165Sbloom 11369578Ssam /* 11379578Ssam * Hang process if it's in the background. 11389578Ssam */ 113923165Sbloom if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 114024392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 114124392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 11427502Sroot u.u_procp->p_flag&SVFORK) 11438520Sroot return (EIO); 11447502Sroot gsignal(u.u_procp->p_pgrp, SIGTTIN); 11457502Sroot sleep((caddr_t)&lbolt, TTIPRI); 114623165Sbloom goto loop; 11477502Sroot } 11489578Ssam t_flags = tp->t_flags; 11499578Ssam 11509578Ssam /* 11519578Ssam * In raw mode take characters directly from the 11529578Ssam * raw queue w/o processing. Interlock against 11539578Ssam * device interrupts when interrogating rawq. 11549578Ssam */ 11559578Ssam if (t_flags&RAW) { 115617545Skarels s = spltty(); 11577502Sroot if (tp->t_rawq.c_cc <= 0) { 11589578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11597502Sroot (tp->t_state&TS_NBIO)) { 11609859Ssam splx(s); 116115094Skarels return (EWOULDBLOCK); 11627502Sroot } 11637502Sroot sleep((caddr_t)&tp->t_rawq, TTIPRI); 11649859Ssam splx(s); 11657502Sroot goto loop; 11667502Sroot } 11679859Ssam splx(s); 116814938Smckusick while (!error && tp->t_rawq.c_cc && uio->uio_resid) 116914938Smckusick error = ureadc(getc(&tp->t_rawq), uio); 11709859Ssam goto checktandem; 11719578Ssam } 11729578Ssam 11739578Ssam /* 11749578Ssam * In cbreak mode use the rawq, otherwise 11759578Ssam * take characters from the canonicalized q. 11769578Ssam */ 11779578Ssam qp = t_flags&CBREAK ? &tp->t_rawq : &tp->t_canq; 11789578Ssam 11799578Ssam /* 11809578Ssam * No input, sleep on rawq awaiting hardware 11819578Ssam * receipt and notification. 11829578Ssam */ 118317545Skarels s = spltty(); 11849578Ssam if (qp->c_cc <= 0) { 11859578Ssam if ((tp->t_state&TS_CARR_ON) == 0 || 11869578Ssam (tp->t_state&TS_NBIO)) { 11879859Ssam splx(s); 11889578Ssam return (EWOULDBLOCK); 11897502Sroot } 11909578Ssam sleep((caddr_t)&tp->t_rawq, TTIPRI); 11919859Ssam splx(s); 11929578Ssam goto loop; 11939578Ssam } 11949859Ssam splx(s); 11959578Ssam 11969578Ssam /* 11979578Ssam * Input present, perform input mapping 11989578Ssam * and processing (we're not in raw mode). 11999578Ssam */ 12009578Ssam first = 1; 12019578Ssam while ((c = getc(qp)) >= 0) { 12029578Ssam if (t_flags&CRMOD && c == '\r') 12039578Ssam c = '\n'; 12049578Ssam /* 12059578Ssam * Check for delayed suspend character. 12069578Ssam */ 12079578Ssam if (tp->t_line == NTTYDISC && c == tp->t_dsuspc) { 12089578Ssam gsignal(tp->t_pgrp, SIGTSTP); 12099578Ssam if (first) { 12109578Ssam sleep((caddr_t)&lbolt, TTIPRI); 12119578Ssam goto loop; 12129578Ssam } 12139578Ssam break; 12147502Sroot } 12159578Ssam /* 12169578Ssam * Interpret EOF only in cooked mode. 12179578Ssam */ 12189578Ssam if (c == tp->t_eofc && (t_flags&CBREAK) == 0) 12199578Ssam break; 12209578Ssam /* 12219578Ssam * Give user character. 12229578Ssam */ 122324273Slepreau error = ureadc(t_flags&PASS8 ? c : c & 0177, uio); 12249578Ssam if (error) 12259578Ssam break; 122614938Smckusick if (uio->uio_resid == 0) 12279578Ssam break; 12289578Ssam /* 12299578Ssam * In cooked mode check for a "break character" 12309578Ssam * marking the end of a "line of input". 12319578Ssam */ 12329578Ssam if ((t_flags&CBREAK) == 0 && ttbreakc(c, tp)) 12339578Ssam break; 12349578Ssam first = 0; 12357502Sroot } 12369578Ssam 12379859Ssam checktandem: 12389578Ssam /* 12399578Ssam * Look to unblock output now that (presumably) 12409578Ssam * the input queue has gone down. 12419578Ssam */ 12429859Ssam if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) 12439578Ssam if (putc(tp->t_startc, &tp->t_outq) == 0) { 12447502Sroot tp->t_state &= ~TS_TBLOCK; 12457502Sroot ttstart(tp); 12467502Sroot } 12478520Sroot return (error); 12487502Sroot } 12497502Sroot 12507502Sroot /* 125125391Skarels * Check the output queue on tp for space for a kernel message 125225391Skarels * (from uprintf/tprintf). Allow some space over the normal 125325391Skarels * hiwater mark so we don't lose messages due to normal flow 125425391Skarels * control, but don't let the tty run amok. 125525391Skarels */ 125625391Skarels ttycheckoutq(tp, wait) 125725391Skarels register struct tty *tp; 125825391Skarels int wait; 125925391Skarels { 126025391Skarels int hiwat, s; 126125391Skarels 126225391Skarels hiwat = TTHIWAT(tp); 126325391Skarels s = spltty(); 126425391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126525391Skarels while (tp->t_outq.c_cc > hiwat) { 126625391Skarels ttstart(tp); 126725391Skarels if (wait == 0) { 126825391Skarels splx(s); 126925391Skarels return (0); 127025391Skarels } 127125391Skarels tp->t_state |= TS_ASLEEP; 127225391Skarels sleep((caddr_t)&tp->t_outq, TTOPRI); 127325391Skarels } 127425391Skarels splx(s); 127525391Skarels return (1); 127625391Skarels } 127725391Skarels 127825391Skarels /* 12797502Sroot * Called from the device's write routine after it has 12807502Sroot * calculated the tty-structure given as argument. 12817502Sroot */ 12827822Sroot ttwrite(tp, uio) 12837625Ssam register struct tty *tp; 12849578Ssam register struct uio *uio; 12857502Sroot { 12867502Sroot register char *cp; 12879578Ssam register int cc, ce, c; 12889578Ssam int i, hiwat, cnt, error, s; 12897502Sroot char obuf[OBUFSIZ]; 12907502Sroot 12919578Ssam hiwat = TTHIWAT(tp); 12929578Ssam cnt = uio->uio_resid; 12939578Ssam error = 0; 12947502Sroot loop: 129521776Sbloom if ((tp->t_state&TS_CARR_ON) == 0) 129621776Sbloom return (EIO); 12979578Ssam /* 12989578Ssam * Hang the process if it's in the background. 12999578Ssam */ 130021776Sbloom if (u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp && 13019578Ssam (tp->t_flags&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 130224392Skarels !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) && 130324392Skarels !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) { 13047502Sroot gsignal(u.u_procp->p_pgrp, SIGTTOU); 13057502Sroot sleep((caddr_t)&lbolt, TTIPRI); 130621776Sbloom goto loop; 13077502Sroot } 13089578Ssam 13099578Ssam /* 13109578Ssam * Process the user's data in at most OBUFSIZ 13119578Ssam * chunks. Perform lower case simulation and 13129578Ssam * similar hacks. Keep track of high water 13139578Ssam * mark, sleep on overflow awaiting device aid 13149578Ssam * in acquiring new space. 13159578Ssam */ 13167822Sroot while (uio->uio_resid > 0) { 13179578Ssam /* 13189578Ssam * Grab a hunk of data from the user. 13199578Ssam */ 13207822Sroot cc = uio->uio_iov->iov_len; 13217822Sroot if (cc == 0) { 13227822Sroot uio->uio_iovcnt--; 13237822Sroot uio->uio_iov++; 132421776Sbloom if (uio->uio_iovcnt <= 0) 13257822Sroot panic("ttwrite"); 13267822Sroot continue; 13277822Sroot } 13287822Sroot if (cc > OBUFSIZ) 13297822Sroot cc = OBUFSIZ; 13307502Sroot cp = obuf; 133112752Ssam error = uiomove(cp, cc, UIO_WRITE, uio); 13328520Sroot if (error) 13337502Sroot break; 13347502Sroot if (tp->t_outq.c_cc > hiwat) 13357502Sroot goto ovhiwat; 13369578Ssam if (tp->t_flags&FLUSHO) 13377502Sroot continue; 13389578Ssam /* 13399578Ssam * If we're mapping lower case or kludging tildes, 13409578Ssam * then we've got to look at each character, so 13419578Ssam * just feed the stuff to ttyoutput... 13429578Ssam */ 13439578Ssam if (tp->t_flags & (LCASE|TILDE)) { 13449578Ssam while (cc > 0) { 13457502Sroot c = *cp++; 13467502Sroot tp->t_rocount = 0; 13477625Ssam while ((c = ttyoutput(c, tp)) >= 0) { 13487502Sroot /* out of clists, wait a bit */ 13497502Sroot ttstart(tp); 13507502Sroot sleep((caddr_t)&lbolt, TTOPRI); 13517502Sroot tp->t_rocount = 0; 135221776Sbloom if (cc != 0) { 135321776Sbloom uio->uio_iov->iov_base -= cc; 135421776Sbloom uio->uio_iov->iov_len += cc; 135521776Sbloom uio->uio_resid += cc; 135621776Sbloom uio->uio_offset -= cc; 135721776Sbloom } 135821776Sbloom goto loop; 13597502Sroot } 13607502Sroot --cc; 13617502Sroot if (tp->t_outq.c_cc > hiwat) 13627502Sroot goto ovhiwat; 13637502Sroot } 13647502Sroot continue; 13657502Sroot } 13669578Ssam /* 13679578Ssam * If nothing fancy need be done, grab those characters we 13689578Ssam * can handle without any of ttyoutput's processing and 13699578Ssam * just transfer them to the output q. For those chars 13709578Ssam * which require special processing (as indicated by the 13719578Ssam * bits in partab), call ttyoutput. After processing 13729578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13739578Ssam * immediately. 13749578Ssam */ 13759578Ssam while (cc > 0) { 13769578Ssam if (tp->t_flags & (RAW|LITOUT)) 13777502Sroot ce = cc; 13787502Sroot else { 137912752Ssam ce = cc - scanc((unsigned)cc, (caddr_t)cp, 138012752Ssam (caddr_t)partab, 077); 13819578Ssam /* 13829578Ssam * If ce is zero, then we're processing 13839578Ssam * a special character through ttyoutput. 13849578Ssam */ 13859578Ssam if (ce == 0) { 13867502Sroot tp->t_rocount = 0; 13877502Sroot if (ttyoutput(*cp, tp) >= 0) { 138821776Sbloom /* no c-lists, wait a bit */ 138921776Sbloom ttstart(tp); 139021776Sbloom sleep((caddr_t)&lbolt, TTOPRI); 139121776Sbloom if (cc != 0) { 139221776Sbloom uio->uio_iov->iov_base -= cc; 139321776Sbloom uio->uio_iov->iov_len += cc; 139421776Sbloom uio->uio_resid += cc; 139521776Sbloom uio->uio_offset -= cc; 139621776Sbloom } 139721776Sbloom goto loop; 13987502Sroot } 13999578Ssam cp++, cc--; 14009578Ssam if (tp->t_flags&FLUSHO || 14019578Ssam tp->t_outq.c_cc > hiwat) 14027502Sroot goto ovhiwat; 14039578Ssam continue; 14047502Sroot } 14057502Sroot } 14069578Ssam /* 14079578Ssam * A bunch of normal characters have been found, 14089578Ssam * transfer them en masse to the output queue and 14099578Ssam * continue processing at the top of the loop. 14109578Ssam * If there are any further characters in this 14119578Ssam * <= OBUFSIZ chunk, the first should be a character 14129578Ssam * requiring special handling by ttyoutput. 14139578Ssam */ 14147502Sroot tp->t_rocount = 0; 14159578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14169578Ssam ce -= i; 14179578Ssam tp->t_col += ce; 14189578Ssam cp += ce, cc -= ce, tk_nout += ce; 14199578Ssam if (i > 0) { 14209578Ssam /* out of c-lists, wait a bit */ 14217502Sroot ttstart(tp); 14227502Sroot sleep((caddr_t)&lbolt, TTOPRI); 142321776Sbloom uio->uio_iov->iov_base -= cc; 142421776Sbloom uio->uio_iov->iov_len += cc; 142521776Sbloom uio->uio_resid += cc; 142621776Sbloom uio->uio_offset -= cc; 142721776Sbloom goto loop; 14287502Sroot } 14299578Ssam if (tp->t_flags&FLUSHO || tp->t_outq.c_cc > hiwat) 14307502Sroot goto ovhiwat; 14317502Sroot } 14327502Sroot } 14337502Sroot ttstart(tp); 14348520Sroot return (error); 14357502Sroot 14367502Sroot ovhiwat: 143717545Skarels s = spltty(); 14389578Ssam if (cc != 0) { 14399578Ssam uio->uio_iov->iov_base -= cc; 14409578Ssam uio->uio_iov->iov_len += cc; 14419578Ssam uio->uio_resid += cc; 14429578Ssam uio->uio_offset -= cc; 14439578Ssam } 14449578Ssam /* 14459578Ssam * This can only occur if FLUSHO 14469578Ssam * is also set in t_flags. 14479578Ssam */ 14487502Sroot if (tp->t_outq.c_cc <= hiwat) { 14499578Ssam splx(s); 14507502Sroot goto loop; 14517502Sroot } 14527502Sroot ttstart(tp); 14539578Ssam if (tp->t_state&TS_NBIO) { 145417545Skarels splx(s); 14557822Sroot if (uio->uio_resid == cnt) 14568520Sroot return (EWOULDBLOCK); 14578520Sroot return (0); 14587502Sroot } 14597502Sroot tp->t_state |= TS_ASLEEP; 14607502Sroot sleep((caddr_t)&tp->t_outq, TTOPRI); 14619578Ssam splx(s); 14627502Sroot goto loop; 14637502Sroot } 14647502Sroot 14657502Sroot /* 14667502Sroot * Rubout one character from the rawq of tp 14677502Sroot * as cleanly as possible. 14687502Sroot */ 14697502Sroot ttyrub(c, tp) 14707625Ssam register c; 14717625Ssam register struct tty *tp; 14727502Sroot { 14737502Sroot register char *cp; 14747502Sroot register int savecol; 14757502Sroot int s; 14767502Sroot char *nextc(); 14777502Sroot 14789578Ssam if ((tp->t_flags&ECHO) == 0) 14797502Sroot return; 14809578Ssam tp->t_flags &= ~FLUSHO; 14817502Sroot c &= 0377; 14829578Ssam if (tp->t_flags&CRTBS) { 14837502Sroot if (tp->t_rocount == 0) { 14847502Sroot /* 14857502Sroot * Screwed by ttwrite; retype 14867502Sroot */ 14877502Sroot ttyretype(tp); 14887502Sroot return; 14897502Sroot } 14909578Ssam if (c == ('\t'|0200) || c == ('\n'|0200)) 14917502Sroot ttyrubo(tp, 2); 14929578Ssam else switch (partab[c&=0177]&0177) { 14937502Sroot 14947502Sroot case ORDINARY: 14957502Sroot if (tp->t_flags&LCASE && c >= 'A' && c <= 'Z') 14967502Sroot ttyrubo(tp, 2); 14977502Sroot else 14987502Sroot ttyrubo(tp, 1); 14997502Sroot break; 15007502Sroot 15017502Sroot case VTAB: 15027502Sroot case BACKSPACE: 15037502Sroot case CONTROL: 15047502Sroot case RETURN: 15059578Ssam if (tp->t_flags&CTLECH) 15067502Sroot ttyrubo(tp, 2); 15077502Sroot break; 15087502Sroot 15097502Sroot case TAB: 15107502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15117502Sroot ttyretype(tp); 15127502Sroot return; 15137502Sroot } 151417545Skarels s = spltty(); 15157502Sroot savecol = tp->t_col; 15169578Ssam tp->t_state |= TS_CNTTB; 15179578Ssam tp->t_flags |= FLUSHO; 15187502Sroot tp->t_col = tp->t_rocol; 15199578Ssam cp = tp->t_rawq.c_cf; 15209578Ssam for (; cp; cp = nextc(&tp->t_rawq, cp)) 15217502Sroot ttyecho(*cp, tp); 15229578Ssam tp->t_flags &= ~FLUSHO; 15239578Ssam tp->t_state &= ~TS_CNTTB; 15247502Sroot splx(s); 15257502Sroot /* 15267502Sroot * savecol will now be length of the tab 15277502Sroot */ 15287502Sroot savecol -= tp->t_col; 15297502Sroot tp->t_col += savecol; 15307502Sroot if (savecol > 8) 15317502Sroot savecol = 8; /* overflow screw */ 15327502Sroot while (--savecol >= 0) 15337502Sroot (void) ttyoutput('\b', tp); 15347502Sroot break; 15357502Sroot 15367502Sroot default: 15377502Sroot panic("ttyrub"); 15387502Sroot } 15399578Ssam } else if (tp->t_flags&PRTERA) { 15409578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15417502Sroot (void) ttyoutput('\\', tp); 15429578Ssam tp->t_state |= TS_ERASE; 15437502Sroot } 15447502Sroot ttyecho(c, tp); 15457502Sroot } else 15467502Sroot ttyecho(tp->t_erase, tp); 15477502Sroot tp->t_rocount--; 15487502Sroot } 15497502Sroot 15507502Sroot /* 15517502Sroot * Crt back over cnt chars perhaps 15527502Sroot * erasing them. 15537502Sroot */ 15547502Sroot ttyrubo(tp, cnt) 15557625Ssam register struct tty *tp; 15567625Ssam int cnt; 15577502Sroot { 15589578Ssam register char *rubostring = tp->t_flags&CRTERA ? "\b \b" : "\b"; 15597502Sroot 15607502Sroot while (--cnt >= 0) 15619578Ssam ttyout(rubostring, tp); 15627502Sroot } 15637502Sroot 15647502Sroot /* 15657502Sroot * Reprint the rawq line. 15667502Sroot * We assume c_cc has already been checked. 15677502Sroot */ 15687502Sroot ttyretype(tp) 15697625Ssam register struct tty *tp; 15707502Sroot { 15717502Sroot register char *cp; 15727502Sroot char *nextc(); 15737502Sroot int s; 15747502Sroot 15759578Ssam if (tp->t_rprntc != 0377) 15769578Ssam ttyecho(tp->t_rprntc, tp); 15777502Sroot (void) ttyoutput('\n', tp); 157817545Skarels s = spltty(); 15797502Sroot for (cp = tp->t_canq.c_cf; cp; cp = nextc(&tp->t_canq, cp)) 15807502Sroot ttyecho(*cp, tp); 15817502Sroot for (cp = tp->t_rawq.c_cf; cp; cp = nextc(&tp->t_rawq, cp)) 15827502Sroot ttyecho(*cp, tp); 15839578Ssam tp->t_state &= ~TS_ERASE; 15847502Sroot splx(s); 15857502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15867502Sroot tp->t_rocol = 0; 15877502Sroot } 15887502Sroot 15897502Sroot /* 15907502Sroot * Echo a typed character to the terminal 15917502Sroot */ 15927502Sroot ttyecho(c, tp) 15937625Ssam register c; 15947625Ssam register struct tty *tp; 15957502Sroot { 15967502Sroot 15979578Ssam if ((tp->t_state&TS_CNTTB) == 0) 15989578Ssam tp->t_flags &= ~FLUSHO; 15997502Sroot if ((tp->t_flags&ECHO) == 0) 16007502Sroot return; 16017502Sroot c &= 0377; 16027502Sroot if (tp->t_flags&RAW) { 16037502Sroot (void) ttyoutput(c, tp); 16047502Sroot return; 16057502Sroot } 16067502Sroot if (c == '\r' && tp->t_flags&CRMOD) 16077502Sroot c = '\n'; 16089578Ssam if (tp->t_flags&CTLECH) { 16097502Sroot if ((c&0177) <= 037 && c!='\t' && c!='\n' || (c&0177)==0177) { 16107502Sroot (void) ttyoutput('^', tp); 16117502Sroot c &= 0177; 16127502Sroot if (c == 0177) 16137502Sroot c = '?'; 16147502Sroot else if (tp->t_flags&LCASE) 16157502Sroot c += 'a' - 1; 16167502Sroot else 16177502Sroot c += 'A' - 1; 16187502Sroot } 16197502Sroot } 16209578Ssam (void) ttyoutput(c&0177, tp); 16217502Sroot } 16227502Sroot 16237502Sroot /* 16247502Sroot * Is c a break char for tp? 16257502Sroot */ 16267502Sroot ttbreakc(c, tp) 16277625Ssam register c; 16287625Ssam register struct tty *tp; 16297502Sroot { 16309578Ssam return (c == '\n' || c == tp->t_eofc || c == tp->t_brkc || 16317502Sroot c == '\r' && (tp->t_flags&CRMOD)); 16327502Sroot } 16337502Sroot 16347502Sroot /* 16357502Sroot * send string cp to tp 16367502Sroot */ 16377502Sroot ttyout(cp, tp) 16387625Ssam register char *cp; 16397625Ssam register struct tty *tp; 16407502Sroot { 16417502Sroot register char c; 16427502Sroot 16437502Sroot while (c = *cp++) 16447502Sroot (void) ttyoutput(c, tp); 16457502Sroot } 16467502Sroot 16477502Sroot ttwakeup(tp) 16487502Sroot struct tty *tp; 16497502Sroot { 16507502Sroot 16517502Sroot if (tp->t_rsel) { 16527502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16537502Sroot tp->t_state &= ~TS_RCOLL; 16547502Sroot tp->t_rsel = 0; 16557502Sroot } 165612752Ssam if (tp->t_state & TS_ASYNC) 165712752Ssam gsignal(tp->t_pgrp, SIGIO); 16587502Sroot wakeup((caddr_t)&tp->t_rawq); 16597502Sroot } 1660