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