summaryrefslogtreecommitdiffstats
path: root/arch/v850/kernel/simcons.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/v850/kernel/simcons.c')
-rw-r--r--arch/v850/kernel/simcons.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c
new file mode 100644
index 000000000000..7f0efaa025c9
--- /dev/null
+++ b/arch/v850/kernel/simcons.c
@@ -0,0 +1,166 @@
+/*
+ * 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 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)
+{
+ 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) {
+ int left = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+ if (left > 0) {
+ unsigned char *buf = tty->flip.char_buf_ptr;
+ int rd = V850_SIM_SYSCALL (read, 0, buf, left);
+
+ if (rd > 0) {
+ tty->flip.count += rd;
+ tty->flip.char_buf_ptr += rd;
+ memset (tty->flip.flag_buf_ptr, 0, rd);
+ tty->flip.flag_buf_ptr += 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");
+}