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*1f80171eSJeff Dike return line_config(vts, ARRAY_SIZE(vts), str, &opts); 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out) 981da177e4SLinus Torvalds { 990834cc77SJeff Dike return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 10229d56cfeSJeff Dike static int con_remove(int n) 1031da177e4SLinus Torvalds { 1040834cc77SJeff Dike return line_remove(vts, ARRAY_SIZE(vts), n); 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds static int con_open(struct tty_struct *tty, struct file *filp) 1081da177e4SLinus Torvalds { 109*1f80171eSJeff Dike return line_open(vts, tty); 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds static int con_init_done = 0; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds static struct tty_operations console_ops = { 1151da177e4SLinus Torvalds .open = con_open, 1161da177e4SLinus Torvalds .close = line_close, 1171da177e4SLinus Torvalds .write = line_write, 118b97b77ccSPaolo 'Blaisorblade' Giarrusso .put_char = line_put_char, 1191da177e4SLinus Torvalds .write_room = line_write_room, 1201da177e4SLinus Torvalds .chars_in_buffer = line_chars_in_buffer, 121b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_buffer = line_flush_buffer, 122b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_chars = line_flush_chars, 1231da177e4SLinus Torvalds .set_termios = line_set_termios, 1241da177e4SLinus Torvalds .ioctl = line_ioctl, 1251da177e4SLinus Torvalds }; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static void uml_console_write(struct console *console, const char *string, 1281da177e4SLinus Torvalds unsigned len) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds struct line *line = &vts[console->index]; 131b97b77ccSPaolo 'Blaisorblade' Giarrusso unsigned long flags; 1321da177e4SLinus Torvalds 133b97b77ccSPaolo 'Blaisorblade' Giarrusso spin_lock_irqsave(&line->lock, flags); 1341da177e4SLinus Torvalds console_write_chan(&line->chan_list, string, len); 135b97b77ccSPaolo 'Blaisorblade' Giarrusso spin_unlock_irqrestore(&line->lock, flags); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static struct tty_driver *uml_console_device(struct console *c, int *index) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds *index = c->index; 1411da177e4SLinus Torvalds return console_driver; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static int uml_console_setup(struct console *co, char *options) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds struct line *line = &vts[co->index]; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds return console_open_chan(line, co, &opts); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static struct console stdiocons = { 1521da177e4SLinus Torvalds .name = "tty", 1531da177e4SLinus Torvalds .write = uml_console_write, 1541da177e4SLinus Torvalds .device = uml_console_device, 1551da177e4SLinus Torvalds .setup = uml_console_setup, 1561da177e4SLinus Torvalds .flags = CON_PRINTBUFFER, 1571da177e4SLinus Torvalds .index = -1, 1581da177e4SLinus Torvalds .data = &vts, 1591da177e4SLinus Torvalds }; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds int stdio_init(void) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds char *new_title; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds console_driver = line_register_devfs(&console_lines, &driver, 1661da177e4SLinus Torvalds &console_ops, vts, 1671da177e4SLinus Torvalds ARRAY_SIZE(vts)); 168d50084a2SJeff Dike if (console_driver == NULL) 1691da177e4SLinus Torvalds return -1; 1701da177e4SLinus Torvalds printk(KERN_INFO "Initialized stdio console driver\n"); 1711da177e4SLinus Torvalds 172*1f80171eSJeff Dike lines_init(vts, ARRAY_SIZE(vts), &opts); 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds new_title = add_xterm_umid(opts.xterm_title); 1751da177e4SLinus Torvalds if(new_title != NULL) 1761da177e4SLinus Torvalds opts.xterm_title = new_title; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds con_init_done = 1; 1791da177e4SLinus Torvalds register_console(&stdiocons); 180d50084a2SJeff Dike return 0; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds late_initcall(stdio_init); 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds static void console_exit(void) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds if (!con_init_done) 1871da177e4SLinus Torvalds return; 1880834cc77SJeff Dike close_lines(vts, ARRAY_SIZE(vts)); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds __uml_exitcall(console_exit); 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static int console_chan_setup(char *str) 1931da177e4SLinus Torvalds { 194d571cd18SJeff Dike return line_setup(vts, ARRAY_SIZE(vts), str); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds __setup("con", console_chan_setup); 1971da177e4SLinus Torvalds __channel_help(console_chan_setup, "con"); 198