bug fixes (kludge round 1)
[unix-history] / usr / src / sys / kern / tty.c
CommitLineData
4c67f645 1/* tty.c 4.20 82/01/25 */
89dc6dfb
BJ
2
3/*
50e2732b 4 * TTY subroutines common to more than one line discipline
89dc6dfb
BJ
5 */
6#include "../h/param.h"
7#include "../h/systm.h"
8#include "../h/dir.h"
9#include "../h/user.h"
10#include "../h/tty.h"
11#include "../h/proc.h"
89dc6dfb
BJ
12#include "../h/inode.h"
13#include "../h/file.h"
14#include "../h/reg.h"
15#include "../h/conf.h"
16#include "../h/buf.h"
d1778415 17#include "../h/dk.h"
89dc6dfb
BJ
18
19char partab[];
20
89dc6dfb
BJ
21/*
22 * Input mapping table-- if an entry is non-zero, when the
23 * corresponding character is typed preceded by "\" the escape
24 * sequence is replaced by the table value. Mostly used for
25 * upper-case only terminals.
26 */
27
28char maptab[] ={
29 000,000,000,000,000,000,000,000,
30 000,000,000,000,000,000,000,000,
31 000,000,000,000,000,000,000,000,
32 000,000,000,000,000,000,000,000,
33 000,'|',000,000,000,000,000,'`',
34 '{','}',000,000,000,000,000,000,
35 000,000,000,000,000,000,000,000,
36 000,000,000,000,000,000,000,000,
37 000,000,000,000,000,000,000,000,
38 000,000,000,000,000,000,000,000,
39 000,000,000,000,000,000,000,000,
40 000,000,000,000,000,000,'~',000,
41 000,'A','B','C','D','E','F','G',
42 'H','I','J','K','L','M','N','O',
43 'P','Q','R','S','T','U','V','W',
44 'X','Y','Z',000,000,000,000,000,
45};
46
0d65848d
BJ
47short tthiwat[16] =
48 { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,650,650 };
49short ttlowat[16] =
50 { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125,125,125 };
51
89dc6dfb
BJ
52#define OBUFSIZ 100
53
89dc6dfb
BJ
54/*
55 * set default control characters.
56 */
57ttychars(tp)
58register struct tty *tp;
59{
8062c8a7 60
89dc6dfb
BJ
61 tun.t_intrc = CINTR;
62 tun.t_quitc = CQUIT;
63 tun.t_startc = CSTART;
64 tun.t_stopc = CSTOP;
65 tun.t_eofc = CEOT;
66 tun.t_brkc = CBRK;
67 tp->t_erase = CERASE;
68 tp->t_kill = CKILL;
8062c8a7 69/* begin local */
6fdc0335
BJ
70 tlun.t_suspc = CTRL(z);
71 tlun.t_dsuspc = CTRL(y);
8062c8a7
BJ
72 tlun.t_rprntc = CTRL(r);
73 tlun.t_flushc = CTRL(o);
74 tlun.t_werasc = CTRL(w);
75 tlun.t_lnextc = CTRL(v);
8062c8a7
BJ
76 tp->t_local = 0;
77 tp->t_lstate = 0;
78/* end local */
89dc6dfb
BJ
79}
80
81/*
50e2732b 82 * Wait for output to drain, then flush input waiting.
89dc6dfb 83 */
50e2732b 84wflushtty(tp)
941944c9 85 register struct tty *tp;
89dc6dfb
BJ
86{
87
50e2732b 88 (void) spl5();
4c67f645
BJ
89 while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
90 && tp->t_oproc) { /* kludge for pty */
50e2732b 91 (*tp->t_oproc)(tp);
941944c9 92 tp->t_state |= TS_ASLEEP;
50e2732b
BJ
93 sleep((caddr_t)&tp->t_outq, TTOPRI);
94 }
39697bd8 95 flushtty(tp, FREAD);
50e2732b 96 (void) spl0();
89dc6dfb
BJ
97}
98
99/*
50e2732b 100 * flush all TTY queues
89dc6dfb 101 */
50e2732b
BJ
102flushtty(tp, rw)
103register struct tty *tp;
89dc6dfb 104{
50e2732b
BJ
105 register s;
106
50e2732b
BJ
107 s = spl6();
108 if (rw & FREAD) {
109 while (getc(&tp->t_canq) >= 0)
110 ;
111 wakeup((caddr_t)&tp->t_rawq);
112 }
113 if (rw & FWRITE) {
114 wakeup((caddr_t)&tp->t_outq);
941944c9 115 tp->t_state &= ~TS_TTSTOP;
39697bd8 116 (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
50e2732b
BJ
117 while (getc(&tp->t_outq) >= 0)
118 ;
119 }
120 if (rw & FREAD) {
121 while (getc(&tp->t_rawq) >= 0)
122 ;
123 tp->t_delct = 0;
124 tp->t_rocount = 0; /* local */
125 tp->t_rocol = 0;
126 tp->t_lstate = 0;
127 }
128 splx(s);
89dc6dfb
BJ
129}
130
50e2732b
BJ
131/*
132 * Send stop character on input overflow.
133 */
134ttyblock(tp)
135register struct tty *tp;
89dc6dfb 136{
50e2732b
BJ
137 register x;
138 x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
139 if (tp->t_rawq.c_cc > TTYHOG) {
140 flushtty(tp, FREAD|FWRITE);
941944c9 141 tp->t_state &= ~TS_TBLOCK;
50e2732b
BJ
142 }
143 if (x >= TTYHOG/2) {
144 if (putc(tun.t_stopc, &tp->t_outq)==0) {
941944c9 145 tp->t_state |= TS_TBLOCK;
50e2732b
BJ
146 tp->t_char++;
147 ttstart(tp);
148 }
149 }
89dc6dfb
BJ
150}
151
101ba270 152/*
50e2732b
BJ
153 * Restart typewriter output following a delay
154 * timeout.
155 * The name of the routine is passed to the timeout
156 * subroutine and it is called during a clock interrupt.
101ba270 157 */
50e2732b 158ttrstrt(tp)
101ba270 159register struct tty *tp;
101ba270
BJ
160{
161
545f5350
BJ
162 if (tp == 0) {
163 printf("ttrstrt: arg was 0!\n");
164 return;
165 }
941944c9 166 tp->t_state &= ~TS_TIMEOUT;
50e2732b 167 ttstart(tp);
101ba270
BJ
168}
169
89dc6dfb 170/*
50e2732b
BJ
171 * Start output on the typewriter. It is used from the top half
172 * after some characters have been put on the output queue,
173 * from the interrupt routine to transmit the next
174 * character, and after a timeout has finished.
89dc6dfb 175 */
50e2732b
BJ
176ttstart(tp)
177register struct tty *tp;
89dc6dfb 178{
50e2732b 179 register s;
8062c8a7 180
50e2732b 181 s = spl5();
4c67f645
BJ
182 if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
183 tp->t_oproc) /* kludge for pty */
50e2732b
BJ
184 (*tp->t_oproc)(tp);
185 splx(s);
89dc6dfb
BJ
186}
187
188/*
50e2732b 189 * Common code for tty ioctls.
89dc6dfb 190 */
49c84d3f 191/*ARGSUSED*/
0cbf0d70 192ttioctl(tp, com, addr, flag)
89dc6dfb
BJ
193register struct tty *tp;
194caddr_t addr;
195{
0cbf0d70 196 int dev;
89dc6dfb 197 unsigned t;
8062c8a7 198 struct sgttyb iocb;
de857265 199 struct clist tq;
89dc6dfb 200 extern int nldisp;
50450a20 201 register c;
da1392b6 202 int temp;
89dc6dfb 203
c6fe3a50
BJ
204 /*
205 * This is especially so that isatty() will
206 * fail when carrier is gone.
207 */
941944c9 208 if ((tp->t_state&TS_CARR_ON) == 0) {
c6fe3a50
BJ
209 u.u_error = EBADF;
210 return (1);
211 }
212
0cbf0d70 213 dev = tp->t_dev;
50e2732b
BJ
214 /*
215 * If the ioctl involves modification,
216 * insist on being able to write the device,
217 * and hang if in the background.
218 */
219 switch(com) {
220
c6fe3a50
BJ
221 case TIOCSETD:
222 case TIOCSETP:
223 case TIOCSETN:
50e2732b
BJ
224 case TIOCFLUSH:
225 case TIOCSETC:
226 case TIOCSLTC:
227 case TIOCSPGRP:
228 case TIOCLBIS:
229 case TIOCLBIC:
230 case TIOCLSET:
231 case TIOCSTI:
c6fe3a50 232/* this is reasonable, but impractical...
50e2732b
BJ
233 if ((flag & FWRITE) == 0) {
234 u.u_error = EBADF;
235 return (1);
236 }
c6fe3a50 237 */
50e2732b
BJ
238 while (tp->t_line == NTTYDISC &&
239 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
240 (u.u_procp->p_flag&SVFORK) == 0 &&
241 u.u_signal[SIGTTOU] != SIG_IGN &&
242 u.u_signal[SIGTTOU] != SIG_HOLD &&
243 (u.u_procp->p_flag&SDETACH)==0) {
244 gsignal(u.u_procp->p_pgrp, SIGTTOU);
245 sleep((caddr_t)&lbolt, TTOPRI);
246 }
247 break;
248 }
249
250 /*
251 * Process the ioctl.
252 */
89dc6dfb
BJ
253 switch(com) {
254
255 /*
50e2732b 256 * Get discipline number
89dc6dfb
BJ
257 */
258 case TIOCGETD:
259 t = tp->t_line;
260 if (copyout((caddr_t)&t, addr, sizeof(t)))
261 u.u_error = EFAULT;
262 break;
263
264 /*
50e2732b 265 * Set line discipline
89dc6dfb
BJ
266 */
267 case TIOCSETD:
268 if (copyin(addr, (caddr_t)&t, sizeof(t))) {
269 u.u_error = EFAULT;
270 break;
271 }
272 if (t >= nldisp) {
273 u.u_error = ENXIO;
274 break;
275 }
8062c8a7 276 (void) spl5();
89dc6dfb
BJ
277 if (tp->t_line)
278 (*linesw[tp->t_line].l_close)(tp);
279 if (t)
280 (*linesw[t].l_open)(dev, tp, addr);
281 if (u.u_error==0)
282 tp->t_line = t;
8062c8a7 283 (void) spl0();
89dc6dfb
BJ
284 break;
285
152c2598
BJ
286 /*
287 * Prevent more opens on channel
288 */
289 case TIOCEXCL:
290 tp->t_state |= TS_XCLUDE;
291 break;
292
293 case TIOCNXCL:
294 tp->t_state &= ~TS_XCLUDE;
295 break;
296
89dc6dfb
BJ
297 /*
298 * Set new parameters
299 */
300 case TIOCSETP:
de857265 301 case TIOCSETN:
89dc6dfb
BJ
302 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
303 u.u_error = EFAULT;
304 return(1);
305 }
101ba270 306 (void) spl5();
e1d74936
BJ
307 if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
308 com == TIOCSETP)
309 wflushtty(tp);
310 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
311 if (iocb.sg_flags & CBREAK) {
312 catq(&tp->t_rawq, &tp->t_canq);
313 tq = tp->t_rawq;
314 tp->t_rawq = tp->t_canq;
315 tp->t_canq = tq;
316 } else {
317 tp->t_local |= LPENDIN;
318 ttwakeup(tp);
8062c8a7
BJ
319 }
320 }
e1d74936
BJ
321 tp->t_ispeed = iocb.sg_ispeed;
322 tp->t_ospeed = iocb.sg_ospeed;
8062c8a7
BJ
323 tp->t_erase = iocb.sg_erase;
324 tp->t_kill = iocb.sg_kill;
325 tp->t_flags = iocb.sg_flags;
627c86ee 326 if (tp->t_flags & RAW) {
941944c9 327 tp->t_state &= ~TS_TTSTOP;
627c86ee
KB
328 ttstart(tp);
329 }
101ba270 330 (void) spl0();
89dc6dfb
BJ
331 break;
332
333 /*
50e2732b 334 * Send current parameters to user
89dc6dfb
BJ
335 */
336 case TIOCGETP:
8062c8a7
BJ
337 iocb.sg_ispeed = tp->t_ispeed;
338 iocb.sg_ospeed = tp->t_ospeed;
339 iocb.sg_erase = tp->t_erase;
340 iocb.sg_kill = tp->t_kill;
341 iocb.sg_flags = tp->t_flags;
89dc6dfb
BJ
342 if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
343 u.u_error = EFAULT;
344 break;
345
346 /*
347 * Hang up line on last close
348 */
89dc6dfb 349 case TIOCHPCL:
941944c9 350 tp->t_state |= TS_HUPCLS;
89dc6dfb
BJ
351 break;
352
7d973a4d
KB
353 case TIOCFLUSH: {
354 int flags;
355 if (addr == 0)
356 flags = FREAD|FWRITE;
357 else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
358 u.u_error = EFAULT;
7344d489 359 return(1);
7d973a4d
KB
360 }
361 flushtty(tp, flags);
89dc6dfb 362 break;
4568c08e 363 }
89dc6dfb 364
941944c9
BJ
365 case FIONBIO: {
366 int nbio;
367 if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
368 u.u_error = EFAULT;
369 return(1);
370 }
371 if (nbio)
372 tp->t_state |= TS_NBIO;
373 else
374 tp->t_state &= ~TS_NBIO;
375 break;
376 }
377
89dc6dfb 378 /*
50e2732b 379 * Set and fetch special characters
89dc6dfb
BJ
380 */
381 case TIOCSETC:
8062c8a7 382 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
89dc6dfb
BJ
383 u.u_error = EFAULT;
384 break;
385
386 case TIOCGETC:
8062c8a7
BJ
387 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
388 u.u_error = EFAULT;
389 break;
390
391/* local ioctls */
50e2732b
BJ
392 /*
393 * Set/get local special characters.
394 */
8062c8a7
BJ
395 case TIOCSLTC:
396 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
397 u.u_error = EFAULT;
398 break;
399
400 case TIOCGLTC:
401 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
402 u.u_error = EFAULT;
403 break;
404
50e2732b
BJ
405 /*
406 * Return number of characters immediately available.
407 */
8062c8a7 408 case FIONREAD: {
e1d74936 409 off_t nread = ttnread(tp);
8062c8a7
BJ
410 if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
411 u.u_error = EFAULT;
412 break;
413 }
414
415 /*
416 * Should allow SPGRP and GPGRP only if tty open for reading.
417 */
418 case TIOCSPGRP:
da1392b6
BJ
419 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
420 u.u_error = EFAULT;
8062c8a7
BJ
421 break;
422
423 case TIOCGPGRP:
424 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
425 u.u_error = EFAULT;
426 break;
427
428 /*
429 * Modify local mode word.
430 */
431 case TIOCLBIS:
da1392b6
BJ
432 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
433 u.u_error = EFAULT;
434 else
435 tp->t_local |= temp;
8062c8a7
BJ
436 break;
437
438 case TIOCLBIC:
da1392b6
BJ
439 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
440 u.u_error = EFAULT;
441 else
442 tp->t_local &= ~temp;
8062c8a7
BJ
443 break;
444
445 case TIOCLSET:
da1392b6
BJ
446 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
447 u.u_error = EFAULT;
448 else
449 tp->t_local = temp;
8062c8a7
BJ
450 break;
451
452 case TIOCLGET:
453 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
89dc6dfb
BJ
454 u.u_error = EFAULT;
455 break;
456
50e2732b
BJ
457 /*
458 * Return number of characters in
459 * the output.
460 */
0dde1c43
BJ
461 case TIOCOUTQ:
462 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
463 u.u_error = EFAULT;
464 break;
465
50e2732b
BJ
466 /*
467 * Simulate typing of a character at the terminal.
468 */
50450a20
BJ
469 case TIOCSTI:
470 c = fubyte(addr);
471 if (u.u_uid && u.u_ttyp != tp || c < 0)
472 u.u_error = EFAULT;
473 else
474 (*linesw[tp->t_line].l_rint)(c, tp);
475 break;
bfcf09ee
BJ
476
477 case TIOCSTOP:
478 c = spl5();
479 if ((tp->t_state & TS_TTSTOP) == 0) {
480 tp->t_state |= TS_TTSTOP;
481 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
482 }
483 splx(c);
484 break;
485
486 case TIOCSTART:
487 c = spl5();
488 if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
489 tp->t_state &= ~TS_TTSTOP;
490 tp->t_local &= ~LFLUSHO;
491 ttstart(tp);
492 }
493 splx(c);
494 break;
495
8062c8a7 496/* end of locals */
50450a20 497
89dc6dfb
BJ
498 default:
499 return(0);
500 }
501 return(1);
502}
e1d74936
BJ
503
504ttnread(tp)
505 struct tty *tp;
506{
507 int nread = 0;
508
509 if (tp->t_local & LPENDIN)
510 ttypend(tp);
511 nread = tp->t_canq.c_cc;
512 if (tp->t_flags & (RAW|CBREAK))
513 nread += tp->t_rawq.c_cc;
514 return (nread);
515}
516
941944c9 517ttselect(dev, rw)
e1d74936 518 dev_t dev;
941944c9 519 int rw;
e1d74936
BJ
520{
521 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
522 int nread;
941944c9 523 int s = spl5();
e1d74936 524
941944c9 525 switch (rw) {
e1d74936
BJ
526
527 case FREAD:
528 nread = ttnread(tp);
529 if (nread > 0)
941944c9 530 goto win;
89b8a44c 531 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
941944c9 532 tp->t_state |= TS_RCOLL;
e1d74936
BJ
533 else
534 tp->t_rsel = u.u_procp;
941944c9 535 break;
e1d74936 536
941944c9
BJ
537 case FWRITE:
538 if (tp->t_outq.c_cc <= TTLOWAT(tp))
539 goto win;
941944c9
BJ
540 if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
541 tp->t_state |= TS_WCOLL;
542 else
543 tp->t_wsel = u.u_procp;
544 break;
e1d74936 545 }
941944c9
BJ
546 splx(s);
547 return (0);
548win:
549 splx(s);
550 return (1);
e1d74936 551}