aboutsummaryrefslogtreecommitdiff
path: root/arch/v850/kernel/memcons.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/v850/kernel/memcons.c')
-rw-r--r--arch/v850/kernel/memcons.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c
new file mode 100644
index 00000000000..491614c435c
--- /dev/null
+++ b/arch/v850/kernel/memcons.c
@@ -0,0 +1,135 @@
+/*
+ * arch/v850/kernel/memcons.c -- Console I/O to a memory buffer
+ *
+ * Copyright (C) 2001,02 NEC Corporation
+ * Copyright (C) 2001,02 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_driver.h>
+#include <linux/init.h>
+
+/* If this device is enabled, the linker map should define start and
+ end points for its buffer. */
+extern char memcons_output[], memcons_output_end;
+
+/* Current offset into the buffer. */
+static unsigned long memcons_offs = 0;
+
+/* Spinlock protecting memcons_offs. */
+static DEFINE_SPINLOCK(memcons_lock);
+
+
+static size_t write (const char *buf, size_t len)
+{
+ int flags;
+ char *point;
+
+ spin_lock_irqsave (memcons_lock, flags);
+
+ point = memcons_output + memcons_offs;
+ if (point + len >= &memcons_output_end) {
+ len = &memcons_output_end - point;
+ memcons_offs = 0;
+ } else
+ memcons_offs += len;
+
+ spin_unlock_irqrestore (memcons_lock, flags);
+
+ memcpy (point, buf, len);
+
+ return len;
+}
+
+
+/* Low-level console. */
+
+static void memcons_write (struct console *co, const char *buf, unsigned len)
+{
+ while (len > 0)
+ len -= write (buf, len);
+}
+
+static struct tty_driver *tty_driver;
+
+static struct tty_driver *memcons_device (struct console *co, int *index)
+{
+ *index = co->index;
+ return tty_driver;
+}
+
+static struct console memcons =
+{
+ .name = "memcons",
+ .write = memcons_write,
+ .device = memcons_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+void memcons_setup (void)
+{
+ register_console (&memcons);
+ printk (KERN_INFO "Console: static memory buffer (memcons)\n");
+}
+
+/* Higher level TTY interface. */
+
+int memcons_tty_open (struct tty_struct *tty, struct file *filp)
+{
+ return 0;
+}
+
+int memcons_tty_write (struct tty_struct *tty, const unsigned char *buf, int len)
+{
+ return write (buf, len);
+}
+
+int memcons_tty_write_room (struct tty_struct *tty)
+{
+ return &memcons_output_end - (memcons_output + memcons_offs);
+}
+
+int memcons_tty_chars_in_buffer (struct tty_struct *tty)
+{
+ /* We have no buffer. */
+ return 0;
+}
+
+static struct tty_operations ops = {
+ .open = memcons_tty_open,
+ .write = memcons_tty_write,
+ .write_room = memcons_tty_write_room,
+ .chars_in_buffer = memcons_tty_chars_in_buffer,
+};
+
+int __init memcons_tty_init (void)
+{
+ int err;
+ struct tty_driver *driver = alloc_tty_driver(1);
+ if (!driver)
+ return -ENOMEM;
+
+ driver->name = "memcons";
+ 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;
+}
+__initcall (memcons_tty_init);