ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / v850 / kernel / memcons.c
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. */
22 extern char memcons_output[], memcons_output_end;
23
24 /* Current offset into the buffer.  */
25 static unsigned long memcons_offs = 0;
26
27 /* Spinlock protecting memcons_offs.  */
28 static spinlock_t memcons_lock = SPIN_LOCK_UNLOCKED;
29
30
31 static size_t write (const char *buf, size_t len)
32 {
33         int 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 \f
53 /*  Low-level console. */
54
55 static void memcons_write (struct console *co, const char *buf, unsigned len)
56 {
57         while (len > 0)
58                 len -= write (buf, len);
59 }
60
61 static struct tty_driver *tty_driver;
62
63 static struct tty_driver *memcons_device (struct console *co, int *index)
64 {
65         *index = co->index;
66         return tty_driver;
67 }
68
69 static struct console memcons =
70 {
71     .name       = "memcons",
72     .write      = memcons_write,
73     .device     = memcons_device,
74     .flags      = CON_PRINTBUFFER,
75     .index      = -1,
76 };
77
78 void memcons_setup (void)
79 {
80         register_console (&memcons);
81         printk (KERN_INFO "Console: static memory buffer (memcons)\n");
82 }
83 \f
84 /* Higher level TTY interface.  */
85
86 int memcons_tty_open (struct tty_struct *tty, struct file *filp)
87 {
88         return 0;
89 }
90
91 int memcons_tty_write (struct tty_struct *tty, int from_user,
92                        const unsigned char *buf, int len)
93 {
94         return write (buf, len);
95 }
96
97 int memcons_tty_write_room (struct tty_struct *tty)
98 {
99         return &memcons_output_end - (memcons_output + memcons_offs);
100 }
101
102 int memcons_tty_chars_in_buffer (struct tty_struct *tty)
103 {
104         /* We have no buffer.  */
105         return 0;
106 }
107
108 static struct tty_operations ops = {
109         .open = memcons_tty_open,
110         .write = memcons_tty_write,
111         .write_room = memcons_tty_write_room,
112         .chars_in_buffer = memcons_tty_chars_in_buffer,
113 };
114
115 int __init memcons_tty_init (void)
116 {
117         int err;
118         struct tty_driver *driver = alloc_tty_driver(1);
119         if (!driver)
120                 return -ENOMEM;
121
122         driver->name = "memcons";
123         driver->major = TTY_MAJOR;
124         driver->minor_start = 64;
125         driver->type = TTY_DRIVER_TYPE_SYSCONS;
126         driver->init_termios = tty_std_termios;
127         tty_set_operations(driver, &ops);
128         err = tty_register_driver(driver);
129         if (err) {
130                 put_tty_driver(driver);
131                 return err;
132         }
133         tty_driver = driver;
134         return 0;
135 }
136 __initcall (memcons_tty_init);