^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/posix_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kdev_t.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/hardirq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/current.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "stdio_console.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "chan.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <irq_user.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "mconsole_kern.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define MAX_TTYS (16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static void stdio_announce(char *dev_name, int dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) dev_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* Almost const, except that xterm_title may be changed in an initcall */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static struct chan_opts opts = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .announce = stdio_announce,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) .xterm_title = "Virtual Console #%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .raw = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static int con_config(char *str, char **error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int con_get_config(char *dev, char *str, int size, char **error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int con_remove(int n, char **con_remove);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* Const, except for .mc.list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static struct line_driver driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .name = "UML console",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .device_name = "tty",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) .major = TTY_MAJOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) .minor_start = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .type = TTY_DRIVER_TYPE_CONSOLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .subtype = SYSTEM_TYPE_CONSOLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) .read_irq = CONSOLE_IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) .read_irq_name = "console",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .write_irq = CONSOLE_WRITE_IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) .write_irq_name = "console-write",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .mc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .list = LIST_HEAD_INIT(driver.mc.list),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .name = "con",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .config = con_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .get_config = con_get_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .id = line_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .remove = con_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* The array is initialized by line_init, at initcall time. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * elements are locked individually as needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static char *vt_conf[MAX_TTYS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static char *def_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static struct line vts[MAX_TTYS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int con_config(char *str, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return line_config(vts, ARRAY_SIZE(vts), str, &opts, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int con_get_config(char *dev, char *str, int size, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int con_remove(int n, char **error_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return line_remove(vts, ARRAY_SIZE(vts), n, error_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* Set in an initcall, checked in an exitcall */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static int con_init_done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int con_install(struct tty_driver *driver, struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return line_install(driver, tty, &vts[tty->index]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static const struct tty_operations console_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .open = line_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .install = con_install,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .close = line_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .write = line_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .write_room = line_write_room,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .chars_in_buffer = line_chars_in_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .flush_buffer = line_flush_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .flush_chars = line_flush_chars,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .set_termios = line_set_termios,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .throttle = line_throttle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .unthrottle = line_unthrottle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .hangup = line_hangup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void uml_console_write(struct console *console, const char *string,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) unsigned len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct line *line = &vts[console->index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) spin_lock_irqsave(&line->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) console_write_chan(line->chan_out, string, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) spin_unlock_irqrestore(&line->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) static struct tty_driver *uml_console_device(struct console *c, int *index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) *index = c->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return driver.driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int uml_console_setup(struct console *co, char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct line *line = &vts[co->index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return console_open_chan(line, co);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* No locking for register_console call - relies on single-threaded initcalls */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static struct console stdiocons = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .name = "tty",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .write = uml_console_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .device = uml_console_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .setup = uml_console_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .flags = CON_PRINTBUFFER|CON_ANYTIME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .index = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static int stdio_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) char *new_title;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) err = register_lines(&driver, &console_ops, vts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ARRAY_SIZE(vts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) printk(KERN_INFO "Initialized stdio console driver\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) new_title = add_xterm_umid(opts.xterm_title);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if(new_title != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) opts.xterm_title = new_title;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) for (i = 0; i < MAX_TTYS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) char *error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) char *s = vt_conf[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) s = def_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (!s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (setup_one_line(vts, i, s, &opts, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) printk(KERN_ERR "setup_one_line failed for "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) "device %d : %s\n", i, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) con_init_done = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) register_console(&stdiocons);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) late_initcall(stdio_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static void console_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (!con_init_done)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) close_lines(vts, ARRAY_SIZE(vts));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) __uml_exitcall(console_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int console_chan_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (!strncmp(str, "sole=", 5)) /* console= option specifies tty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) __setup("con", console_chan_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) __channel_help(console_chan_setup, "con");