1/*
2 * arch/v850/kernel/memcons.c -- Console I/O to a memory buffer
3 *
4 *  Copyright (C) 2001,02  NEC Corporation
5 *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
6 *
7 * This file is subject to the terms and conditions of the GNU General
8 * Public License.  See the file COPYING in the main directory of this
9 * archive for more details.
10 *
11 * Written by Miles Bader <miles@gnu.org>
12 */
13
14#include <linux/kernel.h>
15#include <linux/console.h>
16#include <linux/tty.h>
17#include <linux/tty_driver.h>
18#include <linux/init.h>
19
20/* If this device is enabled, the linker map should define start and
21   end points for its buffer. */
22extern char memcons_output[], memcons_output_end;
23
24/* Current offset into the buffer.  */
25static unsigned long memcons_offs = 0;
26
27/* Spinlock protecting memcons_offs.  */
28static DEFINE_SPINLOCK(memcons_lock);
29
30
31static size_t write (const char *buf, size_t len)
32{
33	unsigned long flags;
34	char *point;
35
36	spin_lock_irqsave (memcons_lock, flags);
37
38	point = memcons_output + memcons_offs;
39	if (point + len >= &memcons_output_end) {
40		len = &memcons_output_end - point;
41		memcons_offs = 0;
42	} else
43		memcons_offs += len;
44
45	spin_unlock_irqrestore (memcons_lock, flags);
46
47	memcpy (point, buf, len);
48
49	return len;
50}
51
52
53/*  Low-level console. */
54
55static void memcons_write (struct console *co, const char *buf, unsigned len)
56{
57	while (len > 0)
58		len -= write (buf, len);
59}
60
61static struct tty_driver *tty_driver;
62
63static struct tty_driver *memcons_device (struct console *co, int *index)
64{
65	*index = co->index;
66	return tty_driver;
67}
68
69static struct console memcons =
70{
71    .name	= "memcons",
72    .write	= memcons_write,
73    .device	= memcons_device,
74    .flags	= CON_PRINTBUFFER,
75    .index	= -1,
76};
77
78void memcons_setup (void)
79{
80	register_console (&memcons);
81	printk (KERN_INFO "Console: static memory buffer (memcons)\n");
82}
83
84/* Higher level TTY interface.  */
85
86int memcons_tty_open (struct tty_struct *tty, struct file *filp)
87{
88	return 0;
89}
90
91int memcons_tty_write (struct tty_struct *tty, const unsigned char *buf, int len)
92{
93	return write (buf, len);
94}
95
96int memcons_tty_write_room (struct tty_struct *tty)
97{
98	return &memcons_output_end - (memcons_output + memcons_offs);
99}
100
101int memcons_tty_chars_in_buffer (struct tty_struct *tty)
102{
103	/* We have no buffer.  */
104	return 0;
105}
106
107static const struct tty_operations ops = {
108	.open = memcons_tty_open,
109	.write = memcons_tty_write,
110	.write_room = memcons_tty_write_room,
111	.chars_in_buffer = memcons_tty_chars_in_buffer,
112};
113
114int __init memcons_tty_init (void)
115{
116	int err;
117	struct tty_driver *driver = alloc_tty_driver(1);
118	if (!driver)
119		return -ENOMEM;
120
121	driver->name = "memcons";
122	driver->major = TTY_MAJOR;
123	driver->minor_start = 64;
124	driver->type = TTY_DRIVER_TYPE_SYSCONS;
125	driver->init_termios = tty_std_termios;
126	tty_set_operations(driver, &ops);
127	err = tty_register_driver(driver);
128	if (err) {
129		put_tty_driver(driver);
130		return err;
131	}
132	tty_driver = driver;
133	return 0;
134}
135__initcall (memcons_tty_init);
136