bug fixes from elz and utcsrgv!thomson
[unix-history] / usr / src / sys / kern / tty.c
... / ...
CommitLineData
1/* tty.c 4.22 82/03/15 */
2
3/*
4 * TTY subroutines common to more than one line discipline
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"
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"
17#include "../h/dk.h"
18
19char partab[];
20
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
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
52#define OBUFSIZ 100
53
54/*
55 * set default control characters.
56 */
57ttychars(tp)
58register struct tty *tp;
59{
60
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;
69/* begin local */
70 tlun.t_suspc = CTRL(z);
71 tlun.t_dsuspc = CTRL(y);
72 tlun.t_rprntc = CTRL(r);
73 tlun.t_flushc = CTRL(o);
74 tlun.t_werasc = CTRL(w);
75 tlun.t_lnextc = CTRL(v);
76 tp->t_local = 0;
77 tp->t_lstate = 0;
78/* end local */
79}
80
81/*
82 * Wait for output to drain, then flush input waiting.
83 */
84wflushtty(tp)
85 register struct tty *tp;
86{
87
88 (void) spl5();
89 while (tp->t_outq.c_cc && tp->t_state&TS_CARR_ON
90 && tp->t_oproc) { /* kludge for pty */
91 (*tp->t_oproc)(tp);
92 tp->t_state |= TS_ASLEEP;
93 sleep((caddr_t)&tp->t_outq, TTOPRI);
94 }
95 flushtty(tp, FREAD);
96 (void) spl0();
97}
98
99/*
100 * flush all TTY queues
101 */
102flushtty(tp, rw)
103register struct tty *tp;
104{
105 register s;
106
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);
115 tp->t_state &= ~TS_TTSTOP;
116 (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
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);
129}
130
131/*
132 * Send stop character on input overflow.
133 */
134ttyblock(tp)
135register struct tty *tp;
136{
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);
141 tp->t_state &= ~TS_TBLOCK;
142 }
143 if (x >= TTYHOG/2) {
144 if (putc(tun.t_stopc, &tp->t_outq)==0) {
145 tp->t_state |= TS_TBLOCK;
146 tp->t_char++;
147 ttstart(tp);
148 }
149 }
150}
151
152/*
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.
157 */
158ttrstrt(tp)
159register struct tty *tp;
160{
161
162 if (tp == 0) {
163 printf("ttrstrt: arg was 0!\n");
164 return;
165 }
166 tp->t_state &= ~TS_TIMEOUT;
167 ttstart(tp);
168}
169
170/*
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.
175 */
176ttstart(tp)
177register struct tty *tp;
178{
179 register s;
180
181 s = spl5();
182 if((tp->t_state&(TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0 &&
183 tp->t_oproc) /* kludge for pty */
184 (*tp->t_oproc)(tp);
185 splx(s);
186}
187
188/*
189 * Common code for tty ioctls.
190 */
191/*ARGSUSED*/
192ttioctl(tp, com, addr, flag)
193register struct tty *tp;
194caddr_t addr;
195{
196 int dev;
197 unsigned t;
198 struct sgttyb iocb;
199 struct clist tq;
200 extern int nldisp;
201 register c;
202 int temp;
203
204 /*
205 * This is especially so that isatty() will
206 * fail when carrier is gone.
207 */
208 if ((tp->t_state&TS_CARR_ON) == 0) {
209 u.u_error = EBADF;
210 return (1);
211 }
212
213 dev = tp->t_dev;
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
221 case TIOCSETD:
222 case TIOCSETP:
223 case TIOCSETN:
224 case TIOCFLUSH:
225 case TIOCSETC:
226 case TIOCSLTC:
227 case TIOCSPGRP:
228 case TIOCLBIS:
229 case TIOCLBIC:
230 case TIOCLSET:
231 case TIOCSTI:
232/* this is reasonable, but impractical...
233 if ((flag & FWRITE) == 0) {
234 u.u_error = EBADF;
235 return (1);
236 }
237 */
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/*
244 &&
245 (u.u_procp->p_flag&SDETACH)==0) {
246*/
247 ) {
248 gsignal(u.u_procp->p_pgrp, SIGTTOU);
249 sleep((caddr_t)&lbolt, TTOPRI);
250 }
251 break;
252 }
253
254 /*
255 * Process the ioctl.
256 */
257 switch(com) {
258
259 /*
260 * Get discipline number
261 */
262 case TIOCGETD:
263 t = tp->t_line;
264 if (copyout((caddr_t)&t, addr, sizeof(t)))
265 u.u_error = EFAULT;
266 break;
267
268 /*
269 * Set line discipline
270 */
271 case TIOCSETD:
272 if (copyin(addr, (caddr_t)&t, sizeof(t))) {
273 u.u_error = EFAULT;
274 break;
275 }
276 if (t >= nldisp) {
277 u.u_error = ENXIO;
278 break;
279 }
280 (void) spl5();
281 if (tp->t_line)
282 (*linesw[tp->t_line].l_close)(tp);
283 if (t)
284 (*linesw[t].l_open)(dev, tp, addr);
285 if (u.u_error==0)
286 tp->t_line = t;
287 (void) spl0();
288 break;
289
290 /*
291 * Prevent more opens on channel
292 */
293 case TIOCEXCL:
294 tp->t_state |= TS_XCLUDE;
295 break;
296
297 case TIOCNXCL:
298 tp->t_state &= ~TS_XCLUDE;
299 break;
300
301 /*
302 * Set new parameters
303 */
304 case TIOCSETP:
305 case TIOCSETN:
306 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
307 u.u_error = EFAULT;
308 return(1);
309 }
310 (void) spl5();
311 if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
312 com == TIOCSETP)
313 wflushtty(tp);
314 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
315 if (iocb.sg_flags & CBREAK) {
316 catq(&tp->t_rawq, &tp->t_canq);
317 tq = tp->t_rawq;
318 tp->t_rawq = tp->t_canq;
319 tp->t_canq = tq;
320 } else {
321 tp->t_local |= LPENDIN;
322 ttwakeup(tp);
323 }
324 }
325 tp->t_ispeed = iocb.sg_ispeed;
326 tp->t_ospeed = iocb.sg_ospeed;
327 tp->t_erase = iocb.sg_erase;
328 tp->t_kill = iocb.sg_kill;
329 tp->t_flags = iocb.sg_flags;
330 if (tp->t_flags & RAW) {
331 tp->t_state &= ~TS_TTSTOP;
332 ttstart(tp);
333 }
334 (void) spl0();
335 break;
336
337 /*
338 * Send current parameters to user
339 */
340 case TIOCGETP:
341 iocb.sg_ispeed = tp->t_ispeed;
342 iocb.sg_ospeed = tp->t_ospeed;
343 iocb.sg_erase = tp->t_erase;
344 iocb.sg_kill = tp->t_kill;
345 iocb.sg_flags = tp->t_flags;
346 if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
347 u.u_error = EFAULT;
348 break;
349
350 /*
351 * Hang up line on last close
352 */
353 case TIOCHPCL:
354 tp->t_state |= TS_HUPCLS;
355 break;
356
357 case TIOCFLUSH: {
358 int flags;
359 if (addr == 0)
360 flags = FREAD|FWRITE;
361 else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
362 u.u_error = EFAULT;
363 return(1);
364 }
365 flushtty(tp, flags);
366 break;
367 }
368
369 case FIONBIO: {
370 int nbio;
371 if (copyin(addr, (caddr_t)&nbio, sizeof (nbio))) {
372 u.u_error = EFAULT;
373 return(1);
374 }
375 if (nbio)
376 tp->t_state |= TS_NBIO;
377 else
378 tp->t_state &= ~TS_NBIO;
379 break;
380 }
381
382 case FIOASYNC: {
383 int async;
384 if (copyin(addr, (caddr_t)&async, sizeof (async))) {
385 u.u_error = EFAULT;
386 return(1);
387 }
388 if (async)
389 tp->t_state |= TS_ASYNC;
390 else
391 tp->t_state &= ~TS_ASYNC;
392 break;
393 }
394
395 /*
396 * Set and fetch special characters
397 */
398 case TIOCSETC:
399 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
400 u.u_error = EFAULT;
401 break;
402
403 case TIOCGETC:
404 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
405 u.u_error = EFAULT;
406 break;
407
408/* local ioctls */
409 /*
410 * Set/get local special characters.
411 */
412 case TIOCSLTC:
413 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
414 u.u_error = EFAULT;
415 break;
416
417 case TIOCGLTC:
418 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
419 u.u_error = EFAULT;
420 break;
421
422 /*
423 * Return number of characters immediately available.
424 */
425 case FIONREAD: {
426 off_t nread = ttnread(tp);
427 if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
428 u.u_error = EFAULT;
429 break;
430 }
431
432 /*
433 * Should allow SPGRP and GPGRP only if tty open for reading.
434 */
435 case TIOCSPGRP:
436 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
437 u.u_error = EFAULT;
438 break;
439
440 case TIOCGPGRP:
441 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
442 u.u_error = EFAULT;
443 break;
444
445 /*
446 * Modify local mode word.
447 */
448 case TIOCLBIS:
449 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
450 u.u_error = EFAULT;
451 else
452 tp->t_local |= temp;
453 break;
454
455 case TIOCLBIC:
456 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
457 u.u_error = EFAULT;
458 else
459 tp->t_local &= ~temp;
460 break;
461
462 case TIOCLSET:
463 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
464 u.u_error = EFAULT;
465 else
466 tp->t_local = temp;
467 break;
468
469 case TIOCLGET:
470 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
471 u.u_error = EFAULT;
472 break;
473
474 /*
475 * Return number of characters in
476 * the output.
477 */
478 case TIOCOUTQ:
479 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
480 u.u_error = EFAULT;
481 break;
482
483 /*
484 * Simulate typing of a character at the terminal.
485 */
486 case TIOCSTI:
487 c = fubyte(addr);
488 if (u.u_uid && u.u_ttyp != tp || c < 0)
489 u.u_error = EFAULT;
490 else
491 (*linesw[tp->t_line].l_rint)(c, tp);
492 break;
493
494 case TIOCSTOP:
495 c = spl5();
496 if ((tp->t_state & TS_TTSTOP) == 0) {
497 tp->t_state |= TS_TTSTOP;
498 (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
499 }
500 splx(c);
501 break;
502
503 case TIOCSTART:
504 c = spl5();
505 if ((tp->t_state & TS_TTSTOP) || (tp->t_local & LFLUSHO)) {
506 tp->t_state &= ~TS_TTSTOP;
507 tp->t_local &= ~LFLUSHO;
508 ttstart(tp);
509 }
510 splx(c);
511 break;
512
513/* end of locals */
514
515 default:
516 return(0);
517 }
518 return(1);
519}
520
521ttnread(tp)
522 struct tty *tp;
523{
524 int nread = 0;
525
526 if (tp->t_local & LPENDIN)
527 ttypend(tp);
528 nread = tp->t_canq.c_cc;
529 if (tp->t_flags & (RAW|CBREAK))
530 nread += tp->t_rawq.c_cc;
531 return (nread);
532}
533
534ttselect(dev, rw)
535 dev_t dev;
536 int rw;
537{
538 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
539 int nread;
540 int s = spl5();
541
542 switch (rw) {
543
544 case FREAD:
545 nread = ttnread(tp);
546 if (nread > 0)
547 goto win;
548 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
549 tp->t_state |= TS_RCOLL;
550 else
551 tp->t_rsel = u.u_procp;
552 break;
553
554 case FWRITE:
555 if (tp->t_outq.c_cc <= TTLOWAT(tp))
556 goto win;
557 if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
558 tp->t_state |= TS_WCOLL;
559 else
560 tp->t_wsel = u.u_procp;
561 break;
562 }
563 splx(s);
564 return (0);
565win:
566 splx(s);
567 return (1);
568}