11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) 31da177e4SLinus Torvalds * Licensed under the GPL 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds #include "linux/config.h" 71da177e4SLinus Torvalds #include "linux/posix_types.h" 81da177e4SLinus Torvalds #include "linux/tty.h" 91da177e4SLinus Torvalds #include "linux/tty_flip.h" 101da177e4SLinus Torvalds #include "linux/types.h" 111da177e4SLinus Torvalds #include "linux/major.h" 121da177e4SLinus Torvalds #include "linux/kdev_t.h" 131da177e4SLinus Torvalds #include "linux/console.h" 141da177e4SLinus Torvalds #include "linux/string.h" 151da177e4SLinus Torvalds #include "linux/sched.h" 161da177e4SLinus Torvalds #include "linux/list.h" 171da177e4SLinus Torvalds #include "linux/init.h" 181da177e4SLinus Torvalds #include "linux/interrupt.h" 191da177e4SLinus Torvalds #include "linux/slab.h" 201da177e4SLinus Torvalds #include "linux/hardirq.h" 211da177e4SLinus Torvalds #include "asm/current.h" 221da177e4SLinus Torvalds #include "asm/irq.h" 231da177e4SLinus Torvalds #include "stdio_console.h" 241da177e4SLinus Torvalds #include "line.h" 251da177e4SLinus Torvalds #include "chan_kern.h" 261da177e4SLinus Torvalds #include "user_util.h" 271da177e4SLinus Torvalds #include "kern_util.h" 281da177e4SLinus Torvalds #include "irq_user.h" 291da177e4SLinus Torvalds #include "mconsole_kern.h" 301da177e4SLinus Torvalds #include "init.h" 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds #define MAX_TTYS (16) 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* ----------------------------------------------------------------------------- */ 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds /* Referenced only by tty_driver below - presumably it's locked correctly 371da177e4SLinus Torvalds * by the tty driver. 381da177e4SLinus Torvalds */ 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds static struct tty_driver *console_driver; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds void stdio_announce(char *dev_name, int dev) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, 451da177e4SLinus Torvalds dev_name); 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds static struct chan_opts opts = { 491da177e4SLinus Torvalds .announce = stdio_announce, 501da177e4SLinus Torvalds .xterm_title = "Virtual Console #%d", 511da177e4SLinus Torvalds .raw = 1, 521da177e4SLinus Torvalds .tramp_stack = 0, 531da177e4SLinus Torvalds .in_kernel = 1, 541da177e4SLinus Torvalds }; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds static int con_config(char *str); 571da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out); 5829d56cfeSJeff Dike static int con_remove(int n); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds static struct line_driver driver = { 611da177e4SLinus Torvalds .name = "UML console", 621da177e4SLinus Torvalds .device_name = "tty", 631da177e4SLinus Torvalds .devfs_name = "vc/", 641da177e4SLinus Torvalds .major = TTY_MAJOR, 651da177e4SLinus Torvalds .minor_start = 0, 661da177e4SLinus Torvalds .type = TTY_DRIVER_TYPE_CONSOLE, 671da177e4SLinus Torvalds .subtype = SYSTEM_TYPE_CONSOLE, 681da177e4SLinus Torvalds .read_irq = CONSOLE_IRQ, 691da177e4SLinus Torvalds .read_irq_name = "console", 701da177e4SLinus Torvalds .write_irq = CONSOLE_WRITE_IRQ, 711da177e4SLinus Torvalds .write_irq_name = "console-write", 721da177e4SLinus Torvalds .symlink_from = "ttys", 731da177e4SLinus Torvalds .symlink_to = "vc", 741da177e4SLinus Torvalds .mc = { 751da177e4SLinus Torvalds .name = "con", 761da177e4SLinus Torvalds .config = con_config, 771da177e4SLinus Torvalds .get_config = con_get_config, 7829d56cfeSJeff Dike .id = line_id, 791da177e4SLinus Torvalds .remove = con_remove, 801da177e4SLinus Torvalds }, 811da177e4SLinus Torvalds }; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds static struct lines console_lines = LINES_INIT(MAX_TTYS); 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* The array is initialized by line_init, which is an initcall. The 861da177e4SLinus Torvalds * individual elements are protected by individual semaphores. 871da177e4SLinus Torvalds */ 881da177e4SLinus Torvalds struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), 891da177e4SLinus Torvalds [ 1 ... MAX_TTYS - 1 ] = 901da177e4SLinus Torvalds LINE_INIT(CONFIG_CON_CHAN, &driver) }; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static int con_config(char *str) 931da177e4SLinus Torvalds { 94*d50084a2SJeff Dike return line_config(vts, sizeof(vts)/sizeof(vts[0]), str); 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out) 981da177e4SLinus Torvalds { 99*d50084a2SJeff Dike return line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str, 100*d50084a2SJeff Dike size, error_out); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 10329d56cfeSJeff Dike static int con_remove(int n) 1041da177e4SLinus Torvalds { 10529d56cfeSJeff Dike return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds static int con_open(struct tty_struct *tty, struct file *filp) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds return line_open(vts, tty, &opts); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static int con_init_done = 0; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds static struct tty_operations console_ops = { 1161da177e4SLinus Torvalds .open = con_open, 1171da177e4SLinus Torvalds .close = line_close, 1181da177e4SLinus Torvalds .write = line_write, 119b97b77ccSPaolo 'Blaisorblade' Giarrusso .put_char = line_put_char, 1201da177e4SLinus Torvalds .write_room = line_write_room, 1211da177e4SLinus Torvalds .chars_in_buffer = line_chars_in_buffer, 122b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_buffer = line_flush_buffer, 123b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_chars = line_flush_chars, 1241da177e4SLinus Torvalds .set_termios = line_set_termios, 1251da177e4SLinus Torvalds .ioctl = line_ioctl, 1261da177e4SLinus Torvalds }; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds static void uml_console_write(struct console *console, const char *string, 1291da177e4SLinus Torvalds unsigned len) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds struct line *line = &vts[console->index]; 132b97b77ccSPaolo 'Blaisorblade' Giarrusso unsigned long flags; 1331da177e4SLinus Torvalds 134b97b77ccSPaolo 'Blaisorblade' Giarrusso spin_lock_irqsave(&line->lock, flags); 1351da177e4SLinus Torvalds console_write_chan(&line->chan_list, string, len); 136b97b77ccSPaolo 'Blaisorblade' Giarrusso spin_unlock_irqrestore(&line->lock, flags); 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds static struct tty_driver *uml_console_device(struct console *c, int *index) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds *index = c->index; 1421da177e4SLinus Torvalds return console_driver; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds static int uml_console_setup(struct console *co, char *options) 1461da177e4SLinus Torvalds { 1471da177e4SLinus Torvalds struct line *line = &vts[co->index]; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds return console_open_chan(line, co, &opts); 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds static struct console stdiocons = { 1531da177e4SLinus Torvalds .name = "tty", 1541da177e4SLinus Torvalds .write = uml_console_write, 1551da177e4SLinus Torvalds .device = uml_console_device, 1561da177e4SLinus Torvalds .setup = uml_console_setup, 1571da177e4SLinus Torvalds .flags = CON_PRINTBUFFER, 1581da177e4SLinus Torvalds .index = -1, 1591da177e4SLinus Torvalds .data = &vts, 1601da177e4SLinus Torvalds }; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds int stdio_init(void) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds char *new_title; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds console_driver = line_register_devfs(&console_lines, &driver, 1671da177e4SLinus Torvalds &console_ops, vts, 1681da177e4SLinus Torvalds ARRAY_SIZE(vts)); 169*d50084a2SJeff Dike if (console_driver == NULL) 1701da177e4SLinus Torvalds return -1; 1711da177e4SLinus Torvalds printk(KERN_INFO "Initialized stdio console driver\n"); 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds lines_init(vts, sizeof(vts)/sizeof(vts[0])); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds new_title = add_xterm_umid(opts.xterm_title); 1761da177e4SLinus Torvalds if(new_title != NULL) 1771da177e4SLinus Torvalds opts.xterm_title = new_title; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds con_init_done = 1; 1801da177e4SLinus Torvalds register_console(&stdiocons); 181*d50084a2SJeff Dike return 0; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds late_initcall(stdio_init); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static void console_exit(void) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds if (!con_init_done) 1881da177e4SLinus Torvalds return; 1891da177e4SLinus Torvalds close_lines(vts, sizeof(vts)/sizeof(vts[0])); 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds __uml_exitcall(console_exit); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds static int console_chan_setup(char *str) 1941da177e4SLinus Torvalds { 195*d50084a2SJeff Dike return line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds __setup("con", console_chan_setup); 1981da177e4SLinus Torvalds __channel_help(console_chan_setup, "con"); 199