]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/misc/sti/sti-console.c
Merge branch 'omap-fixes'
[linux-2.6-omap-h63xx.git] / drivers / misc / sti / sti-console.c
1 /*
2  * Console support for OMAP STI/XTI
3  *
4  * Copyright (C) 2004, 2005, 2006 Nokia Corporation
5  * Written by: Paul Mundt <paul.mundt@nokia.com>
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/console.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/tty.h>
16 #include <linux/tty_driver.h>
17 #include <mach/sti.h>
18 #include <mach/board.h>
19
20 #define DRV_NAME "sticon"
21
22 static struct tty_driver *tty_driver;
23 static DEFINE_SPINLOCK(sti_console_lock);
24 static unsigned int sti_console_channel = -1;
25 static int sti_line_done = -1;
26
27 /*
28  * Write a string to any channel (including terminating NULL)
29  * Returns number of characters written.
30  */
31 static int sti_channel_puts(const char *string, unsigned int channel, int len)
32 {
33         int count = 0;
34
35         /*
36          * sti_line_done is needed to determine when we have reached the
37          * end of the line. write() has a tendency to hand us small
38          * strings which otherwise end up creating newlines.. we need to
39          * keep the channel open and in append mode until the line has
40          * been terminated.
41          */
42         if (sti_line_done != 0) {
43 #ifdef __LITTLE_ENDIAN
44                 sti_channel_writeb(0xc3, channel);
45 #else
46                 sti_channel_writeb(0xc0, channel);
47 #endif
48                 xchg(&sti_line_done, 0);
49         }
50
51         while (*string && count != len) {
52                 char c = *string++;
53
54                 count++;
55
56                 if (c == '\n') {
57                         xchg(&sti_line_done, 1);
58                         sti_channel_writeb(0, channel);
59                         break;
60                 } else
61                         sti_channel_writeb(c, channel);
62         }
63
64         if (sti_line_done)
65                 sti_channel_flush(channel);
66
67         return count;
68 }
69
70 static int sti_tty_open(struct tty_struct *tty, struct file *filp)
71 {
72         return 0;
73 }
74
75 static int sti_tty_write(struct tty_struct *tty,
76                          const unsigned char *buf, int len)
77 {
78         unsigned long flags;
79         int bytes;
80
81         spin_lock_irqsave(&sti_console_lock, flags);
82         bytes = sti_channel_puts(buf, sti_console_channel, len);
83         spin_unlock_irqrestore(&sti_console_lock, flags);
84
85         return bytes;
86 }
87
88 static int sti_tty_write_room(struct tty_struct *tty)
89 {
90         return 0x100000;
91 }
92
93 static int sti_tty_chars_in_buffer(struct tty_struct *tty)
94 {
95         return 0;
96 }
97
98 static struct tty_operations sti_tty_ops = {
99         .open                   = sti_tty_open,
100         .write                  = sti_tty_write,
101         .write_room             = sti_tty_write_room,
102         .chars_in_buffer        = sti_tty_chars_in_buffer,
103 };
104
105 static void sti_console_write(struct console *c, const char *s, unsigned n)
106 {
107         unsigned long flags;
108
109         spin_lock_irqsave(&sti_console_lock, flags);
110         sti_channel_puts(s, sti_console_channel, n);
111         spin_unlock_irqrestore(&sti_console_lock, flags);
112 }
113
114 static struct tty_driver *sti_console_device(struct console *c, int *index)
115 {
116         *index = c->index;
117         return tty_driver;
118 }
119
120 static int sti_console_setup(struct console *c, char *opts)
121 {
122         return 0;
123 }
124
125 static struct console sti_console = {
126         .name           = DRV_NAME,
127         .write          = sti_console_write,
128         .device         = sti_console_device,
129         .setup          = sti_console_setup,
130         .flags          = CON_PRINTBUFFER | CON_ENABLED,
131         .index          = -1,
132 };
133
134 static int __init sti_console_init(void)
135 {
136         const struct omap_sti_console_config *info;
137
138         info = omap_get_config(OMAP_TAG_STI_CONSOLE,
139                                struct omap_sti_console_config);
140         if (info && info->enable) {
141                 add_preferred_console(DRV_NAME, 0, NULL);
142
143                 sti_console_channel = info->channel;
144         }
145
146         if (unlikely(sti_console_channel == -1))
147                 return -EINVAL;
148
149         register_console(&sti_console);
150
151         return 0;
152 }
153 __initcall(sti_console_init);
154
155 static int __init sti_tty_init(void)
156 {
157         struct tty_driver *tty;
158         int ret;
159
160         tty = alloc_tty_driver(1);
161         if (!tty)
162                 return -ENOMEM;
163
164         tty->name               = DRV_NAME;
165         tty->driver_name        = DRV_NAME;
166         tty->major              = 0;    /* dynamic major */
167         tty->minor_start        = 0;
168         tty->type               = TTY_DRIVER_TYPE_SYSTEM;
169         tty->subtype            = SYSTEM_TYPE_SYSCONS;
170         tty->init_termios       = tty_std_termios;
171
172         tty_set_operations(tty, &sti_tty_ops);
173
174         ret = tty_register_driver(tty);
175         if (ret) {
176                 put_tty_driver(tty);
177                 return ret;
178         }
179
180         tty_driver = tty;
181         return 0;
182 }
183 late_initcall(sti_tty_init);
184
185 module_param(sti_console_channel, uint, 0);
186 MODULE_PARM_DESC(sti_console_channel, "STI console channel");
187 MODULE_AUTHOR("Paul Mundt");
188 MODULE_DESCRIPTION("OMAP STI console support");
189 MODULE_LICENSE("GPL");