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