mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
4.9 KiB
205 lines
4.9 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* Copyright (C) 2000, 2002 Jeff Dike ([email protected]) |
|
*/ |
|
|
|
#include <linux/fs.h> |
|
#include <linux/tty.h> |
|
#include <linux/tty_driver.h> |
|
#include <linux/major.h> |
|
#include <linux/mm.h> |
|
#include <linux/init.h> |
|
#include <linux/console.h> |
|
#include <asm/termbits.h> |
|
#include <asm/irq.h> |
|
#include "chan.h" |
|
#include <init.h> |
|
#include <irq_user.h> |
|
#include "mconsole_kern.h" |
|
|
|
static const int ssl_version = 1; |
|
|
|
#define NR_PORTS 64 |
|
|
|
static void ssl_announce(char *dev_name, int dev) |
|
{ |
|
printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev, |
|
dev_name); |
|
} |
|
|
|
/* Almost const, except that xterm_title may be changed in an initcall */ |
|
static struct chan_opts opts = { |
|
.announce = ssl_announce, |
|
.xterm_title = "Serial Line #%d", |
|
.raw = 1, |
|
}; |
|
|
|
static int ssl_config(char *str, char **error_out); |
|
static int ssl_get_config(char *dev, char *str, int size, char **error_out); |
|
static int ssl_remove(int n, char **error_out); |
|
|
|
|
|
/* Const, except for .mc.list */ |
|
static struct line_driver driver = { |
|
.name = "UML serial line", |
|
.device_name = "ttyS", |
|
.major = TTY_MAJOR, |
|
.minor_start = 64, |
|
.type = TTY_DRIVER_TYPE_SERIAL, |
|
.subtype = 0, |
|
.read_irq = SSL_IRQ, |
|
.read_irq_name = "ssl", |
|
.write_irq = SSL_WRITE_IRQ, |
|
.write_irq_name = "ssl-write", |
|
.mc = { |
|
.list = LIST_HEAD_INIT(driver.mc.list), |
|
.name = "ssl", |
|
.config = ssl_config, |
|
.get_config = ssl_get_config, |
|
.id = line_id, |
|
.remove = ssl_remove, |
|
}, |
|
}; |
|
|
|
/* The array is initialized by line_init, at initcall time. The |
|
* elements are locked individually as needed. |
|
*/ |
|
static char *conf[NR_PORTS]; |
|
static char *def_conf = CONFIG_SSL_CHAN; |
|
static struct line serial_lines[NR_PORTS]; |
|
|
|
static int ssl_config(char *str, char **error_out) |
|
{ |
|
return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts, |
|
error_out); |
|
} |
|
|
|
static int ssl_get_config(char *dev, char *str, int size, char **error_out) |
|
{ |
|
return line_get_config(dev, serial_lines, ARRAY_SIZE(serial_lines), str, |
|
size, error_out); |
|
} |
|
|
|
static int ssl_remove(int n, char **error_out) |
|
{ |
|
return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n, |
|
error_out); |
|
} |
|
|
|
static int ssl_install(struct tty_driver *driver, struct tty_struct *tty) |
|
{ |
|
return line_install(driver, tty, &serial_lines[tty->index]); |
|
} |
|
|
|
static const struct tty_operations ssl_ops = { |
|
.open = line_open, |
|
.close = line_close, |
|
.write = line_write, |
|
.write_room = line_write_room, |
|
.chars_in_buffer = line_chars_in_buffer, |
|
.flush_buffer = line_flush_buffer, |
|
.flush_chars = line_flush_chars, |
|
.set_termios = line_set_termios, |
|
.throttle = line_throttle, |
|
.unthrottle = line_unthrottle, |
|
.install = ssl_install, |
|
.hangup = line_hangup, |
|
}; |
|
|
|
/* Changed by ssl_init and referenced by ssl_exit, which are both serialized |
|
* by being an initcall and exitcall, respectively. |
|
*/ |
|
static int ssl_init_done = 0; |
|
|
|
static void ssl_console_write(struct console *c, const char *string, |
|
unsigned len) |
|
{ |
|
struct line *line = &serial_lines[c->index]; |
|
unsigned long flags; |
|
|
|
spin_lock_irqsave(&line->lock, flags); |
|
console_write_chan(line->chan_out, string, len); |
|
spin_unlock_irqrestore(&line->lock, flags); |
|
} |
|
|
|
static struct tty_driver *ssl_console_device(struct console *c, int *index) |
|
{ |
|
*index = c->index; |
|
return driver.driver; |
|
} |
|
|
|
static int ssl_console_setup(struct console *co, char *options) |
|
{ |
|
struct line *line = &serial_lines[co->index]; |
|
|
|
return console_open_chan(line, co); |
|
} |
|
|
|
/* No locking for register_console call - relies on single-threaded initcalls */ |
|
static struct console ssl_cons = { |
|
.name = "ttyS", |
|
.write = ssl_console_write, |
|
.device = ssl_console_device, |
|
.setup = ssl_console_setup, |
|
.flags = CON_PRINTBUFFER|CON_ANYTIME, |
|
.index = -1, |
|
}; |
|
|
|
static int ssl_init(void) |
|
{ |
|
char *new_title; |
|
int err; |
|
int i; |
|
|
|
printk(KERN_INFO "Initializing software serial port version %d\n", |
|
ssl_version); |
|
|
|
err = register_lines(&driver, &ssl_ops, serial_lines, |
|
ARRAY_SIZE(serial_lines)); |
|
if (err) |
|
return err; |
|
|
|
new_title = add_xterm_umid(opts.xterm_title); |
|
if (new_title != NULL) |
|
opts.xterm_title = new_title; |
|
|
|
for (i = 0; i < NR_PORTS; i++) { |
|
char *error; |
|
char *s = conf[i]; |
|
if (!s) |
|
s = def_conf; |
|
if (setup_one_line(serial_lines, i, s, &opts, &error)) |
|
printk(KERN_ERR "setup_one_line failed for " |
|
"device %d : %s\n", i, error); |
|
} |
|
|
|
ssl_init_done = 1; |
|
register_console(&ssl_cons); |
|
return 0; |
|
} |
|
late_initcall(ssl_init); |
|
|
|
static void ssl_exit(void) |
|
{ |
|
if (!ssl_init_done) |
|
return; |
|
close_lines(serial_lines, ARRAY_SIZE(serial_lines)); |
|
} |
|
__uml_exitcall(ssl_exit); |
|
|
|
static int ssl_chan_setup(char *str) |
|
{ |
|
line_setup(conf, NR_PORTS, &def_conf, str, "serial line"); |
|
return 1; |
|
} |
|
|
|
__setup("ssl", ssl_chan_setup); |
|
__channel_help(ssl_chan_setup, "ssl"); |
|
|
|
static int ssl_non_raw_setup(char *str) |
|
{ |
|
opts.raw = 0; |
|
return 1; |
|
} |
|
__setup("ssl-non-raw", ssl_non_raw_setup); |
|
__channel_help(ssl_non_raw_setup, "set serial lines to non-raw mode");
|
|
|