From cfe6b7c79daa0efa27f474f1fe2a88fd7af5cc47 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Sep 2011 19:45:42 -0400 Subject: [PATCH] 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 Signed-off-by: Richard Weinberger --- arch/um/drivers/line.c | 37 +++++++++++++++++++++++-------------- arch/um/drivers/line.h | 9 +++++---- arch/um/drivers/ssl.c | 17 ++++++----------- arch/um/drivers/stdio_console.c | 19 ++++++------------- 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 1a8d659..015209a 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -485,6 +485,7 @@ static int setup_one_line(struct line *lines, int n, char *init, const struct chan_opts *opts, char **error_out) { struct line *line = &lines[n]; + struct tty_driver *driver = line->driver->driver; int err = -EINVAL; mutex_lock(&line->count_lock); @@ -498,6 +499,7 @@ static int setup_one_line(struct line *lines, int n, char *init, if (line->valid) { line->valid = 0; kfree(line->init_str); + tty_unregister_device(driver, n); parse_chan_pair(NULL, line, n, opts, error_out); err = 0; } @@ -507,9 +509,19 @@ static int setup_one_line(struct line *lines, int n, char *init, *error_out = "Failed to allocate memory"; return -ENOMEM; } + if (line->valid) + tty_unregister_device(driver, n); line->init_str = new; line->valid = 1; 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) { line->init_str = NULL; 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); } -struct tty_driver *register_lines(struct line_driver *line_driver, - const struct tty_operations *ops, - struct line *lines, int nlines) +int register_lines(struct line_driver *line_driver, + const struct tty_operations *ops, + struct line *lines, int nlines) { - int i; struct tty_driver *driver = alloc_tty_driver(nlines); + int err; if (!driver) - return NULL; + return -ENOMEM; driver->driver_name = line_driver->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->type = line_driver->type; 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; 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", line_driver->name); put_tty_driver(driver); - return NULL; - } - - for(i = 0; i < nlines; i++) { - if (!lines[i].valid) - tty_unregister_device(driver, i); + return err; } + line_driver->driver = driver; mconsole_register_dev(&line_driver->mc); - return driver; + return 0; } static DEFINE_SPINLOCK(winch_handler_lock); diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 471f477..e3f8606 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -15,7 +15,7 @@ #include "chan_user.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 { const char *name; const char *device_name; @@ -28,6 +28,7 @@ struct line_driver { const int write_irq; const char *write_irq_name; struct mc_device mc; + struct tty_driver *driver; }; 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, void *data); extern void line_close_chan(struct line *line); -extern struct tty_driver *register_lines(struct line_driver *line_driver, - const struct tty_operations *driver, - struct line *lines, int nlines); +extern int register_lines(struct line_driver *line_driver, + const struct tty_operations *driver, + struct line *lines, int nlines); extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); extern void close_lines(struct line *lines, int nlines); diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 23cffd6..6398a47 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -20,12 +20,6 @@ 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 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) { *index = c->index; - return ssl_driver; + return driver.driver; } static int ssl_console_setup(struct console *co, char *options) @@ -187,6 +181,7 @@ static struct console ssl_cons = { static int ssl_init(void) { char *new_title; + int err; int i; printk(KERN_INFO "Initializing software serial port version %d\n", @@ -196,16 +191,16 @@ static int ssl_init(void) char *s = conf[i]; if (!s) s = def_conf; - if (s && strcmp(s, "none") != 0) { + if (s && strcmp(s, "none") != 0) serial_lines[i].init_str = s; - serial_lines[i].valid = 1; - } spin_lock_init(&serial_lines[i].lock); mutex_init(&serial_lines[i].count_lock); 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)); + if (err) + return err; new_title = add_xterm_umid(opts.xterm_title); if (new_title != NULL) diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index f8d4325..32bd040 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -27,12 +27,6 @@ #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) { 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) { *index = c->index; - return console_driver; + return driver.driver; } static int uml_console_setup(struct console *co, char *options) @@ -160,6 +154,7 @@ static struct console stdiocons = { static int stdio_init(void) { char *new_title; + int err; int i; for (i = 0; i < MAX_TTYS; i++) { @@ -168,18 +163,16 @@ static int stdio_init(void) s = def_conf; if (!s) 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].valid = 1; - } spin_lock_init(&vts[i].lock); mutex_init(&vts[i].count_lock); vts[i].driver = &driver; } - console_driver = register_lines(&driver, &console_ops, vts, + err = register_lines(&driver, &console_ops, vts, ARRAY_SIZE(vts)); - if (console_driver == NULL) - return -1; + if (err) + return err; printk(KERN_INFO "Initialized stdio console driver\n"); new_title = add_xterm_umid(opts.xterm_title); -- 2.7.4