2 * linux/arch/alpha/kernel/srmcons.c
4 * Callback based driver for SRM Console console device.
5 * (TTY driver and console driver)
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/console.h>
11 #include <linux/delay.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
15 #include <linux/timer.h>
16 #include <linux/tty.h>
17 #include <linux/tty_driver.h>
18 #include <linux/tty_flip.h>
20 #include <asm/console.h>
21 #include <asm/uaccess.h>
24 static DEFINE_SPINLOCK(srmcons_callback_lock
);
25 static int srm_is_registered_console
= 0;
30 #define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */
32 struct srmcons_private
{
34 struct timer_list timer
;
37 typedef union _srmcons_result
{
40 unsigned long status
:3;
45 /* called with callback_lock held */
47 srmcons_do_receive_chars(struct tty_port
*port
)
49 srmcons_result result
;
50 int count
= 0, loops
= 0;
53 result
.as_long
= callback_getc(0);
54 if (result
.bits
.status
< 2) {
55 tty_insert_flip_char(port
, (char)result
.bits
.c
, 0);
58 } while((result
.bits
.status
& 1) && (++loops
< 10));
61 tty_schedule_flip(port
);
67 srmcons_receive_chars(unsigned long data
)
69 struct srmcons_private
*srmconsp
= (struct srmcons_private
*)data
;
70 struct tty_port
*port
= &srmconsp
->port
;
74 local_irq_save(flags
);
75 if (spin_trylock(&srmcons_callback_lock
)) {
76 if (!srmcons_do_receive_chars(port
))
78 spin_unlock(&srmcons_callback_lock
);
81 spin_lock(&port
->lock
);
83 mod_timer(&srmconsp
->timer
, jiffies
+ incr
);
84 spin_unlock(&port
->lock
);
86 local_irq_restore(flags
);
89 /* called with callback_lock held */
91 srmcons_do_write(struct tty_port
*port
, const char *buf
, int count
)
93 static char str_cr
[1] = "\r";
94 long c
, remaining
= count
;
95 srmcons_result result
;
99 for (cur
= (char *)buf
; remaining
> 0; ) {
102 * Break it up into reasonable size chunks to allow a chance
103 * for input to get in
105 for (c
= 0; c
< min_t(long, 128L, remaining
) && !need_cr
; c
++)
110 result
.as_long
= callback_puts(0, cur
, c
);
112 remaining
-= result
.bits
.c
;
113 cur
+= result
.bits
.c
;
116 * Check for pending input iff a tty port was provided
119 srmcons_do_receive_chars(port
);
123 result
.as_long
= callback_puts(0, str_cr
, 1);
124 if (result
.bits
.c
> 0)
132 srmcons_write(struct tty_struct
*tty
,
133 const unsigned char *buf
, int count
)
137 spin_lock_irqsave(&srmcons_callback_lock
, flags
);
138 srmcons_do_write(tty
->port
, (const char *) buf
, count
);
139 spin_unlock_irqrestore(&srmcons_callback_lock
, flags
);
145 srmcons_write_room(struct tty_struct
*tty
)
151 srmcons_chars_in_buffer(struct tty_struct
*tty
)
157 srmcons_open(struct tty_struct
*tty
, struct file
*filp
)
159 struct srmcons_private
*srmconsp
= &srmcons_singleton
;
160 struct tty_port
*port
= &srmconsp
->port
;
163 spin_lock_irqsave(&port
->lock
, flags
);
166 tty
->driver_data
= srmconsp
;
168 port
->tty
= tty
; /* XXX proper refcounting */
169 mod_timer(&srmconsp
->timer
, jiffies
+ 10);
172 spin_unlock_irqrestore(&port
->lock
, flags
);
178 srmcons_close(struct tty_struct
*tty
, struct file
*filp
)
180 struct srmcons_private
*srmconsp
= tty
->driver_data
;
181 struct tty_port
*port
= &srmconsp
->port
;
184 spin_lock_irqsave(&port
->lock
, flags
);
186 if (tty
->count
== 1) {
188 del_timer(&srmconsp
->timer
);
191 spin_unlock_irqrestore(&port
->lock
, flags
);
195 static struct tty_driver
*srmcons_driver
;
197 static const struct tty_operations srmcons_ops
= {
198 .open
= srmcons_open
,
199 .close
= srmcons_close
,
200 .write
= srmcons_write
,
201 .write_room
= srmcons_write_room
,
202 .chars_in_buffer
= srmcons_chars_in_buffer
,
208 setup_timer(&srmcons_singleton
.timer
, srmcons_receive_chars
,
209 (unsigned long)&srmcons_singleton
);
210 if (srm_is_registered_console
) {
211 struct tty_driver
*driver
;
214 driver
= alloc_tty_driver(MAX_SRM_CONSOLE_DEVICES
);
218 tty_port_init(&srmcons_singleton
.port
);
220 driver
->driver_name
= "srm";
221 driver
->name
= "srm";
222 driver
->major
= 0; /* dynamic */
223 driver
->minor_start
= 0;
224 driver
->type
= TTY_DRIVER_TYPE_SYSTEM
;
225 driver
->subtype
= SYSTEM_TYPE_SYSCONS
;
226 driver
->init_termios
= tty_std_termios
;
227 tty_set_operations(driver
, &srmcons_ops
);
228 tty_port_link_device(&srmcons_singleton
.port
, driver
, 0);
229 err
= tty_register_driver(driver
);
231 put_tty_driver(driver
);
232 tty_port_destroy(&srmcons_singleton
.port
);
235 srmcons_driver
= driver
;
240 device_initcall(srmcons_init
);
247 srm_console_write(struct console
*co
, const char *s
, unsigned count
)
251 spin_lock_irqsave(&srmcons_callback_lock
, flags
);
252 srmcons_do_write(NULL
, s
, count
);
253 spin_unlock_irqrestore(&srmcons_callback_lock
, flags
);
256 static struct tty_driver
*
257 srm_console_device(struct console
*co
, int *index
)
260 return srmcons_driver
;
264 srm_console_setup(struct console
*co
, char *options
)
269 static struct console srmcons
= {
271 .write
= srm_console_write
,
272 .device
= srm_console_device
,
273 .setup
= srm_console_setup
,
274 .flags
= CON_PRINTBUFFER
| CON_BOOT
,
279 register_srm_console(void)
281 if (!srm_is_registered_console
) {
282 callback_open_console();
283 register_console(&srmcons
);
284 srm_is_registered_console
= 1;
289 unregister_srm_console(void)
291 if (srm_is_registered_console
) {
292 callback_close_console();
293 unregister_console(&srmcons
);
294 srm_is_registered_console
= 0;