This source file includes following definitions.
- change_console
- sleep_if_empty
- sleep_if_full
- wait_for_keypress
- copy_to_cooked
- tty_signal
- tty_read
- tty_write
- chr_dev_init
- tty_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <ctype.h>
15 #include <errno.h>
16 #include <signal.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19
20 #define ALRMMASK (1<<(SIGALRM-1))
21
22 #include <linux/sched.h>
23 #include <linux/tty.h>
24 #include <asm/segment.h>
25 #include <asm/system.h>
26
27 int kill_pg(int pgrp, int sig, int priv);
28 int is_orphaned_pgrp(int pgrp);
29
30 extern void lp_init(void);
31
32 #define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
33 #define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
34 #define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
35
36 #define L_CANON(tty) _L_FLAG((tty),ICANON)
37 #define L_ISIG(tty) _L_FLAG((tty),ISIG)
38 #define L_ECHO(tty) _L_FLAG((tty),ECHO)
39 #define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
40 #define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
41 #define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
42 #define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
43 #define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
44 #define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
45
46 #define I_UCLC(tty) _I_FLAG((tty),IUCLC)
47 #define I_NLCR(tty) _I_FLAG((tty),INLCR)
48 #define I_CRNL(tty) _I_FLAG((tty),ICRNL)
49 #define I_NOCR(tty) _I_FLAG((tty),IGNCR)
50 #define I_IXON(tty) _I_FLAG((tty),IXON)
51 #define I_STRP(tty) _I_FLAG((tty),ISTRIP)
52
53 #define O_POST(tty) _O_FLAG((tty),OPOST)
54 #define O_NLCR(tty) _O_FLAG((tty),ONLCR)
55 #define O_CRNL(tty) _O_FLAG((tty),OCRNL)
56 #define O_NLRET(tty) _O_FLAG((tty),ONLRET)
57 #define O_LCUC(tty) _O_FLAG((tty),OLCUC)
58
59 #define C_SPEED(tty) ((tty)->termios.c_cflag & CBAUD)
60 #define C_HUP(tty) (C_SPEED((tty)) == B0)
61
62 #ifndef MIN
63 #define MIN(a,b) ((a) < (b) ? (a) : (b))
64 #endif
65
66 #define QUEUES (3*(MAX_CONSOLES+NR_SERIALS+2*NR_PTYS))
67 static struct tty_queue tty_queues[QUEUES];
68 struct tty_struct tty_table[256];
69
70 #define con_queues tty_queues
71 #define rs_queues ((3*MAX_CONSOLES) + tty_queues)
72 #define mpty_queues ((3*(MAX_CONSOLES+NR_SERIALS)) + tty_queues)
73 #define spty_queues ((3*(MAX_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)
74
75 #define con_table tty_table
76 #define rs_table (64+tty_table)
77 #define mpty_table (128+tty_table)
78 #define spty_table (192+tty_table)
79
80 int fg_console = 0;
81
82
83
84
85
86 struct tty_queue * table_list[]={
87 con_queues + 0, con_queues + 1,
88 rs_queues + 0, rs_queues + 1,
89 rs_queues + 3, rs_queues + 4,
90 rs_queues + 6, rs_queues + 7,
91 rs_queues + 9, rs_queues + 10
92 };
93
94 void change_console(unsigned int new_console)
95 {
96 if (new_console == fg_console || new_console >= NR_CONSOLES)
97 return;
98 table_list[0] = con_queues + 0 + new_console*3;
99 table_list[1] = con_queues + 1 + new_console*3;
100 update_screen(new_console);
101 }
102
103 static void sleep_if_empty(struct tty_queue * queue)
104 {
105 cli();
106 while (!(current->signal & ~current->blocked) && EMPTY(queue))
107 interruptible_sleep_on(&queue->proc_list);
108 sti();
109 }
110
111 static void sleep_if_full(struct tty_queue * queue)
112 {
113 if (!FULL(queue))
114 return;
115 cli();
116 while (!(current->signal & ~current->blocked) && LEFT(queue)<128)
117 interruptible_sleep_on(&queue->proc_list);
118 sti();
119 }
120
121 void wait_for_keypress(void)
122 {
123 sleep_if_empty(tty_table[fg_console].secondary);
124 }
125
126 void copy_to_cooked(struct tty_struct * tty)
127 {
128 unsigned char c;
129
130 if (!(tty && tty->write && tty->read_q &&
131 tty->write_q && tty->secondary)) {
132 printk("copy_to_cooked: missing queues\n\r");
133 return;
134 }
135 while (1) {
136 if (EMPTY(tty->read_q))
137 break;
138 if (FULL(tty->secondary)) {
139 if (tty->secondary->proc_list)
140 if (tty->secondary->proc_list != current)
141 current->counter = 0;
142 break;
143 }
144 GETCH(tty->read_q,c);
145 if (I_STRP(tty))
146 c &= 0x7f;
147 if (c==13) {
148 if (I_CRNL(tty))
149 c=10;
150 else if (I_NOCR(tty))
151 continue;
152 } else if (c==10 && I_NLCR(tty))
153 c=13;
154 if (I_UCLC(tty))
155 c=tolower(c);
156 if (L_CANON(tty)) {
157 if ((KILL_CHAR(tty) != _POSIX_VDISABLE) &&
158 (c==KILL_CHAR(tty))) {
159
160 while(!(EMPTY(tty->secondary) ||
161 (c=LAST(tty->secondary))==10 ||
162 ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
163 (c==EOF_CHAR(tty))))) {
164 if (L_ECHO(tty)) {
165 if (c<32)
166 PUTCH(127,tty->write_q);
167 PUTCH(127,tty->write_q);
168 TTY_WRITE_FLUSH(tty);
169 }
170 DEC(tty->secondary->head);
171 }
172 continue;
173 }
174 if ((ERASE_CHAR(tty) != _POSIX_VDISABLE) &&
175 (c==ERASE_CHAR(tty))) {
176 if (EMPTY(tty->secondary) ||
177 (c=LAST(tty->secondary))==10 ||
178 ((EOF_CHAR(tty) != _POSIX_VDISABLE) &&
179 (c==EOF_CHAR(tty))))
180 continue;
181 if (L_ECHO(tty)) {
182 if (c<32)
183 PUTCH(127,tty->write_q);
184 PUTCH(127,tty->write_q);
185 TTY_WRITE_FLUSH(tty);
186 }
187 DEC(tty->secondary->head);
188 continue;
189 }
190 }
191 if (I_IXON(tty)) {
192 if ((STOP_CHAR(tty) != _POSIX_VDISABLE) &&
193 (c==STOP_CHAR(tty))) {
194 tty->stopped=1;
195 continue;
196 }
197 if ((START_CHAR(tty) != _POSIX_VDISABLE) &&
198 (c==START_CHAR(tty))) {
199 tty->stopped=0;
200 TTY_WRITE_FLUSH(tty);
201 continue;
202 }
203 }
204 if (L_ISIG(tty)) {
205 if ((INTR_CHAR(tty) != _POSIX_VDISABLE) &&
206 (c==INTR_CHAR(tty))) {
207 kill_pg(tty->pgrp, SIGINT, 1);
208 continue;
209 }
210 if ((QUIT_CHAR(tty) != _POSIX_VDISABLE) &&
211 (c==QUIT_CHAR(tty))) {
212 kill_pg(tty->pgrp, SIGQUIT, 1);
213 continue;
214 }
215 if ((SUSPEND_CHAR(tty) != _POSIX_VDISABLE) &&
216 (c==SUSPEND_CHAR(tty))) {
217 if (!is_orphaned_pgrp(tty->pgrp))
218 kill_pg(tty->pgrp, SIGTSTP, 1);
219 continue;
220 }
221 }
222 if (c==10 || (EOF_CHAR(tty) != _POSIX_VDISABLE &&
223 c==EOF_CHAR(tty)))
224 tty->secondary->data++;
225 if ((L_ECHO(tty) || L_ECHONL(tty)) && (c==10)) {
226 PUTCH(10,tty->write_q);
227 PUTCH(13,tty->write_q);
228 } else if (L_ECHO(tty)) {
229 if (c<32 && L_ECHOCTL(tty)) {
230 PUTCH('^',tty->write_q);
231 PUTCH(c+64,tty->write_q);
232 } else
233 PUTCH(c,tty->write_q);
234 }
235 PUTCH(c,tty->secondary);
236 TTY_WRITE_FLUSH(tty);
237 }
238 TTY_WRITE_FLUSH(tty);
239 if (!EMPTY(tty->secondary))
240 wake_up(&tty->secondary->proc_list);
241 if (LEFT(tty->write_q) > TTY_BUF_SIZE/2)
242 wake_up(&tty->write_q->proc_list);
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 int tty_signal(int sig, struct tty_struct *tty)
261 {
262 if (is_orphaned_pgrp(current->pgrp))
263 return -EIO;
264 (void) kill_pg(current->pgrp,sig,1);
265 if ((current->blocked & (1<<(sig-1))) ||
266 ((int) current->sigaction[sig-1].sa_handler == 1))
267 return -EIO;
268 else if (current->sigaction[sig-1].sa_handler)
269 return -EINTR;
270 else
271 return -ERESTARTSYS;
272
273 }
274
275 int tty_read(unsigned channel, char * buf, int nr, unsigned short flags)
276 {
277 struct tty_struct * tty;
278 struct tty_struct * other_tty = NULL;
279 unsigned char c;
280 char * b=buf;
281 int minimum,time;
282
283 if (channel > 255)
284 return -EIO;
285 tty = TTY_TABLE(channel);
286 if (!(tty->read_q && tty->secondary))
287 return -EIO;
288 if ((tty->pgrp > 0) && (current->tty == channel) &&
289 (tty->pgrp != current->pgrp))
290 return(tty_signal(SIGTTIN, tty));
291 if (channel & 0x80)
292 other_tty = tty_table + (channel ^ 0x40);
293 time = 10L*tty->termios.c_cc[VTIME];
294 minimum = tty->termios.c_cc[VMIN];
295 if (L_CANON(tty)) {
296 minimum = nr;
297 current->timeout = 0xffffffff;
298 time = 0;
299 } else if (minimum)
300 current->timeout = 0xffffffff;
301 else {
302 minimum = nr;
303 if (time)
304 current->timeout = time + jiffies;
305 time = 0;
306 }
307 if (flags & O_NONBLOCK)
308 time = current->timeout = 0;
309 if (minimum>nr)
310 minimum = nr;
311 TTY_READ_FLUSH(tty);
312 while (nr>0) {
313 if (other_tty && other_tty->write)
314 TTY_WRITE_FLUSH(other_tty);
315 cli();
316 if (EMPTY(tty->secondary) || (L_CANON(tty) &&
317 !FULL(tty->read_q) && !tty->secondary->data)) {
318 if (!current->timeout)
319 break;
320 if (current->signal & ~current->blocked)
321 break;
322 if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))
323 break;
324 interruptible_sleep_on(&tty->secondary->proc_list);
325 sti();
326 TTY_READ_FLUSH(tty);
327 continue;
328 }
329 sti();
330 do {
331 GETCH(tty->secondary,c);
332 if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
333 c==EOF_CHAR(tty)) || c==10)
334 tty->secondary->data--;
335 if ((EOF_CHAR(tty) != _POSIX_VDISABLE &&
336 c==EOF_CHAR(tty)) && L_CANON(tty))
337 break;
338 else {
339 put_fs_byte(c,b++);
340 if (!--nr)
341 break;
342 }
343 if (c==10 && L_CANON(tty))
344 break;
345 } while (nr>0 && !EMPTY(tty->secondary));
346 wake_up(&tty->read_q->proc_list);
347 if (L_CANON(tty) || b-buf >= minimum)
348 break;
349 if (time)
350 current->timeout = time+jiffies;
351 }
352 sti();
353 current->timeout = 0;
354 if (b-buf)
355 return b-buf;
356 if (current->signal & ~current->blocked)
357 return -ERESTARTSYS;
358 if (flags & O_NONBLOCK)
359 return -EAGAIN;
360 return 0;
361 }
362
363 int tty_write(unsigned channel, char * buf, int nr)
364 {
365 static cr_flag=0;
366 struct tty_struct * tty;
367 char c, *b=buf;
368
369 if (channel > 255)
370 return -EIO;
371 tty = TTY_TABLE(channel);
372 if (!(tty->write_q && tty->write))
373 return -EIO;
374 if (L_TOSTOP(tty) && (tty->pgrp > 0) &&
375 (current->tty == channel) && (tty->pgrp != current->pgrp))
376 return(tty_signal(SIGTTOU, tty));
377 if (nr < 0)
378 return -EINVAL;
379 if (!nr)
380 return 0;
381 while (nr>0) {
382 sleep_if_full(tty->write_q);
383 if (current->signal & ~current->blocked)
384 break;
385 while (nr>0 && !FULL(tty->write_q)) {
386 c=get_fs_byte(b);
387 if (O_POST(tty)) {
388 if (c=='\r' && O_CRNL(tty))
389 c='\n';
390 else if (c=='\n' && O_NLRET(tty))
391 c='\r';
392 if (c=='\n' && !cr_flag && O_NLCR(tty)) {
393 cr_flag = 1;
394 PUTCH(13,tty->write_q);
395 continue;
396 }
397 if (O_LCUC(tty))
398 c=toupper(c);
399 }
400 b++; nr--;
401 cr_flag = 0;
402 PUTCH(c,tty->write_q);
403 }
404 TTY_WRITE_FLUSH(tty);
405 if (nr>0)
406 schedule();
407 }
408 if (b-buf)
409 return b-buf;
410 if (current->signal & ~current->blocked)
411 return -ERESTARTSYS;
412 return 0;
413 }
414
415 void chr_dev_init(void)
416 {
417 }
418
419 void tty_init(void)
420 {
421 int i;
422
423 for (i=0 ; i < QUEUES ; i++)
424 tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
425 rs_queues[0] = (struct tty_queue) {0x3f8,0,0,0,""};
426 rs_queues[1] = (struct tty_queue) {0x3f8,0,0,0,""};
427 rs_queues[3] = (struct tty_queue) {0x2f8,0,0,0,""};
428 rs_queues[4] = (struct tty_queue) {0x2f8,0,0,0,""};
429 rs_queues[6] = (struct tty_queue) {0x3e8,0,0,0,""};
430 rs_queues[7] = (struct tty_queue) {0x3e8,0,0,0,""};
431 rs_queues[9] = (struct tty_queue) {0x2e8,0,0,0,""};
432 rs_queues[10] = (struct tty_queue) {0x2e8,0,0,0,""};
433 for (i=0 ; i<256 ; i++) {
434 tty_table[i] = (struct tty_struct) {
435 {0, 0, 0, 0, 0, INIT_C_CC},
436 -1, 0, 0, 0, {0,0,0,0},
437 NULL, NULL, NULL, NULL
438 };
439 }
440 con_init();
441 for (i = 0 ; i<NR_CONSOLES ; i++) {
442 con_table[i] = (struct tty_struct) {
443 {ICRNL,
444 OPOST|ONLCR,
445 B38400 | CS8,
446 IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
447 0,
448 INIT_C_CC},
449 -1,
450 0,
451 0,
452 0,
453 {video_num_lines,video_num_columns,0,0},
454 con_write,
455 con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
456 };
457 }
458 for (i = 0 ; i<NR_SERIALS ; i++) {
459 rs_table[i] = (struct tty_struct) {
460 {0,
461 0,
462 B2400 | CS8,
463 0,
464 0,
465 INIT_C_CC},
466 -1,
467 0,
468 0,
469 0,
470 {25,80,0,0},
471 rs_write,
472 rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
473 };
474 }
475 for (i = 0 ; i<NR_PTYS ; i++) {
476 mpty_table[i] = (struct tty_struct) {
477 {0,
478 0,
479 B9600 | CS8,
480 0,
481 0,
482 INIT_C_CC},
483 -1,
484 0,
485 0,
486 0,
487 {25,80,0,0},
488 mpty_write,
489 mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
490 };
491 spty_table[i] = (struct tty_struct) {
492 {0,
493 0,
494 B9600 | CS8,
495 IXON | ISIG | ICANON,
496 0,
497 INIT_C_CC},
498 -1,
499 0,
500 0,
501 0,
502 {25,80,0,0},
503 spty_write,
504 spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
505 };
506 }
507 rs_init();
508 printk("%d virtual consoles\n\r",NR_CONSOLES);
509 printk("%d pty's\n\r",NR_PTYS);
510 lp_init();
511 }