linux/arch/alpha/kernel/srmcons.c
<<
>>
Prefs
   1/*
   2 *      linux/arch/alpha/kernel/srmcons.c
   3 *
   4 * Callback based driver for SRM Console console device.
   5 * (TTY driver and console driver)
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/init.h>
  10#include <linux/console.h>
  11#include <linux/delay.h>
  12#include <linux/mm.h>
  13#include <linux/slab.h>
  14#include <linux/spinlock.h>
  15#include <linux/timer.h>
  16#include <linux/tty.h>
  17#include <linux/tty_driver.h>
  18#include <linux/tty_flip.h>
  19
  20#include <asm/console.h>
  21#include <linux/uaccess.h>
  22
  23
  24static DEFINE_SPINLOCK(srmcons_callback_lock);
  25static int srm_is_registered_console = 0;
  26
  27/* 
  28 * The TTY driver
  29 */
  30#define MAX_SRM_CONSOLE_DEVICES 1       /* only support 1 console device */
  31
  32struct srmcons_private {
  33        struct tty_port port;
  34        struct timer_list timer;
  35} srmcons_singleton;
  36
  37typedef union _srmcons_result {
  38        struct {
  39                unsigned long c :61;
  40                unsigned long status :3;
  41        } bits;
  42        long as_long;
  43} srmcons_result;
  44
  45/* called with callback_lock held */
  46static int
  47srmcons_do_receive_chars(struct tty_port *port)
  48{
  49        srmcons_result result;
  50        int count = 0, loops = 0;
  51
  52        do {
  53                result.as_long = callback_getc(0);
  54                if (result.bits.status < 2) {
  55                        tty_insert_flip_char(port, (char)result.bits.c, 0);
  56                        count++;
  57                }
  58        } while((result.bits.status & 1) && (++loops < 10));
  59
  60        if (count)
  61                tty_schedule_flip(port);
  62
  63        return count;
  64}
  65
  66static void
  67srmcons_receive_chars(unsigned long data)
  68{
  69        struct srmcons_private *srmconsp = (struct srmcons_private *)data;
  70        struct tty_port *port = &srmconsp->port;
  71        unsigned long flags;
  72        int incr = 10;
  73
  74        local_irq_save(flags);
  75        if (spin_trylock(&srmcons_callback_lock)) {
  76                if (!srmcons_do_receive_chars(port))
  77                        incr = 100;
  78                spin_unlock(&srmcons_callback_lock);
  79        } 
  80
  81        spin_lock(&port->lock);
  82        if (port->tty)
  83                mod_timer(&srmconsp->timer, jiffies + incr);
  84        spin_unlock(&port->lock);
  85
  86        local_irq_restore(flags);
  87}
  88
  89/* called with callback_lock held */
  90static int
  91srmcons_do_write(struct tty_port *port, const char *buf, int count)
  92{
  93        static char str_cr[1] = "\r";
  94        long c, remaining = count;
  95        srmcons_result result;
  96        char *cur;
  97        int need_cr;
  98
  99        for (cur = (char *)buf; remaining > 0; ) {
 100                need_cr = 0;
 101                /* 
 102                 * Break it up into reasonable size chunks to allow a chance
 103                 * for input to get in
 104                 */
 105                for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
 106                        if (cur[c] == '\n')
 107                                need_cr = 1;
 108                
 109                while (c > 0) {
 110                        result.as_long = callback_puts(0, cur, c);
 111                        c -= result.bits.c;
 112                        remaining -= result.bits.c;
 113                        cur += result.bits.c;
 114
 115                        /*
 116                         * Check for pending input iff a tty port was provided
 117                         */
 118                        if (port)
 119                                srmcons_do_receive_chars(port);
 120                }
 121
 122                while (need_cr) {
 123                        result.as_long = callback_puts(0, str_cr, 1);
 124                        if (result.bits.c > 0)
 125                                need_cr = 0;
 126                }
 127        }
 128        return count;
 129}
 130
 131static int
 132srmcons_write(struct tty_struct *tty,
 133              const unsigned char *buf, int count)
 134{
 135        unsigned long flags;
 136
 137        spin_lock_irqsave(&srmcons_callback_lock, flags);
 138        srmcons_do_write(tty->port, (const char *) buf, count);
 139        spin_unlock_irqrestore(&srmcons_callback_lock, flags);
 140
 141        return count;
 142}
 143
 144static int
 145srmcons_write_room(struct tty_struct *tty)
 146{
 147        return 512;
 148}
 149
 150static int
 151srmcons_chars_in_buffer(struct tty_struct *tty)
 152{
 153        return 0;
 154}
 155
 156static int
 157srmcons_open(struct tty_struct *tty, struct file *filp)
 158{
 159        struct srmcons_private *srmconsp = &srmcons_singleton;
 160        struct tty_port *port = &srmconsp->port;
 161        unsigned long flags;
 162
 163        spin_lock_irqsave(&port->lock, flags);
 164
 165        if (!port->tty) {
 166                tty->driver_data = srmconsp;
 167                tty->port = port;
 168                port->tty = tty; /* XXX proper refcounting */
 169                mod_timer(&srmconsp->timer, jiffies + 10);
 170        }
 171
 172        spin_unlock_irqrestore(&port->lock, flags);
 173
 174        return 0;
 175}
 176
 177static void
 178srmcons_close(struct tty_struct *tty, struct file *filp)
 179{
 180        struct srmcons_private *srmconsp = tty->driver_data;
 181        struct tty_port *port = &srmconsp->port;
 182        unsigned long flags;
 183
 184        spin_lock_irqsave(&port->lock, flags);
 185
 186        if (tty->count == 1) {
 187                port->tty = NULL;
 188                del_timer(&srmconsp->timer);
 189        }
 190
 191        spin_unlock_irqrestore(&port->lock, flags);
 192}
 193
 194
 195static struct tty_driver *srmcons_driver;
 196
 197static const struct tty_operations srmcons_ops = {
 198        .open           = srmcons_open,
 199        .close          = srmcons_close,
 200        .write          = srmcons_write,
 201        .write_room     = srmcons_write_room,
 202        .chars_in_buffer= srmcons_chars_in_buffer,
 203};
 204
 205static int __init
 206srmcons_init(void)
 207{
 208        setup_timer(&srmcons_singleton.timer, srmcons_receive_chars,
 209                        (unsigned long)&srmcons_singleton);
 210        if (srm_is_registered_console) {
 211                struct tty_driver *driver;
 212                int err;
 213
 214                driver = alloc_tty_driver(MAX_SRM_CONSOLE_DEVICES);
 215                if (!driver)
 216                        return -ENOMEM;
 217
 218                tty_port_init(&srmcons_singleton.port);
 219
 220                driver->driver_name = "srm";
 221                driver->name = "srm";
 222                driver->major = 0;      /* dynamic */
 223                driver->minor_start = 0;
 224                driver->type = TTY_DRIVER_TYPE_SYSTEM;
 225                driver->subtype = SYSTEM_TYPE_SYSCONS;
 226                driver->init_termios = tty_std_termios;
 227                tty_set_operations(driver, &srmcons_ops);
 228                tty_port_link_device(&srmcons_singleton.port, driver, 0);
 229                err = tty_register_driver(driver);
 230                if (err) {
 231                        put_tty_driver(driver);
 232                        tty_port_destroy(&srmcons_singleton.port);
 233                        return err;
 234                }
 235                srmcons_driver = driver;
 236        }
 237
 238        return -ENODEV;
 239}
 240device_initcall(srmcons_init);
 241
 242
 243/*
 244 * The console driver
 245 */
 246static void
 247srm_console_write(struct console *co, const char *s, unsigned count)
 248{
 249        unsigned long flags;
 250
 251        spin_lock_irqsave(&srmcons_callback_lock, flags);
 252        srmcons_do_write(NULL, s, count);
 253        spin_unlock_irqrestore(&srmcons_callback_lock, flags);
 254}
 255
 256static struct tty_driver *
 257srm_console_device(struct console *co, int *index)
 258{
 259        *index = co->index;
 260        return srmcons_driver;
 261}
 262
 263static int
 264srm_console_setup(struct console *co, char *options)
 265{
 266        return 0;
 267}
 268
 269static struct console srmcons = {
 270        .name           = "srm",
 271        .write          = srm_console_write,
 272        .device         = srm_console_device,
 273        .setup          = srm_console_setup,
 274        .flags          = CON_PRINTBUFFER | CON_BOOT,
 275        .index          = -1,
 276};
 277
 278void __init
 279register_srm_console(void)
 280{
 281        if (!srm_is_registered_console) {
 282                callback_open_console();
 283                register_console(&srmcons);
 284                srm_is_registered_console = 1;
 285        }
 286}
 287
 288void __init
 289unregister_srm_console(void)
 290{
 291        if (srm_is_registered_console) {
 292                callback_close_console();
 293                unregister_console(&srmcons);
 294                srm_is_registered_console = 0;
 295        }
 296}
 297