This source file includes following definitions.
- put_tty_queue
- get_tty_queue
- tty_write_flush
- tty_read_flush
- change_console
- sleep_if_empty
- wait_for_keypress
- copy_to_cooked
- is_ignored
- tty_signal
- wait_for_canon_input
- read_chan
- write_chan
- tty_read
- tty_write
- tty_lseek
- tty_open
- tty_release
- tty_select
- tty_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <linux/types.h>
15 #include <linux/errno.h>
16 #include <linux/signal.h>
17 #include <linux/fcntl.h>
18 #include <linux/sched.h>
19 #include <linux/tty.h>
20 #include <linux/ctype.h>
21
22 #include <asm/io.h>
23 #include <asm/segment.h>
24 #include <asm/system.h>
25
26 #include <sys/kd.h>
27 #include "vt_kern.h"
28
29 #define QUEUES (3*(NR_CONSOLES+NR_SERIALS+2*NR_PTYS))
30 static struct tty_queue * tty_queues;
31 struct tty_struct tty_table[256];
32
33 #define con_queues tty_queues
34 #define rs_queues ((3*NR_CONSOLES) + tty_queues)
35 #define mpty_queues ((3*(NR_CONSOLES+NR_SERIALS)) + tty_queues)
36 #define spty_queues ((3*(NR_CONSOLES+NR_SERIALS+NR_PTYS)) + tty_queues)
37
38 #define con_table tty_table
39 #define rs_table (64+tty_table)
40 #define mpty_table (128+tty_table)
41 #define spty_table (192+tty_table)
42
43
44
45
46
47
48 int fg_console = 0;
49 struct tty_struct * redirect = NULL;
50
51
52
53
54
55 struct tty_queue * table_list[] = { NULL, NULL };
56
57 void inline put_tty_queue(char c, struct tty_queue * queue)
58 {
59 int head;
60 unsigned long flags;
61
62 __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
63 head = (queue->head + 1) & (TTY_BUF_SIZE-1);
64 if (head != queue->tail) {
65 queue->buf[queue->head] = c;
66 queue->head = head;
67 }
68 __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
69 }
70
71 int inline get_tty_queue(struct tty_queue * queue)
72 {
73 int result = -1;
74 unsigned long flags;
75
76 __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
77 if (queue->tail != queue->head) {
78 result = 0xff & queue->buf[queue->tail];
79 queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
80 }
81 __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
82 return result;
83 }
84
85 void inline tty_write_flush(struct tty_struct * tty)
86 {
87 if (EMPTY(tty->write_q))
88 return;
89 if (set_bit(TTY_WRITE_BUSY,&tty->flags))
90 return;
91 tty->write(tty);
92 if (clear_bit(TTY_WRITE_BUSY,&tty->flags))
93 printk("tty_write_flush: bit already cleared\n");
94 }
95
96 void tty_read_flush(struct tty_struct * tty)
97 {
98 if (EMPTY(tty->read_q))
99 return;
100 if (set_bit(TTY_READ_BUSY, &tty->flags))
101 return;
102 copy_to_cooked(tty);
103 if (clear_bit(TTY_READ_BUSY, &tty->flags))
104 printk("tty_read_flush: bit already cleared\n");
105 }
106
107 void change_console(unsigned int new_console)
108 {
109 if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
110 return;
111 if (new_console == fg_console || new_console >= NR_CONSOLES)
112 return;
113 table_list[0] = con_queues + 0 + new_console*3;
114 table_list[1] = con_queues + 1 + new_console*3;
115 update_screen(new_console);
116 }
117
118 static void sleep_if_empty(struct tty_queue * queue)
119 {
120 cli();
121 while (!(current->signal & ~current->blocked) && EMPTY(queue))
122 interruptible_sleep_on(&queue->proc_list);
123 sti();
124 }
125
126 void wait_for_keypress(void)
127 {
128 sleep_if_empty(tty_table[fg_console].secondary);
129 flush_input(&tty_table[fg_console]);
130 }
131
132 void copy_to_cooked(struct tty_struct * tty)
133 {
134 int c;
135
136 if (!(tty && tty->write && tty->read_q &&
137 tty->write_q && tty->secondary)) {
138 printk("copy_to_cooked: missing queues\n\r");
139 return;
140 }
141 while (1) {
142 if (FULL(tty->secondary))
143 break;
144 c = get_tty_queue(tty->read_q);
145 if (c < 0)
146 break;
147 if (I_STRP(tty))
148 c &= 0x7f;
149 if (c==13) {
150 if (I_CRNL(tty))
151 c=10;
152 else if (I_NOCR(tty))
153 continue;
154 } else if (c==10 && I_NLCR(tty))
155 c=13;
156 if (I_UCLC(tty))
157 c=tolower(c);
158 if (L_CANON(tty)) {
159 if ((KILL_CHAR(tty) != __DISABLED_CHAR) &&
160 (c==KILL_CHAR(tty))) {
161
162 while(!(EMPTY(tty->secondary) ||
163 (c=LAST(tty->secondary))==10 ||
164 ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
165 (c==EOF_CHAR(tty))))) {
166 if (L_ECHO(tty)) {
167 if (c<32) {
168 put_tty_queue(8,tty->write_q);
169 put_tty_queue(' ',tty->write_q);
170 put_tty_queue(8,tty->write_q);
171 }
172 put_tty_queue(8,tty->write_q);
173 put_tty_queue(' ',tty->write_q);
174 put_tty_queue(8,tty->write_q);
175 }
176 DEC(tty->secondary->head);
177 }
178 continue;
179 }
180 if ((ERASE_CHAR(tty) != __DISABLED_CHAR) &&
181 (c==ERASE_CHAR(tty))) {
182 if (EMPTY(tty->secondary) ||
183 (c=LAST(tty->secondary))==10 ||
184 ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
185 (c==EOF_CHAR(tty))))
186 continue;
187 if (L_ECHO(tty)) {
188 if (c<32) {
189 put_tty_queue(8,tty->write_q);
190 put_tty_queue(' ',tty->write_q);
191 put_tty_queue(8,tty->write_q);
192 }
193 put_tty_queue(8,tty->write_q);
194 put_tty_queue(32,tty->write_q);
195 put_tty_queue(8,tty->write_q);
196 }
197 DEC(tty->secondary->head);
198 continue;
199 }
200 }
201 if (I_IXON(tty)) {
202 if ((STOP_CHAR(tty) != __DISABLED_CHAR) &&
203 (c==STOP_CHAR(tty))) {
204 tty->stopped=1;
205 continue;
206 }
207 if ((START_CHAR(tty) != __DISABLED_CHAR) &&
208 (c==START_CHAR(tty))) {
209 tty->stopped=0;
210 continue;
211 }
212 }
213 if (L_ISIG(tty)) {
214 if ((INTR_CHAR(tty) != __DISABLED_CHAR) &&
215 (c==INTR_CHAR(tty))) {
216 kill_pg(tty->pgrp, SIGINT, 1);
217 flush_input(tty);
218 continue;
219 }
220 if ((QUIT_CHAR(tty) != __DISABLED_CHAR) &&
221 (c==QUIT_CHAR(tty))) {
222 kill_pg(tty->pgrp, SIGQUIT, 1);
223 flush_input(tty);
224 continue;
225 }
226 if ((SUSPEND_CHAR(tty) != __DISABLED_CHAR) &&
227 (c==SUSPEND_CHAR(tty))) {
228 if (!is_orphaned_pgrp(tty->pgrp))
229 kill_pg(tty->pgrp, SIGTSTP, 1);
230 continue;
231 }
232 }
233 if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR &&
234 c==EOF_CHAR(tty)))
235 tty->secondary->data++;
236 if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) {
237 put_tty_queue(10,tty->write_q);
238 put_tty_queue(13,tty->write_q);
239 } else if (L_ECHO(tty)) {
240 if (c<32 && L_ECHOCTL(tty)) {
241 put_tty_queue('^',tty->write_q);
242 put_tty_queue(c+64,tty->write_q);
243 } else
244 put_tty_queue(c,tty->write_q);
245 }
246 put_tty_queue(c,tty->secondary);
247 }
248 TTY_WRITE_FLUSH(tty);
249 if (!EMPTY(tty->secondary))
250 wake_up(&tty->secondary->proc_list);
251 if (tty->write_q->proc_list && LEFT(tty->write_q) > TTY_BUF_SIZE/2)
252 wake_up(&tty->write_q->proc_list);
253 }
254
255 int is_ignored(int sig)
256 {
257 return ((current->blocked & (1<<(sig-1))) ||
258 (current->sigaction[sig-1].sa_handler == SIG_IGN));
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276 int tty_signal(int sig, struct tty_struct *tty)
277 {
278 (void) kill_pg(current->pgrp,sig,1);
279 return -ERESTARTSYS;
280 }
281
282 static void wait_for_canon_input(struct tty_struct * tty)
283 {
284 while (1) {
285 TTY_READ_FLUSH(tty);
286 if (tty->link)
287 if (tty->link->count)
288 TTY_WRITE_FLUSH(tty->link);
289 else
290 return;
291 if (current->signal & ~current->blocked)
292 return;
293 if (FULL(tty->read_q))
294 return;
295 if (tty->secondary->data)
296 return;
297 cli();
298 if (!tty->secondary->data)
299 interruptible_sleep_on(&tty->secondary->proc_list);
300 sti();
301 }
302 }
303
304 static int read_chan(unsigned int channel, struct file * file, char * buf, int nr)
305 {
306 struct tty_struct * tty;
307 int c;
308 char * b=buf;
309 int minimum,time;
310
311 if (channel > 255)
312 return -EIO;
313 tty = TTY_TABLE(channel);
314 if (!(tty->read_q && tty->secondary))
315 return -EIO;
316 if ((tty->pgrp > 0) &&
317 (current->tty == channel) &&
318 (tty->pgrp != current->pgrp))
319 if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
320 return -EIO;
321 else
322 return(tty_signal(SIGTTIN, tty));
323 if (L_CANON(tty))
324 minimum = time = current->timeout = 0;
325 else {
326 time = 10L*tty->termios.c_cc[VTIME];
327 minimum = tty->termios.c_cc[VMIN];
328 if (minimum)
329 current->timeout = 0xffffffff;
330 else {
331 if (time)
332 current->timeout = time + jiffies;
333 else
334 current->timeout = 0;
335 time = 0;
336 minimum = 1;
337 }
338 }
339 if (file->f_flags & O_NONBLOCK)
340 time = current->timeout = 0;
341 else if (L_CANON(tty))
342 wait_for_canon_input(tty);
343 if (minimum>nr)
344 minimum = nr;
345 while (nr>0) {
346 TTY_READ_FLUSH(tty);
347 if (tty->link)
348 TTY_WRITE_FLUSH(tty->link);
349 while (nr > 0 && ((c = get_tty_queue(tty->secondary)) >= 0)) {
350 if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
351 c==EOF_CHAR(tty)) || c==10)
352 tty->secondary->data--;
353 if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
354 c==EOF_CHAR(tty)) && L_CANON(tty))
355 break;
356 put_fs_byte(c,b++);
357 nr--;
358 if (time)
359 current->timeout = time+jiffies;
360 if (c==10 && L_CANON(tty))
361 break;
362 };
363 wake_up(&tty->read_q->proc_list);
364 if (b-buf >= minimum || !current->timeout)
365 break;
366 if (current->signal & ~current->blocked)
367 break;
368 if (tty->link && !tty->link->count)
369 break;
370 TTY_READ_FLUSH(tty);
371 if (tty->link)
372 TTY_WRITE_FLUSH(tty->link);
373 cli();
374 if (EMPTY(tty->secondary))
375 interruptible_sleep_on(&tty->secondary->proc_list);
376 sti();
377 }
378 TTY_READ_FLUSH(tty);
379 if (tty->link && tty->link->write)
380 TTY_WRITE_FLUSH(tty->link);
381 current->timeout = 0;
382 if (b-buf)
383 return b-buf;
384 if (current->signal & ~current->blocked)
385 return -ERESTARTSYS;
386 if (file->f_flags & O_NONBLOCK)
387 return -EAGAIN;
388 return 0;
389 }
390
391 static int write_chan(unsigned int channel, struct file * file, char * buf, int nr)
392 {
393 struct tty_struct * tty;
394 char c, *b=buf;
395
396 if (channel > 255)
397 return -EIO;
398 tty = TTY_TABLE(channel);
399 if (L_TOSTOP(tty) && (tty->pgrp > 0) &&
400 (current->tty == channel) && (tty->pgrp != current->pgrp)) {
401 if (is_orphaned_pgrp(tty->pgrp))
402 return -EIO;
403 if (!is_ignored(SIGTTOU))
404 return tty_signal(SIGTTOU, tty);
405 }
406 if (nr < 0)
407 return -EINVAL;
408 if (!nr)
409 return 0;
410 if (redirect && tty == TTY_TABLE(0))
411 tty = redirect;
412 if (!(tty->write_q && tty->write))
413 return -EIO;
414 while (nr>0) {
415 if (current->signal & ~current->blocked)
416 break;
417 if (tty->link && !tty->link->count) {
418 send_sig(SIGPIPE,current,0);
419 break;
420 }
421 if (FULL(tty->write_q)) {
422 TTY_WRITE_FLUSH(tty);
423 cli();
424 if (FULL(tty->write_q))
425 interruptible_sleep_on(&tty->write_q->proc_list);
426 sti();
427 continue;
428 }
429 while (nr>0 && !FULL(tty->write_q)) {
430 c=get_fs_byte(b);
431 if (O_POST(tty)) {
432 if (c=='\r' && O_CRNL(tty))
433 c='\n';
434 else if (c=='\n' && O_NLRET(tty))
435 c='\r';
436 if (c=='\n' && O_NLCR(tty) &&
437 !set_bit(TTY_CR_PENDING,&tty->flags)) {
438 put_tty_queue(13,tty->write_q);
439 continue;
440 }
441 if (O_LCUC(tty))
442 c=toupper(c);
443 }
444 b++; nr--;
445 clear_bit(TTY_CR_PENDING,&tty->flags);
446 put_tty_queue(c,tty->write_q);
447 }
448 if (nr>0)
449 schedule();
450 }
451 TTY_WRITE_FLUSH(tty);
452 if (b-buf)
453 return b-buf;
454 if (tty->link && !tty->link->count)
455 return -EPIPE;
456 if (current->signal & ~current->blocked)
457 return -ERESTARTSYS;
458 return 0;
459 }
460
461 static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
462 {
463 int i;
464
465 if (MAJOR(file->f_rdev) != 4) {
466 printk("tty_read: pseudo-major != 4\n");
467 return -EINVAL;
468 }
469 i = read_chan(MINOR(file->f_rdev),file,buf,count);
470 if (i > 0)
471 inode->i_atime = CURRENT_TIME;
472 return i;
473 }
474
475 static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
476 {
477 int i;
478
479 if (MAJOR(file->f_rdev) != 4) {
480 printk("tty_write: pseudo-major != 4\n");
481 return -EINVAL;
482 }
483 i = write_chan(MINOR(file->f_rdev),file,buf,count);
484 if (i > 0)
485 inode->i_mtime = CURRENT_TIME;
486 return i;
487 }
488
489 static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
490 {
491 return -EBADF;
492 }
493
494
495
496
497
498
499
500
501
502 static int tty_open(struct inode * inode, struct file * filp)
503 {
504 struct tty_struct *tty;
505 int dev, retval;
506
507 dev = inode->i_rdev;
508 if (MAJOR(dev) == 5)
509 dev = current->tty;
510 else
511 dev = MINOR(dev);
512 if (dev < 0)
513 return -ENODEV;
514 filp->f_rdev = 0x0400 | dev;
515 tty = TTY_TABLE(dev);
516 if (!tty->count && !(tty->link && tty->link->count)) {
517 flush_input(tty);
518 flush_output(tty);
519 tty->stopped = 0;
520 }
521 if (IS_A_PTY_MASTER(dev)) {
522 if (tty->count)
523 return -EAGAIN;
524 if (tty->link)
525 tty->link->count++;
526 }
527 tty->count++;
528 retval = 0;
529 if (!(filp->f_flags & O_NOCTTY) &&
530 current->leader &&
531 current->tty<0 &&
532 tty->session==0) {
533 current->tty = dev;
534 tty->session = current->session;
535 tty->pgrp = current->pgrp;
536 }
537 if (IS_A_SERIAL(dev) && tty->count < 2)
538 retval = serial_open(dev-64,filp);
539 else if (IS_A_PTY(dev))
540 retval = pty_open(dev,filp);
541 if (retval) {
542 tty->count--;
543 if (IS_A_PTY_MASTER(dev) && tty->link)
544 tty->link->count--;
545 }
546 return retval;
547 }
548
549
550
551
552
553
554 static void tty_release(struct inode * inode, struct file * filp)
555 {
556 int dev;
557 struct tty_struct * tty;
558
559 dev = filp->f_rdev;
560 if (MAJOR(dev) != 4) {
561 printk("tty_close: tty pseudo-major != 4\n");
562 return;
563 }
564 dev = MINOR(filp->f_rdev);
565 tty = TTY_TABLE(dev);
566 if (IS_A_PTY_MASTER(dev) && tty->link)
567 tty->link->count--;
568 tty->count--;
569 if (tty->count)
570 return;
571 if (IS_A_SERIAL(dev)) {
572 wait_until_sent(tty);
573 serial_close(dev-64,filp);
574 } else if (IS_A_PTY(dev))
575 pty_close(dev,filp);
576 if (!tty->count && (tty == redirect))
577 redirect = NULL;
578 if (tty = tty->link)
579 if (!tty->count && (tty == redirect))
580 redirect = NULL;
581 }
582
583 static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
584 {
585 int dev;
586 struct tty_struct * tty;
587
588 dev = filp->f_rdev;
589 if (MAJOR(dev) != 4) {
590 printk("tty_select: tty pseudo-major != 4\n");
591 return 0;
592 }
593 dev = MINOR(filp->f_rdev);
594 tty = TTY_TABLE(dev);
595 switch (sel_type) {
596 case SEL_IN:
597 if (!EMPTY(tty->secondary))
598 return 1;
599 if (tty->link && !tty->link->count)
600 return 1;
601 select_wait(&tty->secondary->proc_list, wait);
602 return 0;
603 case SEL_OUT:
604 if (!FULL(tty->write_q))
605 return 1;
606 select_wait(&tty->write_q->proc_list, wait);
607 return 0;
608 case SEL_EX:
609 if (tty->link && !tty->link->count)
610 return 1;
611 return 0;
612 }
613 return 0;
614 }
615
616 static struct file_operations tty_fops = {
617 tty_lseek,
618 tty_read,
619 tty_write,
620 NULL,
621 tty_select,
622 tty_ioctl,
623 tty_open,
624 tty_release
625 };
626
627 long tty_init(long kmem_start)
628 {
629 int i;
630
631 tty_queues = (struct tty_queue *) kmem_start;
632 kmem_start += QUEUES * (sizeof (struct tty_queue));
633 table_list[0] = con_queues + 0;
634 table_list[1] = con_queues + 1;
635 chrdev_fops[4] = &tty_fops;
636 chrdev_fops[5] = &tty_fops;
637 for (i=0 ; i < QUEUES ; i++)
638 tty_queues[i] = (struct tty_queue) {0,0,0,0,""};
639 for (i=0 ; i<256 ; i++) {
640 tty_table[i] = (struct tty_struct) {
641 {0, 0, 0, 0, 0, INIT_C_CC},
642 -1, 0, 0, 0, 0, {0,0,0,0},
643 NULL, NULL, NULL, NULL, NULL
644 };
645 }
646 kmem_start = con_init(kmem_start);
647 for (i = 0 ; i<NR_CONSOLES ; i++) {
648 con_table[i] = (struct tty_struct) {
649 {ICRNL,
650 OPOST|ONLCR,
651 B38400 | CS8,
652 IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
653 0,
654 INIT_C_CC},
655 -1,
656 0,
657 0,
658 0,
659 0,
660 {video_num_lines,video_num_columns,0,0},
661 con_write,
662 NULL,
663 con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
664 };
665 }
666 for (i = 0 ; i<NR_SERIALS ; i++) {
667 rs_table[i] = (struct tty_struct) {
668 {0,
669 0,
670 B2400 | CS8,
671 0,
672 0,
673 INIT_C_CC},
674 -1,
675 0,
676 0,
677 0,
678 0,
679 {25,80,0,0},
680 rs_write,
681 NULL,
682 rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
683 };
684 }
685 for (i = 0 ; i<NR_PTYS ; i++) {
686 mpty_table[i] = (struct tty_struct) {
687 {0,
688 0,
689 B9600 | CS8,
690 0,
691 0,
692 INIT_C_CC},
693 -1,
694 0,
695 0,
696 0,
697 0,
698 {25,80,0,0},
699 mpty_write,
700 spty_table+i,
701 mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
702 };
703 spty_table[i] = (struct tty_struct) {
704 {0,
705 0,
706 B9600 | CS8,
707 IXON | ISIG | ICANON,
708 0,
709 INIT_C_CC},
710 -1,
711 0,
712 0,
713 0,
714 0,
715 {25,80,0,0},
716 spty_write,
717 mpty_table+i,
718 spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
719 };
720 }
721 kmem_start = rs_init(kmem_start);
722 printk("%d virtual consoles\n\r",NR_CONSOLES);
723 printk("%d pty's\n\r",NR_PTYS);
724 return kmem_start;
725 }