mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 15:20:41 +00:00
um: switch line.c tty drivers to dynamic device creation
Current code doesn't update the symlinks in /sys/dev/char when we add/remove tty lines. Fixing that allows to stop messing with ->valid before the driver registration, which is a Good Thing(tm) - we shouldn't have it set before we really have the things set up and ready for line_open(). We need tty_driver available to call tty_{un,}register_device(), so we just stash a reference to it into struct line_driver. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
31efcebb7d
commit
cfe6b7c79d
4 changed files with 40 additions and 42 deletions
|
@ -485,6 +485,7 @@ static int setup_one_line(struct line *lines, int n, char *init,
|
||||||
const struct chan_opts *opts, char **error_out)
|
const struct chan_opts *opts, char **error_out)
|
||||||
{
|
{
|
||||||
struct line *line = &lines[n];
|
struct line *line = &lines[n];
|
||||||
|
struct tty_driver *driver = line->driver->driver;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&line->count_lock);
|
mutex_lock(&line->count_lock);
|
||||||
|
@ -498,6 +499,7 @@ static int setup_one_line(struct line *lines, int n, char *init,
|
||||||
if (line->valid) {
|
if (line->valid) {
|
||||||
line->valid = 0;
|
line->valid = 0;
|
||||||
kfree(line->init_str);
|
kfree(line->init_str);
|
||||||
|
tty_unregister_device(driver, n);
|
||||||
parse_chan_pair(NULL, line, n, opts, error_out);
|
parse_chan_pair(NULL, line, n, opts, error_out);
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
@ -507,9 +509,19 @@ static int setup_one_line(struct line *lines, int n, char *init,
|
||||||
*error_out = "Failed to allocate memory";
|
*error_out = "Failed to allocate memory";
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
if (line->valid)
|
||||||
|
tty_unregister_device(driver, n);
|
||||||
line->init_str = new;
|
line->init_str = new;
|
||||||
line->valid = 1;
|
line->valid = 1;
|
||||||
err = parse_chan_pair(new, line, n, opts, error_out);
|
err = parse_chan_pair(new, line, n, opts, error_out);
|
||||||
|
if (!err) {
|
||||||
|
struct device *d = tty_register_device(driver, n, NULL);
|
||||||
|
if (IS_ERR(d)) {
|
||||||
|
*error_out = "Failed to register device";
|
||||||
|
err = PTR_ERR(d);
|
||||||
|
parse_chan_pair(NULL, line, n, opts, error_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
line->init_str = NULL;
|
line->init_str = NULL;
|
||||||
line->valid = 0;
|
line->valid = 0;
|
||||||
|
@ -640,15 +652,15 @@ int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
|
||||||
return setup_one_line(lines, n, "none", NULL, error_out);
|
return setup_one_line(lines, n, "none", NULL, error_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tty_driver *register_lines(struct line_driver *line_driver,
|
int register_lines(struct line_driver *line_driver,
|
||||||
const struct tty_operations *ops,
|
const struct tty_operations *ops,
|
||||||
struct line *lines, int nlines)
|
struct line *lines, int nlines)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct tty_driver *driver = alloc_tty_driver(nlines);
|
struct tty_driver *driver = alloc_tty_driver(nlines);
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!driver)
|
if (!driver)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
|
|
||||||
driver->driver_name = line_driver->name;
|
driver->driver_name = line_driver->name;
|
||||||
driver->name = line_driver->device_name;
|
driver->name = line_driver->device_name;
|
||||||
|
@ -656,24 +668,21 @@ struct tty_driver *register_lines(struct line_driver *line_driver,
|
||||||
driver->minor_start = line_driver->minor_start;
|
driver->minor_start = line_driver->minor_start;
|
||||||
driver->type = line_driver->type;
|
driver->type = line_driver->type;
|
||||||
driver->subtype = line_driver->subtype;
|
driver->subtype = line_driver->subtype;
|
||||||
driver->flags = TTY_DRIVER_REAL_RAW;
|
driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||||
driver->init_termios = tty_std_termios;
|
driver->init_termios = tty_std_termios;
|
||||||
tty_set_operations(driver, ops);
|
tty_set_operations(driver, ops);
|
||||||
|
|
||||||
if (tty_register_driver(driver)) {
|
err = tty_register_driver(driver);
|
||||||
|
if (err) {
|
||||||
printk(KERN_ERR "register_lines : can't register %s driver\n",
|
printk(KERN_ERR "register_lines : can't register %s driver\n",
|
||||||
line_driver->name);
|
line_driver->name);
|
||||||
put_tty_driver(driver);
|
put_tty_driver(driver);
|
||||||
return NULL;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < nlines; i++) {
|
|
||||||
if (!lines[i].valid)
|
|
||||||
tty_unregister_device(driver, i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line_driver->driver = driver;
|
||||||
mconsole_register_dev(&line_driver->mc);
|
mconsole_register_dev(&line_driver->mc);
|
||||||
return driver;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(winch_handler_lock);
|
static DEFINE_SPINLOCK(winch_handler_lock);
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "chan_user.h"
|
#include "chan_user.h"
|
||||||
#include "mconsole_kern.h"
|
#include "mconsole_kern.h"
|
||||||
|
|
||||||
/* There's only one modifiable field in this - .mc.list */
|
/* There's only two modifiable fields in this - .mc.list and .driver */
|
||||||
struct line_driver {
|
struct line_driver {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *device_name;
|
const char *device_name;
|
||||||
|
@ -28,6 +28,7 @@ struct line_driver {
|
||||||
const int write_irq;
|
const int write_irq;
|
||||||
const char *write_irq_name;
|
const char *write_irq_name;
|
||||||
struct mc_device mc;
|
struct mc_device mc;
|
||||||
|
struct tty_driver *driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct line {
|
struct line {
|
||||||
|
@ -78,9 +79,9 @@ extern char *add_xterm_umid(char *base);
|
||||||
extern int line_setup_irq(int fd, int input, int output, struct line *line,
|
extern int line_setup_irq(int fd, int input, int output, struct line *line,
|
||||||
void *data);
|
void *data);
|
||||||
extern void line_close_chan(struct line *line);
|
extern void line_close_chan(struct line *line);
|
||||||
extern struct tty_driver *register_lines(struct line_driver *line_driver,
|
extern int register_lines(struct line_driver *line_driver,
|
||||||
const struct tty_operations *driver,
|
const struct tty_operations *driver,
|
||||||
struct line *lines, int nlines);
|
struct line *lines, int nlines);
|
||||||
extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
|
extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
|
||||||
extern void close_lines(struct line *lines, int nlines);
|
extern void close_lines(struct line *lines, int nlines);
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,6 @@
|
||||||
|
|
||||||
static const int ssl_version = 1;
|
static const int ssl_version = 1;
|
||||||
|
|
||||||
/* Referenced only by tty_driver below - presumably it's locked correctly
|
|
||||||
* by the tty driver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static struct tty_driver *ssl_driver;
|
|
||||||
|
|
||||||
#define NR_PORTS 64
|
#define NR_PORTS 64
|
||||||
|
|
||||||
static void ssl_announce(char *dev_name, int dev)
|
static void ssl_announce(char *dev_name, int dev)
|
||||||
|
@ -164,7 +158,7 @@ static void ssl_console_write(struct console *c, const char *string,
|
||||||
static struct tty_driver *ssl_console_device(struct console *c, int *index)
|
static struct tty_driver *ssl_console_device(struct console *c, int *index)
|
||||||
{
|
{
|
||||||
*index = c->index;
|
*index = c->index;
|
||||||
return ssl_driver;
|
return driver.driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ssl_console_setup(struct console *co, char *options)
|
static int ssl_console_setup(struct console *co, char *options)
|
||||||
|
@ -187,6 +181,7 @@ static struct console ssl_cons = {
|
||||||
static int ssl_init(void)
|
static int ssl_init(void)
|
||||||
{
|
{
|
||||||
char *new_title;
|
char *new_title;
|
||||||
|
int err;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printk(KERN_INFO "Initializing software serial port version %d\n",
|
printk(KERN_INFO "Initializing software serial port version %d\n",
|
||||||
|
@ -196,16 +191,16 @@ static int ssl_init(void)
|
||||||
char *s = conf[i];
|
char *s = conf[i];
|
||||||
if (!s)
|
if (!s)
|
||||||
s = def_conf;
|
s = def_conf;
|
||||||
if (s && strcmp(s, "none") != 0) {
|
if (s && strcmp(s, "none") != 0)
|
||||||
serial_lines[i].init_str = s;
|
serial_lines[i].init_str = s;
|
||||||
serial_lines[i].valid = 1;
|
|
||||||
}
|
|
||||||
spin_lock_init(&serial_lines[i].lock);
|
spin_lock_init(&serial_lines[i].lock);
|
||||||
mutex_init(&serial_lines[i].count_lock);
|
mutex_init(&serial_lines[i].count_lock);
|
||||||
serial_lines[i].driver = &driver;
|
serial_lines[i].driver = &driver;
|
||||||
}
|
}
|
||||||
ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
|
err = register_lines(&driver, &ssl_ops, serial_lines,
|
||||||
ARRAY_SIZE(serial_lines));
|
ARRAY_SIZE(serial_lines));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
new_title = add_xterm_umid(opts.xterm_title);
|
new_title = add_xterm_umid(opts.xterm_title);
|
||||||
if (new_title != NULL)
|
if (new_title != NULL)
|
||||||
|
|
|
@ -27,12 +27,6 @@
|
||||||
|
|
||||||
#define MAX_TTYS (16)
|
#define MAX_TTYS (16)
|
||||||
|
|
||||||
/* Referenced only by tty_driver below - presumably it's locked correctly
|
|
||||||
* by the tty driver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static struct tty_driver *console_driver;
|
|
||||||
|
|
||||||
static void stdio_announce(char *dev_name, int dev)
|
static void stdio_announce(char *dev_name, int dev)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
|
printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
|
||||||
|
@ -137,7 +131,7 @@ static void uml_console_write(struct console *console, const char *string,
|
||||||
static struct tty_driver *uml_console_device(struct console *c, int *index)
|
static struct tty_driver *uml_console_device(struct console *c, int *index)
|
||||||
{
|
{
|
||||||
*index = c->index;
|
*index = c->index;
|
||||||
return console_driver;
|
return driver.driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uml_console_setup(struct console *co, char *options)
|
static int uml_console_setup(struct console *co, char *options)
|
||||||
|
@ -160,6 +154,7 @@ static struct console stdiocons = {
|
||||||
static int stdio_init(void)
|
static int stdio_init(void)
|
||||||
{
|
{
|
||||||
char *new_title;
|
char *new_title;
|
||||||
|
int err;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_TTYS; i++) {
|
for (i = 0; i < MAX_TTYS; i++) {
|
||||||
|
@ -168,18 +163,16 @@ static int stdio_init(void)
|
||||||
s = def_conf;
|
s = def_conf;
|
||||||
if (!s)
|
if (!s)
|
||||||
s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN;
|
s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN;
|
||||||
if (s && strcmp(s, "none") != 0) {
|
if (s && strcmp(s, "none") != 0)
|
||||||
vts[i].init_str = s;
|
vts[i].init_str = s;
|
||||||
vts[i].valid = 1;
|
|
||||||
}
|
|
||||||
spin_lock_init(&vts[i].lock);
|
spin_lock_init(&vts[i].lock);
|
||||||
mutex_init(&vts[i].count_lock);
|
mutex_init(&vts[i].count_lock);
|
||||||
vts[i].driver = &driver;
|
vts[i].driver = &driver;
|
||||||
}
|
}
|
||||||
console_driver = register_lines(&driver, &console_ops, vts,
|
err = register_lines(&driver, &console_ops, vts,
|
||||||
ARRAY_SIZE(vts));
|
ARRAY_SIZE(vts));
|
||||||
if (console_driver == NULL)
|
if (err)
|
||||||
return -1;
|
return err;
|
||||||
printk(KERN_INFO "Initialized stdio console driver\n");
|
printk(KERN_INFO "Initialized stdio console driver\n");
|
||||||
|
|
||||||
new_title = add_xterm_umid(opts.xterm_title);
|
new_title = add_xterm_umid(opts.xterm_title);
|
||||||
|
|
Loading…
Reference in a new issue