1 // SPDX-License-Identifier: GPL-2.0
3 * linux/arch/alpha/kernel/srmcons.c
5 * Callback based driver for SRM Console console device.
6 * (TTY driver and console driver)
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/console.h>
12 #include <linux/delay.h>
14 #include <linux/slab.h>
15 #include <linux/spinlock.h>
16 #include <linux/timer.h>
17 #include <linux/tty.h>
18 #include <linux/tty_driver.h>
19 #include <linux/tty_flip.h>
21 #include <asm/console.h>
22 #include <linux/uaccess.h>
25 static DEFINE_SPINLOCK(srmcons_callback_lock
);
26 static int srm_is_registered_console
= 0;
31 #define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */
33 struct srmcons_private
{
35 struct timer_list timer
;
38 typedef union _srmcons_result
{
41 unsigned long status
:3;
46 /* called with callback_lock held */
48 srmcons_do_receive_chars(struct tty_port
*port
)
50 srmcons_result result
;
51 int count
= 0, loops
= 0;
54 result
.as_long
= callback_getc(0);
55 if (result
.bits
.status
< 2) {
56 tty_insert_flip_char(port
, (char)result
.bits
.c
, 0);
59 } while((result
.bits
.status
& 1) && (++loops
< 10));
62 tty_schedule_flip(port
);
68 srmcons_receive_chars(struct timer_list
*t
)
70 struct srmcons_private
*srmconsp
= from_timer(srmconsp
, t
, timer
);
71 struct tty_port
*port
= &srmconsp
->port
;
75 local_irq_save(flags
);
76 if (spin_trylock(&srmcons_callback_lock
)) {
77 if (!srmcons_do_receive_chars(port
))
79 spin_unlock(&srmcons_callback_lock
);
82 spin_lock(&port
->lock
);
84 mod_timer(&srmconsp
->timer
, jiffies
+ incr
);
85 spin_unlock(&port
->lock
);
87 local_irq_restore(flags
);
90 /* called with callback_lock held */
92 srmcons_do_write(struct tty_port
*port
, const char *buf
, int count
)
94 static char str_cr
[1] = "\r";
95 long c
, remaining
= count
;
96 srmcons_result result
;
100 for (cur
= (char *)buf
; remaining
> 0; ) {
103 * Break it up into reasonable size chunks to allow a chance
104 * for input to get in
106 for (c
= 0; c
< min_t(long, 128L, remaining
) && !need_cr
; c
++)
111 result
.as_long
= callback_puts(0, cur
, c
);
113 remaining
-= result
.bits
.c
;
114 cur
+= result
.bits
.c
;
117 * Check for pending input iff a tty port was provided
120 srmcons_do_receive_chars(port
);
124 result
.as_long
= callback_puts(0, str_cr
, 1);
125 if (result
.bits
.c
> 0)
133 srmcons_write(struct tty_struct
*tty
,
134 const unsigned char *buf
, int count
)
138 spin_lock_irqsave(&srmcons_callback_lock
, flags
);
139 srmcons_do_write(tty
->port
, (const char *) buf
, count
);
140 spin_unlock_irqrestore(&srmcons_callback_lock
, flags
);
146 srmcons_write_room(struct tty_struct
*tty
)
152 srmcons_chars_in_buffer(struct tty_struct
*tty
)
158 srmcons_open(struct tty_struct
*tty
, struct file
*filp
)
160 struct srmcons_private
*srmconsp
= &srmcons_singleton
;
161 struct tty_port
*port
= &srmconsp
->port
;
164 spin_lock_irqsave(&port
->lock
, flags
);
167 tty
->driver_data
= srmconsp
;
169 port
->tty
= tty
; /* XXX proper refcounting */
170 mod_timer(&srmconsp
->timer
, jiffies
+ 10);
173 spin_unlock_irqrestore(&port
->lock
, flags
);
179 srmcons_close(struct tty_struct
*tty
, struct file
*filp
)
181 struct srmcons_private
*srmconsp
= tty
->driver_data
;
182 struct tty_port
*port
= &srmconsp
->port
;
185 spin_lock_irqsave(&port
->lock
, flags
);
187 if (tty
->count
== 1) {
189 del_timer(&srmconsp
->timer
);
192 spin_unlock_irqrestore(&port
->lock
, flags
);
196 static struct tty_driver
*srmcons_driver
;
198 static const struct tty_operations srmcons_ops
= {
199 .open
= srmcons_open
,
200 .close
= srmcons_close
,
201 .write
= srmcons_write
,
202 .write_room
= srmcons_write_room
,
203 .chars_in_buffer
= srmcons_chars_in_buffer
,
209 timer_setup(&srmcons_singleton
.timer
, srmcons_receive_chars
, 0);
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;