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