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