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/posix_types.h" 71da177e4SLinus Torvalds #include "linux/tty.h" 81da177e4SLinus Torvalds #include "linux/tty_flip.h" 91da177e4SLinus Torvalds #include "linux/types.h" 101da177e4SLinus Torvalds #include "linux/major.h" 111da177e4SLinus Torvalds #include "linux/kdev_t.h" 121da177e4SLinus Torvalds #include "linux/console.h" 131da177e4SLinus Torvalds #include "linux/string.h" 141da177e4SLinus Torvalds #include "linux/sched.h" 151da177e4SLinus Torvalds #include "linux/list.h" 161da177e4SLinus Torvalds #include "linux/init.h" 171da177e4SLinus Torvalds #include "linux/interrupt.h" 181da177e4SLinus Torvalds #include "linux/slab.h" 191da177e4SLinus Torvalds #include "linux/hardirq.h" 201da177e4SLinus Torvalds #include "asm/current.h" 211da177e4SLinus Torvalds #include "asm/irq.h" 221da177e4SLinus Torvalds #include "stdio_console.h" 231da177e4SLinus Torvalds #include "line.h" 241da177e4SLinus Torvalds #include "chan_kern.h" 251da177e4SLinus Torvalds #include "user_util.h" 261da177e4SLinus Torvalds #include "kern_util.h" 271da177e4SLinus Torvalds #include "irq_user.h" 281da177e4SLinus Torvalds #include "mconsole_kern.h" 291da177e4SLinus Torvalds #include "init.h" 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #define MAX_TTYS (16) 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds /* Referenced only by tty_driver below - presumably it's locked correctly 341da177e4SLinus Torvalds * by the tty driver. 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static struct tty_driver *console_driver; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds void stdio_announce(char *dev_name, int dev) 401da177e4SLinus Torvalds { 411da177e4SLinus Torvalds printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, 421da177e4SLinus Torvalds dev_name); 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds 45*a52f362fSJeff Dike /* Almost const, except that xterm_title may be changed in an initcall */ 461da177e4SLinus Torvalds static struct chan_opts opts = { 471da177e4SLinus Torvalds .announce = stdio_announce, 481da177e4SLinus Torvalds .xterm_title = "Virtual Console #%d", 491da177e4SLinus Torvalds .raw = 1, 501da177e4SLinus Torvalds .tramp_stack = 0, 511da177e4SLinus Torvalds .in_kernel = 1, 521da177e4SLinus Torvalds }; 531da177e4SLinus Torvalds 54f28169d2SJeff Dike static int con_config(char *str, char **error_out); 551da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out); 56f28169d2SJeff Dike static int con_remove(int n, char **con_remove); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static struct line_driver driver = { 591da177e4SLinus Torvalds .name = "UML console", 601da177e4SLinus Torvalds .device_name = "tty", 611da177e4SLinus Torvalds .major = TTY_MAJOR, 621da177e4SLinus Torvalds .minor_start = 0, 631da177e4SLinus Torvalds .type = TTY_DRIVER_TYPE_CONSOLE, 641da177e4SLinus Torvalds .subtype = SYSTEM_TYPE_CONSOLE, 651da177e4SLinus Torvalds .read_irq = CONSOLE_IRQ, 661da177e4SLinus Torvalds .read_irq_name = "console", 671da177e4SLinus Torvalds .write_irq = CONSOLE_WRITE_IRQ, 681da177e4SLinus Torvalds .write_irq_name = "console-write", 691da177e4SLinus Torvalds .symlink_from = "ttys", 701da177e4SLinus Torvalds .symlink_to = "vc", 711da177e4SLinus Torvalds .mc = { 721da177e4SLinus Torvalds .name = "con", 731da177e4SLinus Torvalds .config = con_config, 741da177e4SLinus Torvalds .get_config = con_get_config, 7529d56cfeSJeff Dike .id = line_id, 761da177e4SLinus Torvalds .remove = con_remove, 771da177e4SLinus Torvalds }, 781da177e4SLinus Torvalds }; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds static struct lines console_lines = LINES_INIT(MAX_TTYS); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* The array is initialized by line_init, which is an initcall. The 831da177e4SLinus Torvalds * individual elements are protected by individual semaphores. 841da177e4SLinus Torvalds */ 85d79a5809SJeff Dike static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), 861da177e4SLinus Torvalds [ 1 ... MAX_TTYS - 1 ] = 871da177e4SLinus Torvalds LINE_INIT(CONFIG_CON_CHAN, &driver) }; 881da177e4SLinus Torvalds 89f28169d2SJeff Dike static int con_config(char *str, char **error_out) 901da177e4SLinus Torvalds { 91f28169d2SJeff Dike return line_config(vts, ARRAY_SIZE(vts), str, &opts, error_out); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out) 951da177e4SLinus Torvalds { 960834cc77SJeff Dike return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 99f28169d2SJeff Dike static int con_remove(int n, char **error_out) 1001da177e4SLinus Torvalds { 101f28169d2SJeff Dike return line_remove(vts, ARRAY_SIZE(vts), n, error_out); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds static int con_open(struct tty_struct *tty, struct file *filp) 1051da177e4SLinus Torvalds { 1061f80171eSJeff Dike return line_open(vts, tty); 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 109730760e9SJeff Dike /* Set in an initcall, checked in an exitcall */ 1101da177e4SLinus Torvalds static int con_init_done = 0; 1111da177e4SLinus Torvalds 1125e7672ecSJeff Dike static const struct tty_operations console_ops = { 1131da177e4SLinus Torvalds .open = con_open, 1141da177e4SLinus Torvalds .close = line_close, 1151da177e4SLinus Torvalds .write = line_write, 116b97b77ccSPaolo 'Blaisorblade' Giarrusso .put_char = line_put_char, 1171da177e4SLinus Torvalds .write_room = line_write_room, 1181da177e4SLinus Torvalds .chars_in_buffer = line_chars_in_buffer, 119b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_buffer = line_flush_buffer, 120b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_chars = line_flush_chars, 1211da177e4SLinus Torvalds .set_termios = line_set_termios, 1221da177e4SLinus Torvalds .ioctl = line_ioctl, 123e4dcee80SJeff Dike .throttle = line_throttle, 124e4dcee80SJeff Dike .unthrottle = line_unthrottle, 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 148*a52f362fSJeff Dike return console_open_chan(line, co); 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 1721f80171eSJeff 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 { 194f28169d2SJeff Dike char *error; 195f28169d2SJeff Dike int ret; 196f28169d2SJeff Dike 197f28169d2SJeff Dike ret = line_setup(vts, ARRAY_SIZE(vts), str, &error); 198f28169d2SJeff Dike if(ret < 0) 199f28169d2SJeff Dike printk(KERN_ERR "Failed to set up console with " 200f28169d2SJeff Dike "configuration string \"%s\" : %s\n", str, error); 201f28169d2SJeff Dike 202f28169d2SJeff Dike return 1; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds __setup("con", console_chan_setup); 2051da177e4SLinus Torvalds __channel_help(console_chan_setup, "con"); 206