new and cleaner version
[unix-history] / usr / src / sys / kern / tty.c
CommitLineData
89b8a44c 1/* tty.c 4.14 81/11/18 */
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)
89dc6dfb
BJ
85register struct tty *tp;
86{
87
50e2732b
BJ
88 (void) spl5();
89 while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
90 (*tp->t_oproc)(tp);
91 tp->t_state |= ASLEEP;
92 sleep((caddr_t)&tp->t_outq, TTOPRI);
93 }
94 flushtty(tp, FREAD|FWRITE);
95 (void) spl0();
89dc6dfb
BJ
96}
97
98/*
50e2732b 99 * flush all TTY queues
89dc6dfb 100 */
50e2732b
BJ
101flushtty(tp, rw)
102register struct tty *tp;
89dc6dfb 103{
50e2732b
BJ
104 register s;
105
50e2732b
BJ
106 s = spl6();
107 if (rw & FREAD) {
108 while (getc(&tp->t_canq) >= 0)
109 ;
110 wakeup((caddr_t)&tp->t_rawq);
111 }
112 if (rw & FWRITE) {
113 wakeup((caddr_t)&tp->t_outq);
114 tp->t_state &= ~TTSTOP;
115 (*cdevsw[major(tp->t_dev)].d_stop)(tp);
116 while (getc(&tp->t_outq) >= 0)
117 ;
118 }
119 if (rw & FREAD) {
120 while (getc(&tp->t_rawq) >= 0)
121 ;
122 tp->t_delct = 0;
123 tp->t_rocount = 0; /* local */
124 tp->t_rocol = 0;
125 tp->t_lstate = 0;
126 }
127 splx(s);
89dc6dfb
BJ
128}
129
50e2732b
BJ
130/*
131 * Send stop character on input overflow.
132 */
133ttyblock(tp)
134register struct tty *tp;
89dc6dfb 135{
50e2732b
BJ
136 register x;
137 x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
138 if (tp->t_rawq.c_cc > TTYHOG) {
139 flushtty(tp, FREAD|FWRITE);
140 tp->t_state &= ~TBLOCK;
141 }
142 if (x >= TTYHOG/2) {
143 if (putc(tun.t_stopc, &tp->t_outq)==0) {
144 tp->t_state |= TBLOCK;
145 tp->t_char++;
146 ttstart(tp);
147 }
148 }
89dc6dfb
BJ
149}
150
101ba270 151/*
50e2732b
BJ
152 * Restart typewriter output following a delay
153 * timeout.
154 * The name of the routine is passed to the timeout
155 * subroutine and it is called during a clock interrupt.
101ba270 156 */
50e2732b 157ttrstrt(tp)
101ba270 158register struct tty *tp;
101ba270
BJ
159{
160
545f5350
BJ
161 if (tp == 0) {
162 printf("ttrstrt: arg was 0!\n");
163 return;
164 }
50e2732b
BJ
165 tp->t_state &= ~TIMEOUT;
166 ttstart(tp);
101ba270
BJ
167}
168
89dc6dfb 169/*
50e2732b
BJ
170 * Start output on the typewriter. It is used from the top half
171 * after some characters have been put on the output queue,
172 * from the interrupt routine to transmit the next
173 * character, and after a timeout has finished.
89dc6dfb 174 */
50e2732b
BJ
175ttstart(tp)
176register struct tty *tp;
89dc6dfb 177{
50e2732b 178 register s;
8062c8a7 179
50e2732b
BJ
180 s = spl5();
181 if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
182 (*tp->t_oproc)(tp);
183 splx(s);
89dc6dfb
BJ
184}
185
186/*
50e2732b 187 * Common code for tty ioctls.
89dc6dfb 188 */
49c84d3f 189/*ARGSUSED*/
0cbf0d70 190ttioctl(tp, com, addr, flag)
89dc6dfb
BJ
191register struct tty *tp;
192caddr_t addr;
193{
0cbf0d70 194 int dev;
89dc6dfb 195 unsigned t;
8062c8a7 196 struct sgttyb iocb;
de857265 197 struct clist tq;
89dc6dfb 198 extern int nldisp;
50450a20 199 register c;
da1392b6 200 int temp;
89dc6dfb 201
c6fe3a50
BJ
202 /*
203 * This is especially so that isatty() will
204 * fail when carrier is gone.
205 */
206 if ((tp->t_state&CARR_ON) == 0) {
207 u.u_error = EBADF;
208 return (1);
209 }
210
0cbf0d70 211 dev = tp->t_dev;
50e2732b
BJ
212 /*
213 * If the ioctl involves modification,
214 * insist on being able to write the device,
215 * and hang if in the background.
216 */
217 switch(com) {
218
c6fe3a50
BJ
219 case TIOCSETD:
220 case TIOCSETP:
221 case TIOCSETN:
50e2732b
BJ
222 case TIOCFLUSH:
223 case TIOCSETC:
224 case TIOCSLTC:
225 case TIOCSPGRP:
226 case TIOCLBIS:
227 case TIOCLBIC:
228 case TIOCLSET:
229 case TIOCSTI:
c6fe3a50 230/* this is reasonable, but impractical...
50e2732b
BJ
231 if ((flag & FWRITE) == 0) {
232 u.u_error = EBADF;
233 return (1);
234 }
c6fe3a50 235 */
50e2732b
BJ
236 while (tp->t_line == NTTYDISC &&
237 u.u_procp->p_pgrp != tp->t_pgrp && tp == u.u_ttyp &&
238 (u.u_procp->p_flag&SVFORK) == 0 &&
239 u.u_signal[SIGTTOU] != SIG_IGN &&
240 u.u_signal[SIGTTOU] != SIG_HOLD &&
241 (u.u_procp->p_flag&SDETACH)==0) {
242 gsignal(u.u_procp->p_pgrp, SIGTTOU);
243 sleep((caddr_t)&lbolt, TTOPRI);
244 }
245 break;
246 }
247
248 /*
249 * Process the ioctl.
250 */
89dc6dfb
BJ
251 switch(com) {
252
253 /*
50e2732b 254 * Get discipline number
89dc6dfb
BJ
255 */
256 case TIOCGETD:
257 t = tp->t_line;
258 if (copyout((caddr_t)&t, addr, sizeof(t)))
259 u.u_error = EFAULT;
260 break;
261
262 /*
50e2732b 263 * Set line discipline
89dc6dfb
BJ
264 */
265 case TIOCSETD:
266 if (copyin(addr, (caddr_t)&t, sizeof(t))) {
267 u.u_error = EFAULT;
268 break;
269 }
270 if (t >= nldisp) {
271 u.u_error = ENXIO;
272 break;
273 }
8062c8a7 274 (void) spl5();
89dc6dfb
BJ
275 if (tp->t_line)
276 (*linesw[tp->t_line].l_close)(tp);
277 if (t)
278 (*linesw[t].l_open)(dev, tp, addr);
279 if (u.u_error==0)
280 tp->t_line = t;
8062c8a7 281 (void) spl0();
89dc6dfb
BJ
282 break;
283
89dc6dfb
BJ
284 /*
285 * Set new parameters
286 */
287 case TIOCSETP:
de857265 288 case TIOCSETN:
89dc6dfb
BJ
289 if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
290 u.u_error = EFAULT;
291 return(1);
292 }
101ba270 293 (void) spl5();
e1d74936
BJ
294 if (tp->t_flags&RAW || iocb.sg_flags&RAW ||
295 com == TIOCSETP)
296 wflushtty(tp);
297 else if ((tp->t_flags&CBREAK) != (iocb.sg_flags&CBREAK)) {
298 if (iocb.sg_flags & CBREAK) {
299 catq(&tp->t_rawq, &tp->t_canq);
300 tq = tp->t_rawq;
301 tp->t_rawq = tp->t_canq;
302 tp->t_canq = tq;
303 } else {
304 tp->t_local |= LPENDIN;
305 ttwakeup(tp);
8062c8a7
BJ
306 }
307 }
e1d74936
BJ
308 tp->t_ispeed = iocb.sg_ispeed;
309 tp->t_ospeed = iocb.sg_ospeed;
8062c8a7
BJ
310 tp->t_erase = iocb.sg_erase;
311 tp->t_kill = iocb.sg_kill;
312 tp->t_flags = iocb.sg_flags;
627c86ee
KB
313 if (tp->t_flags & RAW) {
314 tp->t_state &= ~TTSTOP;
315 ttstart(tp);
316 }
101ba270 317 (void) spl0();
89dc6dfb
BJ
318 break;
319
320 /*
50e2732b 321 * Send current parameters to user
89dc6dfb
BJ
322 */
323 case TIOCGETP:
8062c8a7
BJ
324 iocb.sg_ispeed = tp->t_ispeed;
325 iocb.sg_ospeed = tp->t_ospeed;
326 iocb.sg_erase = tp->t_erase;
327 iocb.sg_kill = tp->t_kill;
328 iocb.sg_flags = tp->t_flags;
89dc6dfb
BJ
329 if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
330 u.u_error = EFAULT;
331 break;
332
333 /*
334 * Hang up line on last close
335 */
89dc6dfb
BJ
336 case TIOCHPCL:
337 tp->t_state |= HUPCLS;
338 break;
339
7d973a4d
KB
340 case TIOCFLUSH: {
341 int flags;
342 if (addr == 0)
343 flags = FREAD|FWRITE;
344 else if (copyin(addr, (caddr_t)&flags, sizeof (flags))) {
345 u.u_error = EFAULT;
7344d489 346 return(1);
7d973a4d
KB
347 }
348 flushtty(tp, flags);
89dc6dfb 349 break;
4568c08e 350 }
89dc6dfb 351
89dc6dfb 352 /*
50e2732b 353 * Set and fetch special characters
89dc6dfb
BJ
354 */
355 case TIOCSETC:
8062c8a7 356 if (copyin(addr, (caddr_t)&tun, sizeof(struct tchars)))
89dc6dfb
BJ
357 u.u_error = EFAULT;
358 break;
359
360 case TIOCGETC:
8062c8a7
BJ
361 if (copyout((caddr_t)&tun, addr, sizeof(struct tchars)))
362 u.u_error = EFAULT;
363 break;
364
365/* local ioctls */
50e2732b
BJ
366 /*
367 * Set/get local special characters.
368 */
8062c8a7
BJ
369 case TIOCSLTC:
370 if (copyin(addr, (caddr_t)&tlun, sizeof (struct ltchars)))
371 u.u_error = EFAULT;
372 break;
373
374 case TIOCGLTC:
375 if (copyout((caddr_t)&tlun, addr, sizeof (struct ltchars)))
376 u.u_error = EFAULT;
377 break;
378
50e2732b
BJ
379 /*
380 * Return number of characters immediately available.
381 */
8062c8a7 382 case FIONREAD: {
e1d74936 383 off_t nread = ttnread(tp);
8062c8a7
BJ
384 if (copyout((caddr_t)&nread, addr, sizeof (off_t)))
385 u.u_error = EFAULT;
386 break;
387 }
388
389 /*
390 * Should allow SPGRP and GPGRP only if tty open for reading.
391 */
392 case TIOCSPGRP:
da1392b6
BJ
393 if (copyin(addr, (caddr_t)&tp->t_pgrp, sizeof (tp->t_pgrp)))
394 u.u_error = EFAULT;
8062c8a7
BJ
395 break;
396
397 case TIOCGPGRP:
398 if (copyout((caddr_t)&tp->t_pgrp, addr, sizeof(tp->t_pgrp)))
399 u.u_error = EFAULT;
400 break;
401
402 /*
403 * Modify local mode word.
404 */
405 case TIOCLBIS:
da1392b6
BJ
406 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
407 u.u_error = EFAULT;
408 else
409 tp->t_local |= temp;
8062c8a7
BJ
410 break;
411
412 case TIOCLBIC:
da1392b6
BJ
413 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
414 u.u_error = EFAULT;
415 else
416 tp->t_local &= ~temp;
8062c8a7
BJ
417 break;
418
419 case TIOCLSET:
da1392b6
BJ
420 if (copyin(addr, (caddr_t)&temp, sizeof (tp->t_local)))
421 u.u_error = EFAULT;
422 else
423 tp->t_local = temp;
8062c8a7
BJ
424 break;
425
426 case TIOCLGET:
427 if (copyout((caddr_t)&tp->t_local, addr, sizeof(tp->t_local)))
89dc6dfb
BJ
428 u.u_error = EFAULT;
429 break;
430
50e2732b
BJ
431 /*
432 * Return number of characters in
433 * the output.
434 */
0dde1c43
BJ
435 case TIOCOUTQ:
436 if (copyout((caddr_t)&tp->t_outq.c_cc, addr, sizeof(tp->t_outq.c_cc)))
437 u.u_error = EFAULT;
438 break;
439
50e2732b
BJ
440 /*
441 * Simulate typing of a character at the terminal.
442 */
50450a20
BJ
443 case TIOCSTI:
444 c = fubyte(addr);
445 if (u.u_uid && u.u_ttyp != tp || c < 0)
446 u.u_error = EFAULT;
447 else
448 (*linesw[tp->t_line].l_rint)(c, tp);
449 break;
8062c8a7 450/* end of locals */
50450a20 451
89dc6dfb
BJ
452 default:
453 return(0);
454 }
455 return(1);
456}
e1d74936
BJ
457
458ttnread(tp)
459 struct tty *tp;
460{
461 int nread = 0;
462
463 if (tp->t_local & LPENDIN)
464 ttypend(tp);
465 nread = tp->t_canq.c_cc;
466 if (tp->t_flags & (RAW|CBREAK))
467 nread += tp->t_rawq.c_cc;
468 return (nread);
469}
470
471ttselect(dev, flag)
472 dev_t dev;
473 int flag;
474{
475 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
476 int nread;
477
478 switch (flag) {
479
480 case FREAD:
481 nread = ttnread(tp);
482 if (nread > 0)
483 return (1);
89b8a44c 484 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
e1d74936
BJ
485 tp->t_state |= RCOLL;
486 else
487 tp->t_rsel = u.u_procp;
488 return (0);
489
490 default:
491 return (1);
492 }
493}