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