um: switch line.c tty drivers to dynamic device creation
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 9 Sep 2011 23:45:42 +0000 (19:45 -0400)
committerRichard Weinberger <richard@nod.at>
Sat, 24 Mar 2012 23:29:53 +0000 (00:29 +0100)
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>
arch/um/drivers/line.c
arch/um/drivers/line.h
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c

index 1a8d6591c2044af2f4ba8ec456dca34ce9592020..015209a9881529bd9495460338b048f65adc7994 100644 (file)
@@ -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);
index 471f477b271ed4d57933d50462691566e9d07bb6..e3f86065e0496da9494614c8ef206dbee990b0ad 100644 (file)
@@ -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);
 
index 23cffd6d85af1fed181a6e4b368399dcea89da20..6398a47d035bab6e6a920d2e9111153e6a4be6f3 100644 (file)
 
 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)
index f8d4325b28b73adedc6eb1e429e9f8e0eb2d1171..32bd040138f090ec15341846fd58192d2cf4ab6e 100644 (file)
 
 #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);