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