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" 23510c72a3SAl Viro #include "chan.h" 241da177e4SLinus Torvalds #include "irq_user.h" 251da177e4SLinus Torvalds #include "mconsole_kern.h" 261da177e4SLinus Torvalds #include "init.h" 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #define MAX_TTYS (16) 291da177e4SLinus Torvalds 30074a0db8SWANG Cong static void stdio_announce(char *dev_name, int dev) 311da177e4SLinus Torvalds { 321da177e4SLinus Torvalds printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, 331da177e4SLinus Torvalds dev_name); 341da177e4SLinus Torvalds } 351da177e4SLinus Torvalds 36a52f362fSJeff Dike /* Almost const, except that xterm_title may be changed in an initcall */ 371da177e4SLinus Torvalds static struct chan_opts opts = { 381da177e4SLinus Torvalds .announce = stdio_announce, 391da177e4SLinus Torvalds .xterm_title = "Virtual Console #%d", 401da177e4SLinus Torvalds .raw = 1, 411da177e4SLinus Torvalds }; 421da177e4SLinus Torvalds 43f28169d2SJeff Dike static int con_config(char *str, char **error_out); 441da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out); 45f28169d2SJeff Dike static int con_remove(int n, char **con_remove); 461da177e4SLinus Torvalds 47d5c9ffc6SJeff Dike 48d5c9ffc6SJeff Dike /* Const, except for .mc.list */ 491da177e4SLinus Torvalds static struct line_driver driver = { 501da177e4SLinus Torvalds .name = "UML console", 511da177e4SLinus Torvalds .device_name = "tty", 521da177e4SLinus Torvalds .major = TTY_MAJOR, 531da177e4SLinus Torvalds .minor_start = 0, 541da177e4SLinus Torvalds .type = TTY_DRIVER_TYPE_CONSOLE, 551da177e4SLinus Torvalds .subtype = SYSTEM_TYPE_CONSOLE, 561da177e4SLinus Torvalds .read_irq = CONSOLE_IRQ, 571da177e4SLinus Torvalds .read_irq_name = "console", 581da177e4SLinus Torvalds .write_irq = CONSOLE_WRITE_IRQ, 591da177e4SLinus Torvalds .write_irq_name = "console-write", 601da177e4SLinus Torvalds .mc = { 61c0961c18SJeff Dike .list = LIST_HEAD_INIT(driver.mc.list), 621da177e4SLinus Torvalds .name = "con", 631da177e4SLinus Torvalds .config = con_config, 641da177e4SLinus Torvalds .get_config = con_get_config, 6529d56cfeSJeff Dike .id = line_id, 661da177e4SLinus Torvalds .remove = con_remove, 671da177e4SLinus Torvalds }, 681da177e4SLinus Torvalds }; 691da177e4SLinus Torvalds 70d5c9ffc6SJeff Dike /* The array is initialized by line_init, at initcall time. The 71d5c9ffc6SJeff Dike * elements are locked individually as needed. 721da177e4SLinus Torvalds */ 7343574c1aSAl Viro static char *vt_conf[MAX_TTYS]; 7443574c1aSAl Viro static char *def_conf; 7543574c1aSAl Viro static struct line vts[MAX_TTYS]; 761da177e4SLinus Torvalds 77f28169d2SJeff Dike static int con_config(char *str, char **error_out) 781da177e4SLinus Torvalds { 79f28169d2SJeff Dike return line_config(vts, ARRAY_SIZE(vts), str, &opts, error_out); 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static int con_get_config(char *dev, char *str, int size, char **error_out) 831da177e4SLinus Torvalds { 840834cc77SJeff Dike return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 87f28169d2SJeff Dike static int con_remove(int n, char **error_out) 881da177e4SLinus Torvalds { 89f28169d2SJeff Dike return line_remove(vts, ARRAY_SIZE(vts), n, error_out); 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static int con_open(struct tty_struct *tty, struct file *filp) 931da177e4SLinus Torvalds { 94d14ad81fSJeff Dike int err = line_open(vts, tty); 95d14ad81fSJeff Dike if (err) 96d14ad81fSJeff Dike printk(KERN_ERR "Failed to open console %d, err = %d\n", 97d14ad81fSJeff Dike tty->index, err); 98d14ad81fSJeff Dike 99d14ad81fSJeff Dike return err; 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 102730760e9SJeff Dike /* Set in an initcall, checked in an exitcall */ 1031da177e4SLinus Torvalds static int con_init_done = 0; 1041da177e4SLinus Torvalds 1055e7672ecSJeff Dike static const struct tty_operations console_ops = { 1061da177e4SLinus Torvalds .open = con_open, 1071da177e4SLinus Torvalds .close = line_close, 1081da177e4SLinus Torvalds .write = line_write, 109b97b77ccSPaolo 'Blaisorblade' Giarrusso .put_char = line_put_char, 1101da177e4SLinus Torvalds .write_room = line_write_room, 1111da177e4SLinus Torvalds .chars_in_buffer = line_chars_in_buffer, 112b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_buffer = line_flush_buffer, 113b97b77ccSPaolo 'Blaisorblade' Giarrusso .flush_chars = line_flush_chars, 1141da177e4SLinus Torvalds .set_termios = line_set_termios, 1151da177e4SLinus Torvalds .ioctl = line_ioctl, 116e4dcee80SJeff Dike .throttle = line_throttle, 117e4dcee80SJeff Dike .unthrottle = line_unthrottle, 1181da177e4SLinus Torvalds }; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static void uml_console_write(struct console *console, const char *string, 1211da177e4SLinus Torvalds unsigned len) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds struct line *line = &vts[console->index]; 124b97b77ccSPaolo 'Blaisorblade' Giarrusso unsigned long flags; 1251da177e4SLinus Torvalds 126b97b77ccSPaolo 'Blaisorblade' Giarrusso spin_lock_irqsave(&line->lock, flags); 1271da177e4SLinus Torvalds console_write_chan(&line->chan_list, string, len); 128b97b77ccSPaolo 'Blaisorblade' Giarrusso spin_unlock_irqrestore(&line->lock, flags); 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds static struct tty_driver *uml_console_device(struct console *c, int *index) 1321da177e4SLinus Torvalds { 1331da177e4SLinus Torvalds *index = c->index; 134*cfe6b7c7SAl Viro return driver.driver; 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds static int uml_console_setup(struct console *co, char *options) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds struct line *line = &vts[co->index]; 1401da177e4SLinus Torvalds 141a52f362fSJeff Dike return console_open_chan(line, co); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 144d5c9ffc6SJeff Dike /* No locking for register_console call - relies on single-threaded initcalls */ 1451da177e4SLinus Torvalds static struct console stdiocons = { 1461da177e4SLinus Torvalds .name = "tty", 1471da177e4SLinus Torvalds .write = uml_console_write, 1481da177e4SLinus Torvalds .device = uml_console_device, 1491da177e4SLinus Torvalds .setup = uml_console_setup, 150b5337885SPaolo 'Blaisorblade' Giarrusso .flags = CON_PRINTBUFFER|CON_ANYTIME, 1511da177e4SLinus Torvalds .index = -1, 1521da177e4SLinus Torvalds }; 1531da177e4SLinus Torvalds 154074a0db8SWANG Cong static int stdio_init(void) 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds char *new_title; 157*cfe6b7c7SAl Viro int err; 15843574c1aSAl Viro int i; 1591da177e4SLinus Torvalds 16043574c1aSAl Viro for (i = 0; i < MAX_TTYS; i++) { 16143574c1aSAl Viro char *s = vt_conf[i]; 16243574c1aSAl Viro if (!s) 16343574c1aSAl Viro s = def_conf; 16443574c1aSAl Viro if (!s) 16543574c1aSAl Viro s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; 166*cfe6b7c7SAl Viro if (s && strcmp(s, "none") != 0) 16743574c1aSAl Viro vts[i].init_str = s; 16843574c1aSAl Viro spin_lock_init(&vts[i].lock); 169d8c215adSAl Viro mutex_init(&vts[i].count_lock); 17043574c1aSAl Viro vts[i].driver = &driver; 17143574c1aSAl Viro } 172*cfe6b7c7SAl Viro err = register_lines(&driver, &console_ops, vts, 1731da177e4SLinus Torvalds ARRAY_SIZE(vts)); 174*cfe6b7c7SAl Viro if (err) 175*cfe6b7c7SAl Viro return err; 1761da177e4SLinus Torvalds printk(KERN_INFO "Initialized stdio console driver\n"); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds new_title = add_xterm_umid(opts.xterm_title); 1791da177e4SLinus Torvalds if(new_title != NULL) 1801da177e4SLinus Torvalds opts.xterm_title = new_title; 1811da177e4SLinus Torvalds 18257ac895aSDavide Brini lines_init(vts, ARRAY_SIZE(vts), &opts); 18357ac895aSDavide Brini 1841da177e4SLinus Torvalds con_init_done = 1; 1851da177e4SLinus Torvalds register_console(&stdiocons); 186d50084a2SJeff Dike return 0; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds late_initcall(stdio_init); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static void console_exit(void) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds if (!con_init_done) 1931da177e4SLinus Torvalds return; 1940834cc77SJeff Dike close_lines(vts, ARRAY_SIZE(vts)); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds __uml_exitcall(console_exit); 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds static int console_chan_setup(char *str) 1991da177e4SLinus Torvalds { 20043574c1aSAl Viro line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console"); 201f28169d2SJeff Dike return 1; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds __setup("con", console_chan_setup); 2041da177e4SLinus Torvalds __channel_help(console_chan_setup, "con"); 205