root/arch/alpha/kernel/srmcons.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. srmcons_do_receive_chars
  2. srmcons_receive_chars
  3. srmcons_do_write
  4. srmcons_write
  5. srmcons_write_room
  6. srmcons_chars_in_buffer
  7. srmcons_open
  8. srmcons_close
  9. srmcons_init
  10. srm_console_write
  11. srm_console_device
  12. srm_console_setup
  13. register_srm_console
  14. unregister_srm_console

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *      linux/arch/alpha/kernel/srmcons.c
   4  *
   5  * Callback based driver for SRM Console console device.
   6  * (TTY driver and console driver)
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/init.h>
  11 #include <linux/console.h>
  12 #include <linux/delay.h>
  13 #include <linux/mm.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>
  20 
  21 #include <asm/console.h>
  22 #include <linux/uaccess.h>
  23 
  24 
  25 static DEFINE_SPINLOCK(srmcons_callback_lock);
  26 static int srm_is_registered_console = 0;
  27 
  28 /* 
  29  * The TTY driver
  30  */
  31 #define MAX_SRM_CONSOLE_DEVICES 1       /* only support 1 console device */
  32 
  33 struct srmcons_private {
  34         struct tty_port port;
  35         struct timer_list timer;
  36 } srmcons_singleton;
  37 
  38 typedef union _srmcons_result {
  39         struct {
  40                 unsigned long c :61;
  41                 unsigned long status :3;
  42         } bits;
  43         long as_long;
  44 } srmcons_result;
  45 
  46 /* called with callback_lock held */
  47 static int
  48 srmcons_do_receive_chars(struct tty_port *port)
  49 {
  50         srmcons_result result;
  51         int count = 0, loops = 0;
  52 
  53         do {
  54                 result.as_long = callback_getc(0);
  55                 if (result.bits.status < 2) {
  56                         tty_insert_flip_char(port, (char)result.bits.c, 0);
  57                         count++;
  58                 }
  59         } while((result.bits.status & 1) && (++loops < 10));
  60 
  61         if (count)
  62                 tty_schedule_flip(port);
  63 
  64         return count;
  65 }
  66 
  67 static void
  68 srmcons_receive_chars(struct timer_list *t)
  69 {
  70         struct srmcons_private *srmconsp = from_timer(srmconsp, t, timer);
  71         struct tty_port *port = &srmconsp->port;
  72         unsigned long flags;
  73         int incr = 10;
  74 
  75         local_irq_save(flags);
  76         if (spin_trylock(&srmcons_callback_lock)) {
  77                 if (!srmcons_do_receive_chars(port))
  78                         incr = 100;
  79                 spin_unlock(&srmcons_callback_lock);
  80         } 
  81 
  82         spin_lock(&port->lock);
  83         if (port->tty)
  84                 mod_timer(&srmconsp->timer, jiffies + incr);
  85         spin_unlock(&port->lock);
  86 
  87         local_irq_restore(flags);
  88 }
  89 
  90 /* called with callback_lock held */
  91 static int
  92 srmcons_do_write(struct tty_port *port, const char *buf, int count)
  93 {
  94         static char str_cr[1] = "\r";
  95         long c, remaining = count;
  96         srmcons_result result;
  97         char *cur;
  98         int need_cr;
  99 
 100         for (cur = (char *)buf; remaining > 0; ) {
 101                 need_cr = 0;
 102                 /* 
 103                  * Break it up into reasonable size chunks to allow a chance
 104                  * for input to get in
 105                  */
 106                 for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
 107                         if (cur[c] == '\n')
 108                                 need_cr = 1;
 109                 
 110                 while (c > 0) {
 111                         result.as_long = callback_puts(0, cur, c);
 112                         c -= result.bits.c;
 113                         remaining -= result.bits.c;
 114                         cur += result.bits.c;
 115 
 116                         /*
 117                          * Check for pending input iff a tty port was provided
 118                          */
 119                         if (port)
 120                                 srmcons_do_receive_chars(port);
 121                 }
 122 
 123                 while (need_cr) {
 124                         result.as_long = callback_puts(0, str_cr, 1);
 125                         if (result.bits.c > 0)
 126                                 need_cr = 0;
 127                 }
 128         }
 129         return count;
 130 }
 131 
 132 static int
 133 srmcons_write(struct tty_struct *tty,
 134               const unsigned char *buf, int count)
 135 {
 136         unsigned long flags;
 137 
 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);
 141 
 142         return count;
 143 }
 144 
 145 static int
 146 srmcons_write_room(struct tty_struct *tty)
 147 {
 148         return 512;
 149 }
 150 
 151 static int
 152 srmcons_chars_in_buffer(struct tty_struct *tty)
 153 {
 154         return 0;
 155 }
 156 
 157 static int
 158 srmcons_open(struct tty_struct *tty, struct file *filp)
 159 {
 160         struct srmcons_private *srmconsp = &srmcons_singleton;
 161         struct tty_port *port = &srmconsp->port;
 162         unsigned long flags;
 163 
 164         spin_lock_irqsave(&port->lock, flags);
 165 
 166         if (!port->tty) {
 167                 tty->driver_data = srmconsp;
 168                 tty->port = port;
 169                 port->tty = tty; /* XXX proper refcounting */
 170                 mod_timer(&srmconsp->timer, jiffies + 10);
 171         }
 172 
 173         spin_unlock_irqrestore(&port->lock, flags);
 174 
 175         return 0;
 176 }
 177 
 178 static void
 179 srmcons_close(struct tty_struct *tty, struct file *filp)
 180 {
 181         struct srmcons_private *srmconsp = tty->driver_data;
 182         struct tty_port *port = &srmconsp->port;
 183         unsigned long flags;
 184 
 185         spin_lock_irqsave(&port->lock, flags);
 186 
 187         if (tty->count == 1) {
 188                 port->tty = NULL;
 189                 del_timer(&srmconsp->timer);
 190         }
 191 
 192         spin_unlock_irqrestore(&port->lock, flags);
 193 }
 194 
 195 
 196 static struct tty_driver *srmcons_driver;
 197 
 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,
 204 };
 205 
 206 static int __init
 207 srmcons_init(void)
 208 {
 209         timer_setup(&srmcons_singleton.timer, srmcons_receive_chars, 0);
 210         if (srm_is_registered_console) {
 211                 struct tty_driver *driver;
 212                 int err;
 213 
 214                 driver = alloc_tty_driver(MAX_SRM_CONSOLE_DEVICES);
 215                 if (!driver)
 216                         return -ENOMEM;
 217 
 218                 tty_port_init(&srmcons_singleton.port);
 219 
 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);
 230                 if (err) {
 231                         put_tty_driver(driver);
 232                         tty_port_destroy(&srmcons_singleton.port);
 233                         return err;
 234                 }
 235                 srmcons_driver = driver;
 236         }
 237 
 238         return -ENODEV;
 239 }
 240 device_initcall(srmcons_init);
 241 
 242 
 243 /*
 244  * The console driver
 245  */
 246 static void
 247 srm_console_write(struct console *co, const char *s, unsigned count)
 248 {
 249         unsigned long flags;
 250 
 251         spin_lock_irqsave(&srmcons_callback_lock, flags);
 252         srmcons_do_write(NULL, s, count);
 253         spin_unlock_irqrestore(&srmcons_callback_lock, flags);
 254 }
 255 
 256 static struct tty_driver *
 257 srm_console_device(struct console *co, int *index)
 258 {
 259         *index = co->index;
 260         return srmcons_driver;
 261 }
 262 
 263 static int
 264 srm_console_setup(struct console *co, char *options)
 265 {
 266         return 0;
 267 }
 268 
 269 static struct console srmcons = {
 270         .name           = "srm",
 271         .write          = srm_console_write,
 272         .device         = srm_console_device,
 273         .setup          = srm_console_setup,
 274         .flags          = CON_PRINTBUFFER | CON_BOOT,
 275         .index          = -1,
 276 };
 277 
 278 void __init
 279 register_srm_console(void)
 280 {
 281         if (!srm_is_registered_console) {
 282                 callback_open_console();
 283                 register_console(&srmcons);
 284                 srm_is_registered_console = 1;
 285         }
 286 }
 287 
 288 void __init
 289 unregister_srm_console(void)
 290 {
 291         if (srm_is_registered_console) {
 292                 callback_close_console();
 293                 unregister_console(&srmcons);
 294                 srm_is_registered_console = 0;
 295         }
 296 }

/* [<][>][^][v][top][bottom][index][help] */