diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-09-09 19:45:42 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2012-03-24 19:29:53 -0400 |
commit | cfe6b7c79daa0efa27f474f1fe2a88fd7af5cc47 (patch) | |
tree | 5030f25d83451e3b3e579bac4b9a2e561990048d /arch/um | |
parent | 31efcebb7d7196adcee73027f513d7c0bf572b47 (diff) |
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>
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/drivers/line.c | 37 | ||||
-rw-r--r-- | arch/um/drivers/line.h | 9 | ||||
-rw-r--r-- | arch/um/drivers/ssl.c | 17 | ||||
-rw-r--r-- | 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 1a8d6591c204..015209a98815 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, | |||
485 | const struct chan_opts *opts, char **error_out) | 485 | const struct chan_opts *opts, char **error_out) |
486 | { | 486 | { |
487 | struct line *line = &lines[n]; | 487 | struct line *line = &lines[n]; |
488 | struct tty_driver *driver = line->driver->driver; | ||
488 | int err = -EINVAL; | 489 | int err = -EINVAL; |
489 | 490 | ||
490 | mutex_lock(&line->count_lock); | 491 | mutex_lock(&line->count_lock); |
@@ -498,6 +499,7 @@ static int setup_one_line(struct line *lines, int n, char *init, | |||
498 | if (line->valid) { | 499 | if (line->valid) { |
499 | line->valid = 0; | 500 | line->valid = 0; |
500 | kfree(line->init_str); | 501 | kfree(line->init_str); |
502 | tty_unregister_device(driver, n); | ||
501 | parse_chan_pair(NULL, line, n, opts, error_out); | 503 | parse_chan_pair(NULL, line, n, opts, error_out); |
502 | err = 0; | 504 | err = 0; |
503 | } | 505 | } |
@@ -507,9 +509,19 @@ static int setup_one_line(struct line *lines, int n, char *init, | |||
507 | *error_out = "Failed to allocate memory"; | 509 | *error_out = "Failed to allocate memory"; |
508 | return -ENOMEM; | 510 | return -ENOMEM; |
509 | } | 511 | } |
512 | if (line->valid) | ||
513 | tty_unregister_device(driver, n); | ||
510 | line->init_str = new; | 514 | line->init_str = new; |
511 | line->valid = 1; | 515 | line->valid = 1; |
512 | err = parse_chan_pair(new, line, n, opts, error_out); | 516 | err = parse_chan_pair(new, line, n, opts, error_out); |
517 | if (!err) { | ||
518 | struct device *d = tty_register_device(driver, n, NULL); | ||
519 | if (IS_ERR(d)) { | ||
520 | *error_out = "Failed to register device"; | ||
521 | err = PTR_ERR(d); | ||
522 | parse_chan_pair(NULL, line, n, opts, error_out); | ||
523 | } | ||
524 | } | ||
513 | if (err) { | 525 | if (err) { |
514 | line->init_str = NULL; | 526 | line->init_str = NULL; |
515 | line->valid = 0; | 527 | line->valid = 0; |
@@ -640,15 +652,15 @@ int line_remove(struct line *lines, unsigned int num, int n, char **error_out) | |||
640 | return setup_one_line(lines, n, "none", NULL, error_out); | 652 | return setup_one_line(lines, n, "none", NULL, error_out); |
641 | } | 653 | } |
642 | 654 | ||
643 | struct tty_driver *register_lines(struct line_driver *line_driver, | 655 | int register_lines(struct line_driver *line_driver, |
644 | const struct tty_operations *ops, | 656 | const struct tty_operations *ops, |
645 | struct line *lines, int nlines) | 657 | struct line *lines, int nlines) |
646 | { | 658 | { |
647 | int i; | ||
648 | struct tty_driver *driver = alloc_tty_driver(nlines); | 659 | struct tty_driver *driver = alloc_tty_driver(nlines); |
660 | int err; | ||
649 | 661 | ||
650 | if (!driver) | 662 | if (!driver) |
651 | return NULL; | 663 | return -ENOMEM; |
652 | 664 | ||
653 | driver->driver_name = line_driver->name; | 665 | driver->driver_name = line_driver->name; |
654 | driver->name = line_driver->device_name; | 666 | driver->name = line_driver->device_name; |
@@ -656,24 +668,21 @@ struct tty_driver *register_lines(struct line_driver *line_driver, | |||
656 | driver->minor_start = line_driver->minor_start; | 668 | driver->minor_start = line_driver->minor_start; |
657 | driver->type = line_driver->type; | 669 | driver->type = line_driver->type; |
658 | driver->subtype = line_driver->subtype; | 670 | driver->subtype = line_driver->subtype; |
659 | driver->flags = TTY_DRIVER_REAL_RAW; | 671 | driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
660 | driver->init_termios = tty_std_termios; | 672 | driver->init_termios = tty_std_termios; |
661 | tty_set_operations(driver, ops); | 673 | tty_set_operations(driver, ops); |
662 | 674 | ||
663 | if (tty_register_driver(driver)) { | 675 | err = tty_register_driver(driver); |
676 | if (err) { | ||
664 | printk(KERN_ERR "register_lines : can't register %s driver\n", | 677 | printk(KERN_ERR "register_lines : can't register %s driver\n", |
665 | line_driver->name); | 678 | line_driver->name); |
666 | put_tty_driver(driver); | 679 | put_tty_driver(driver); |
667 | return NULL; | 680 | return err; |
668 | } | ||
669 | |||
670 | for(i = 0; i < nlines; i++) { | ||
671 | if (!lines[i].valid) | ||
672 | tty_unregister_device(driver, i); | ||
673 | } | 681 | } |
674 | 682 | ||
683 | line_driver->driver = driver; | ||
675 | mconsole_register_dev(&line_driver->mc); | 684 | mconsole_register_dev(&line_driver->mc); |
676 | return driver; | 685 | return 0; |
677 | } | 686 | } |
678 | 687 | ||
679 | static DEFINE_SPINLOCK(winch_handler_lock); | 688 | static DEFINE_SPINLOCK(winch_handler_lock); |
diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 471f477b271e..e3f86065e049 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h | |||
@@ -15,7 +15,7 @@ | |||
15 | #include "chan_user.h" | 15 | #include "chan_user.h" |
16 | #include "mconsole_kern.h" | 16 | #include "mconsole_kern.h" |
17 | 17 | ||
18 | /* There's only one modifiable field in this - .mc.list */ | 18 | /* There's only two modifiable fields in this - .mc.list and .driver */ |
19 | struct line_driver { | 19 | struct line_driver { |
20 | const char *name; | 20 | const char *name; |
21 | const char *device_name; | 21 | const char *device_name; |
@@ -28,6 +28,7 @@ struct line_driver { | |||
28 | const int write_irq; | 28 | const int write_irq; |
29 | const char *write_irq_name; | 29 | const char *write_irq_name; |
30 | struct mc_device mc; | 30 | struct mc_device mc; |
31 | struct tty_driver *driver; | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | struct line { | 34 | struct line { |
@@ -78,9 +79,9 @@ extern char *add_xterm_umid(char *base); | |||
78 | extern int line_setup_irq(int fd, int input, int output, struct line *line, | 79 | extern int line_setup_irq(int fd, int input, int output, struct line *line, |
79 | void *data); | 80 | void *data); |
80 | extern void line_close_chan(struct line *line); | 81 | extern void line_close_chan(struct line *line); |
81 | extern struct tty_driver *register_lines(struct line_driver *line_driver, | 82 | extern int register_lines(struct line_driver *line_driver, |
82 | const struct tty_operations *driver, | 83 | const struct tty_operations *driver, |
83 | struct line *lines, int nlines); | 84 | struct line *lines, int nlines); |
84 | extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); | 85 | extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); |
85 | extern void close_lines(struct line *lines, int nlines); | 86 | extern void close_lines(struct line *lines, int nlines); |
86 | 87 | ||
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 23cffd6d85af..6398a47d035b 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c | |||
@@ -20,12 +20,6 @@ | |||
20 | 20 | ||
21 | static const int ssl_version = 1; | 21 | static const int ssl_version = 1; |
22 | 22 | ||
23 | /* Referenced only by tty_driver below - presumably it's locked correctly | ||
24 | * by the tty driver. | ||
25 | */ | ||
26 | |||
27 | static struct tty_driver *ssl_driver; | ||
28 | |||
29 | #define NR_PORTS 64 | 23 | #define NR_PORTS 64 |
30 | 24 | ||
31 | static void ssl_announce(char *dev_name, int dev) | 25 | static void ssl_announce(char *dev_name, int dev) |
@@ -164,7 +158,7 @@ static void ssl_console_write(struct console *c, const char *string, | |||
164 | static struct tty_driver *ssl_console_device(struct console *c, int *index) | 158 | static struct tty_driver *ssl_console_device(struct console *c, int *index) |
165 | { | 159 | { |
166 | *index = c->index; | 160 | *index = c->index; |
167 | return ssl_driver; | 161 | return driver.driver; |
168 | } | 162 | } |
169 | 163 | ||
170 | static int ssl_console_setup(struct console *co, char *options) | 164 | static int ssl_console_setup(struct console *co, char *options) |
@@ -187,6 +181,7 @@ static struct console ssl_cons = { | |||
187 | static int ssl_init(void) | 181 | static int ssl_init(void) |
188 | { | 182 | { |
189 | char *new_title; | 183 | char *new_title; |
184 | int err; | ||
190 | int i; | 185 | int i; |
191 | 186 | ||
192 | printk(KERN_INFO "Initializing software serial port version %d\n", | 187 | printk(KERN_INFO "Initializing software serial port version %d\n", |
@@ -196,16 +191,16 @@ static int ssl_init(void) | |||
196 | char *s = conf[i]; | 191 | char *s = conf[i]; |
197 | if (!s) | 192 | if (!s) |
198 | s = def_conf; | 193 | s = def_conf; |
199 | if (s && strcmp(s, "none") != 0) { | 194 | if (s && strcmp(s, "none") != 0) |
200 | serial_lines[i].init_str = s; | 195 | serial_lines[i].init_str = s; |
201 | serial_lines[i].valid = 1; | ||
202 | } | ||
203 | spin_lock_init(&serial_lines[i].lock); | 196 | spin_lock_init(&serial_lines[i].lock); |
204 | mutex_init(&serial_lines[i].count_lock); | 197 | mutex_init(&serial_lines[i].count_lock); |
205 | serial_lines[i].driver = &driver; | 198 | serial_lines[i].driver = &driver; |
206 | } | 199 | } |
207 | ssl_driver = register_lines(&driver, &ssl_ops, serial_lines, | 200 | err = register_lines(&driver, &ssl_ops, serial_lines, |
208 | ARRAY_SIZE(serial_lines)); | 201 | ARRAY_SIZE(serial_lines)); |
202 | if (err) | ||
203 | return err; | ||
209 | 204 | ||
210 | new_title = add_xterm_umid(opts.xterm_title); | 205 | new_title = add_xterm_umid(opts.xterm_title); |
211 | if (new_title != NULL) | 206 | if (new_title != NULL) |
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index f8d4325b28b7..32bd040138f0 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c | |||
@@ -27,12 +27,6 @@ | |||
27 | 27 | ||
28 | #define MAX_TTYS (16) | 28 | #define MAX_TTYS (16) |
29 | 29 | ||
30 | /* Referenced only by tty_driver below - presumably it's locked correctly | ||
31 | * by the tty driver. | ||
32 | */ | ||
33 | |||
34 | static struct tty_driver *console_driver; | ||
35 | |||
36 | static void stdio_announce(char *dev_name, int dev) | 30 | static void stdio_announce(char *dev_name, int dev) |
37 | { | 31 | { |
38 | printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, | 32 | 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, | |||
137 | static struct tty_driver *uml_console_device(struct console *c, int *index) | 131 | static struct tty_driver *uml_console_device(struct console *c, int *index) |
138 | { | 132 | { |
139 | *index = c->index; | 133 | *index = c->index; |
140 | return console_driver; | 134 | return driver.driver; |
141 | } | 135 | } |
142 | 136 | ||
143 | static int uml_console_setup(struct console *co, char *options) | 137 | static int uml_console_setup(struct console *co, char *options) |
@@ -160,6 +154,7 @@ static struct console stdiocons = { | |||
160 | static int stdio_init(void) | 154 | static int stdio_init(void) |
161 | { | 155 | { |
162 | char *new_title; | 156 | char *new_title; |
157 | int err; | ||
163 | int i; | 158 | int i; |
164 | 159 | ||
165 | for (i = 0; i < MAX_TTYS; i++) { | 160 | for (i = 0; i < MAX_TTYS; i++) { |
@@ -168,18 +163,16 @@ static int stdio_init(void) | |||
168 | s = def_conf; | 163 | s = def_conf; |
169 | if (!s) | 164 | if (!s) |
170 | s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; | 165 | s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; |
171 | if (s && strcmp(s, "none") != 0) { | 166 | if (s && strcmp(s, "none") != 0) |
172 | vts[i].init_str = s; | 167 | vts[i].init_str = s; |
173 | vts[i].valid = 1; | ||
174 | } | ||
175 | spin_lock_init(&vts[i].lock); | 168 | spin_lock_init(&vts[i].lock); |
176 | mutex_init(&vts[i].count_lock); | 169 | mutex_init(&vts[i].count_lock); |
177 | vts[i].driver = &driver; | 170 | vts[i].driver = &driver; |
178 | } | 171 | } |
179 | console_driver = register_lines(&driver, &console_ops, vts, | 172 | err = register_lines(&driver, &console_ops, vts, |
180 | ARRAY_SIZE(vts)); | 173 | ARRAY_SIZE(vts)); |
181 | if (console_driver == NULL) | 174 | if (err) |
182 | return -1; | 175 | return err; |
183 | printk(KERN_INFO "Initialized stdio console driver\n"); | 176 | printk(KERN_INFO "Initialized stdio console driver\n"); |
184 | 177 | ||
185 | new_title = add_xterm_umid(opts.xterm_title); | 178 | new_title = add_xterm_umid(opts.xterm_title); |