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