Logo Search packages:      
Sourcecode: linux version File versions  Download package

simcons.c

/*
 * arch/v850/kernel/simcons.c -- Console I/O for GDB v850e simulator
 *
 *  Copyright (C) 2001,02,03  NEC Electronics Corporation
 *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License.  See the file COPYING in the main directory of this
 * archive for more details.
 *
 * Written by Miles Bader <miles@gnu.org>
 */

#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/tty_driver.h>
#include <linux/init.h>

#include <asm/poll.h>
#include <asm/string.h>
#include <asm/simsyscall.h>


/*  Low-level console. */

static void simcons_write (struct console *co, const char *buf, unsigned len)
{
      V850_SIM_SYSCALL (write, 1, buf, len);
}

static int simcons_read (struct console *co, char *buf, unsigned len)
{
      return V850_SIM_SYSCALL (read, 0, buf, len);
}

static struct tty_driver *tty_driver;
static struct tty_driver *simcons_device (struct console *c, int *index)
{
      *index = c->index;
      return tty_driver;
}

static struct console simcons =
{
    .name   = "simcons",
    .write  = simcons_write,
    .read   = simcons_read,
    .device = simcons_device,
    .flags  = CON_PRINTBUFFER,
    .index  = -1,
};

/* Higher level TTY interface.  */

int simcons_tty_open (struct tty_struct *tty, struct file *filp)
{
      return 0;
}

int simcons_tty_write (struct tty_struct *tty,
                   const unsigned char *buf, int count)
{
      return V850_SIM_SYSCALL (write, 1, buf, count);
}

int simcons_tty_write_room (struct tty_struct *tty)
{
      /* Completely arbitrary.  */
      return 0x100000;
}

int simcons_tty_chars_in_buffer (struct tty_struct *tty)
{
      /* We have no buffer.  */
      return 0;
}

static const struct tty_operations ops = {
      .open = simcons_tty_open,
      .write = simcons_tty_write,
      .write_room = simcons_tty_write_room,
      .chars_in_buffer = simcons_tty_chars_in_buffer,
};

int __init simcons_tty_init (void)
{
      struct tty_driver *driver = alloc_tty_driver(1);
      int err;
      if (!driver)
            return -ENOMEM;
      driver->name = "simcons";
      driver->major = TTY_MAJOR;
      driver->minor_start = 64;
      driver->type = TTY_DRIVER_TYPE_SYSCONS;
      driver->init_termios = tty_std_termios;
      tty_set_operations(driver, &ops);
      err = tty_register_driver(driver);
      if (err) {
            put_tty_driver(driver);
            return err;
      }
      tty_driver = driver;
      return 0;
}
/* We use `late_initcall' instead of just `__initcall' as a workaround for
   the fact that (1) simcons_tty_init can't be called before tty_init,
   (2) tty_init is called via `module_init', (3) if statically linked,
   module_init == device_init, and (4) there's no ordering of init lists.
   We can do this easily because simcons is always statically linked, but
   other tty drivers that depend on tty_init and which must use
   `module_init' to declare their init routines are likely to be broken.  */
late_initcall(simcons_tty_init);

/* Poll for input on the console, and if there's any, deliver it to the
   tty driver.  */
void simcons_poll_tty (struct tty_struct *tty)
{
      char buf[32];     /* Not the nicest way to do it but I need it correct first */
      int flip = 0, send_break = 0;
      struct pollfd pfd;
      pfd.fd = 0;
      pfd.events = POLLIN;

      if (V850_SIM_SYSCALL (poll, &pfd, 1, 0) > 0) {
            if (pfd.revents & POLLIN) {
                  /* Real block hardware knows the transfer size before
                     transfer so the new tty buffering doesn't try to handle
                     this rather weird simulator specific case well */
                  int rd = V850_SIM_SYSCALL (read, 0, buf, 32);
                  if (rd > 0) {
                        tty_insert_flip_string(tty, buf, rd);
                        flip = 1;
                  } else
                        send_break = 1;
            } else if (pfd.revents & POLLERR)
                  send_break = 1;
      }

      if (send_break) {
            tty_insert_flip_char (tty, 0, TTY_BREAK);       
            flip = 1;
      }

      if (flip)
            tty_schedule_flip (tty);
}

void simcons_poll_ttys (void)
{
      if (tty_driver && tty_driver->ttys[0])
            simcons_poll_tty (tty_driver->ttys[0]);
}

void simcons_setup (void)
{
      V850_SIM_SYSCALL (make_raw, 0);
      register_console (&simcons);
      printk (KERN_INFO "Console: GDB V850E simulator stdio\n");
}

Generated by  Doxygen 1.6.0   Back to index