From 43574c1afea4f798592c03cf4d4ecea4fd0a8416 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Sep 2011 17:25:00 -0400 Subject: um: get rid of the init_prio mess make line_setup() act on a separate array of conf strings + default conf, have lines array initialized explicitly by that data, bury LINE_INIT() macro from hell. Signed-off-by: Al Viro Signed-off-by: Richard Weinberger --- arch/um/drivers/stdio_console.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'arch/um/drivers/stdio_console.c') diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 088776f0190..6d244f47096 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -76,9 +76,9 @@ static struct line_driver driver = { /* The array is initialized by line_init, at initcall time. The * elements are locked individually as needed. */ -static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), - [ 1 ... MAX_TTYS - 1 ] = - LINE_INIT(CONFIG_CON_CHAN, &driver) }; +static char *vt_conf[MAX_TTYS]; +static char *def_conf; +static struct line vts[MAX_TTYS]; static int con_config(char *str, char **error_out) { @@ -160,7 +160,22 @@ static struct console stdiocons = { static int stdio_init(void) { char *new_title; - + int i; + + for (i = 0; i < MAX_TTYS; i++) { + char *s = vt_conf[i]; + if (!s) + s = def_conf; + if (!s) + s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; + if (s && strcmp(s, "none") != 0) { + vts[i].init_str = s; + vts[i].valid = 1; + } + spin_lock_init(&vts[i].lock); + spin_lock_init(&vts[i].count_lock); + vts[i].driver = &driver; + } console_driver = register_lines(&driver, &console_ops, vts, ARRAY_SIZE(vts)); if (console_driver == NULL) @@ -189,14 +204,7 @@ __uml_exitcall(console_exit); static int console_chan_setup(char *str) { - char *error; - int ret; - - ret = line_setup(vts, ARRAY_SIZE(vts), str, &error); - if(ret < 0) - printk(KERN_ERR "Failed to set up console with " - "configuration string \"%s\" : %s\n", str, error); - + line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console"); return 1; } __setup("con", console_chan_setup); -- cgit v1.2.3-70-g09d2 From d8c215adbf3901aa7d00a0f17f08d77be689f838 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Sep 2011 17:36:37 -0400 Subject: um: convert count_lock to mutex, fix a race in line_open() If two processes are opening the same line, the second to get into line_open() will decide that it doesn't need to do anything (correctly) or wait for anything. The latter, unfortunately, is incorrect - the first opener might not be through yet. We need to have exclusion covering the entire line_init(), including the blocking parts. Moreover, the next patch will need to widen the exclusion on mconsole side of things, also including the blocking bits, so let's just convert that sucker to mutex... Signed-off-by: Al Viro Signed-off-by: Richard Weinberger --- arch/um/drivers/line.c | 26 +++++++++----------------- arch/um/drivers/line.h | 2 +- arch/um/drivers/ssl.c | 2 +- arch/um/drivers/stdio_console.c | 2 +- 4 files changed, 12 insertions(+), 20 deletions(-) (limited to 'arch/um/drivers/stdio_console.c') diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 3eea99e98a1..dc7e216df6a 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -409,7 +409,7 @@ int line_open(struct line *lines, struct tty_struct *tty) struct line *line = &lines[tty->index]; int err = -ENODEV; - spin_lock(&line->count_lock); + mutex_lock(&line->count_lock); if (!line->valid) goto out_unlock; @@ -421,10 +421,9 @@ int line_open(struct line *lines, struct tty_struct *tty) tty->driver_data = line; line->tty = tty; - spin_unlock(&line->count_lock); err = enable_chan(line); if (err) /* line_close() will be called by our caller */ - return err; + goto out_unlock; INIT_DELAYED_WORK(&line->task, line_timer_cb); @@ -435,11 +434,8 @@ int line_open(struct line *lines, struct tty_struct *tty) chan_window_size(&line->chan_list, &tty->winsize.ws_row, &tty->winsize.ws_col); - - return 0; - out_unlock: - spin_unlock(&line->count_lock); + mutex_unlock(&line->count_lock); return err; } @@ -459,7 +455,7 @@ void line_close(struct tty_struct *tty, struct file * filp) /* We ignore the error anyway! */ flush_buffer(line); - spin_lock(&line->count_lock); + mutex_lock(&line->count_lock); BUG_ON(!line->valid); if (--line->count) @@ -468,17 +464,13 @@ void line_close(struct tty_struct *tty, struct file * filp) line->tty = NULL; tty->driver_data = NULL; - spin_unlock(&line->count_lock); - if (line->sigio) { unregister_winch(tty); line->sigio = 0; } - return; - out_unlock: - spin_unlock(&line->count_lock); + mutex_unlock(&line->count_lock); } void close_lines(struct line *lines, int nlines) @@ -495,7 +487,7 @@ static int setup_one_line(struct line *lines, int n, char *init, struct line *line = &lines[n]; int err = -EINVAL; - spin_lock(&line->count_lock); + mutex_lock(&line->count_lock); if (line->count) { *error_out = "Device is already open"; @@ -510,7 +502,7 @@ static int setup_one_line(struct line *lines, int n, char *init, } err = 0; out: - spin_unlock(&line->count_lock); + mutex_unlock(&line->count_lock); return err; } @@ -609,13 +601,13 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, line = &lines[dev]; - spin_lock(&line->count_lock); + mutex_lock(&line->count_lock); if (!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); else if (line->tty == NULL) CONFIG_CHUNK(str, size, n, line->init_str, 1); else n = chan_config_string(&line->chan_list, str, size, error_out); - spin_unlock(&line->count_lock); + mutex_unlock(&line->count_lock); return n; } diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 0c4dadf5e03..471f477b271 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -32,7 +32,7 @@ struct line_driver { struct line { struct tty_struct *tty; - spinlock_t count_lock; + struct mutex count_lock; unsigned long count; int valid; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 445288ff065..23cffd6d85a 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -201,7 +201,7 @@ static int ssl_init(void) serial_lines[i].valid = 1; } spin_lock_init(&serial_lines[i].lock); - spin_lock_init(&serial_lines[i].count_lock); + mutex_init(&serial_lines[i].count_lock); serial_lines[i].driver = &driver; } ssl_driver = register_lines(&driver, &ssl_ops, serial_lines, diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 6d244f47096..f8d4325b28b 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -173,7 +173,7 @@ static int stdio_init(void) vts[i].valid = 1; } spin_lock_init(&vts[i].lock); - spin_lock_init(&vts[i].count_lock); + mutex_init(&vts[i].count_lock); vts[i].driver = &driver; } console_driver = register_lines(&driver, &console_ops, vts, -- cgit v1.2.3-70-g09d2 From cfe6b7c79daa0efa27f474f1fe2a88fd7af5cc47 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Sep 2011 19:45:42 -0400 Subject: 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(-) (limited to 'arch/um/drivers/stdio_console.c') diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 1a8d6591c20..015209a9881 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 471f477b271..e3f86065e04 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 23cffd6d85a..6398a47d035 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 f8d4325b28b..32bd040138f 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); -- cgit v1.2.3-70-g09d2 From 04292b2cf8f02a33cfc1054c0c51aa8c77731813 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Sep 2011 20:07:05 -0400 Subject: um: get rid of lines_init() move config-independent parts of initialization into register_lines(), call setup_one_line() after it instead of abusing ->init_str. Signed-off-by: Al Viro Signed-off-by: Richard Weinberger --- arch/um/drivers/line.c | 31 ++++++++++--------------------- arch/um/drivers/line.h | 3 ++- arch/um/drivers/ssl.c | 20 +++++++++----------- arch/um/drivers/stdio_console.c | 25 ++++++++++++------------- 4 files changed, 33 insertions(+), 46 deletions(-) (limited to 'arch/um/drivers/stdio_console.c') diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 015209a9881..002d4a968ae 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -481,8 +481,8 @@ void close_lines(struct line *lines, int nlines) close_chan(&lines[i].chan_list, 0); } -static int setup_one_line(struct line *lines, int n, char *init, - const struct chan_opts *opts, char **error_out) +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; @@ -658,6 +658,7 @@ int register_lines(struct line_driver *line_driver, { struct tty_driver *driver = alloc_tty_driver(nlines); int err; + int i; if (!driver) return -ENOMEM; @@ -670,6 +671,13 @@ int register_lines(struct line_driver *line_driver, driver->subtype = line_driver->subtype; driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; driver->init_termios = tty_std_termios; + + for (i = 0; i < nlines; i++) { + spin_lock_init(&lines[i].lock); + mutex_init(&lines[i].count_lock); + lines[i].driver = line_driver; + INIT_LIST_HEAD(&lines[i].chan_list); + } tty_set_operations(driver, ops); err = tty_register_driver(driver); @@ -688,25 +696,6 @@ int register_lines(struct line_driver *line_driver, static DEFINE_SPINLOCK(winch_handler_lock); static LIST_HEAD(winch_handlers); -void lines_init(struct line *lines, int nlines, struct chan_opts *opts) -{ - struct line *line; - char *error; - int i; - - for(i = 0; i < nlines; i++) { - line = &lines[i]; - INIT_LIST_HEAD(&line->chan_list); - - if (line->init_str == NULL) - continue; - - if (setup_one_line(lines, i, line->init_str, opts, &error)) - printk(KERN_ERR "setup_one_line failed for " - "device %d : %s\n", i, error); - } -} - struct winch { struct list_head list; int fd; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index e3f86065e04..95991994a93 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -82,7 +82,8 @@ extern void line_close_chan(struct line *line); 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 int setup_one_line(struct line *lines, int n, char *init, + const struct chan_opts *opts, char **error_out); extern void close_lines(struct line *lines, int nlines); extern int line_config(struct line *lines, unsigned int sizeof_lines, diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 6398a47d035..d0b5ccf2379 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -187,16 +187,6 @@ static int ssl_init(void) printk(KERN_INFO "Initializing software serial port version %d\n", ssl_version); - for (i = 0; i < NR_PORTS; i++) { - char *s = conf[i]; - if (!s) - s = def_conf; - if (s && strcmp(s, "none") != 0) - serial_lines[i].init_str = s; - spin_lock_init(&serial_lines[i].lock); - mutex_init(&serial_lines[i].count_lock); - serial_lines[i].driver = &driver; - } err = register_lines(&driver, &ssl_ops, serial_lines, ARRAY_SIZE(serial_lines)); if (err) @@ -206,7 +196,15 @@ static int ssl_init(void) if (new_title != NULL) opts.xterm_title = new_title; - lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); + 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); diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 32bd040138f..fe581209d62 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -157,29 +157,28 @@ static int stdio_init(void) int err; int i; - for (i = 0; i < MAX_TTYS; i++) { - char *s = vt_conf[i]; - if (!s) - s = def_conf; - if (!s) - s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; - if (s && strcmp(s, "none") != 0) - vts[i].init_str = s; - spin_lock_init(&vts[i].lock); - mutex_init(&vts[i].count_lock); - vts[i].driver = &driver; - } err = register_lines(&driver, &console_ops, vts, ARRAY_SIZE(vts)); if (err) return err; + printk(KERN_INFO "Initialized stdio console driver\n"); new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; - lines_init(vts, ARRAY_SIZE(vts), &opts); + for (i = 0; i < MAX_TTYS; i++) { + char *error; + char *s = vt_conf[i]; + if (!s) + s = def_conf; + if (!s) + s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN; + if (setup_one_line(vts, i, s, &opts, &error)) + printk(KERN_ERR "setup_one_line failed for " + "device %d : %s\n", i, error); + } con_init_done = 1; register_console(&stdiocons); -- cgit v1.2.3-70-g09d2 From bed5e39c56f3fe792e336cfa2670001d78f1d44c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 8 Sep 2011 10:49:34 -0400 Subject: um: switch users of ->chan_list to ->chan_{in,out} (easy cases) Signed-off-by: Al Viro Signed-off-by: Richard Weinberger --- arch/um/drivers/chan.h | 16 ++-- arch/um/drivers/chan_kern.c | 172 +++++++++++++++------------------------- arch/um/drivers/line.c | 24 +++--- arch/um/drivers/ssl.c | 2 +- arch/um/drivers/stdio_console.c | 2 +- 5 files changed, 88 insertions(+), 128 deletions(-) (limited to 'arch/um/drivers/stdio_console.c') diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h index 8df0fd9024d..5078ec701c6 100644 --- a/arch/um/drivers/chan.h +++ b/arch/um/drivers/chan.h @@ -27,24 +27,24 @@ struct chan { void *data; }; -extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, +extern void chan_interrupt(struct line *line, struct delayed_work *task, struct tty_struct *tty, int irq); extern int parse_chan_pair(char *str, struct line *line, int device, const struct chan_opts *opts, char **error_out); -extern int write_chan(struct list_head *chans, const char *buf, int len, +extern int write_chan(struct chan *chan, const char *buf, int len, int write_irq); -extern int console_write_chan(struct list_head *chans, const char *buf, +extern int console_write_chan(struct chan *chan, const char *buf, int len); extern int console_open_chan(struct line *line, struct console *co); -extern void deactivate_chan(struct list_head *chans, int irq); -extern void reactivate_chan(struct list_head *chans, int irq); -extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); +extern void deactivate_chan(struct chan *chan, int irq); +extern void reactivate_chan(struct chan *chan, int irq); +extern void chan_enable_winch(struct chan *chan, struct tty_struct *tty); extern int enable_chan(struct line *line); extern void close_chan(struct list_head *chans, int delay_free_irq); -extern int chan_window_size(struct list_head *chans, +extern int chan_window_size(struct line *line, unsigned short *rows_out, unsigned short *cols_out); -extern int chan_config_string(struct list_head *chans, char *str, int size, +extern int chan_config_string(struct line *line, char *str, int size, char **error_out); #endif diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 390920d63a2..73d7bc018ab 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -140,18 +140,10 @@ static int open_chan(struct list_head *chans) return err; } -void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) +void chan_enable_winch(struct chan *chan, struct tty_struct *tty) { - struct list_head *ele; - struct chan *chan; - - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (chan->primary && chan->output && chan->ops->winch) { - register_winch(chan->fd, tty); - return; - } - } + if (chan && chan->primary && chan->ops->winch) + register_winch(chan->fd, tty); } int enable_chan(struct line *line) @@ -258,72 +250,45 @@ void close_chan(struct list_head *chans, int delay_free_irq) } } -void deactivate_chan(struct list_head *chans, int irq) +void deactivate_chan(struct chan *chan, int irq) { - struct list_head *ele; - - struct chan *chan; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - - if (chan->enabled && chan->input) - deactivate_fd(chan->fd, irq); - } + if (chan && chan->enabled) + deactivate_fd(chan->fd, irq); } -void reactivate_chan(struct list_head *chans, int irq) +void reactivate_chan(struct chan *chan, int irq) { - struct list_head *ele; - struct chan *chan; - - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - - if (chan->enabled && chan->input) - reactivate_fd(chan->fd, irq); - } + if (chan && chan->enabled) + reactivate_fd(chan->fd, irq); } -int write_chan(struct list_head *chans, const char *buf, int len, +int write_chan(struct chan *chan, const char *buf, int len, int write_irq) { - struct list_head *ele; - struct chan *chan = NULL; int n, ret = 0; - if (len == 0) + if (len == 0 || !chan || !chan->ops->write) return 0; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->output || (chan->ops->write == NULL)) - continue; - - n = chan->ops->write(chan->fd, buf, len, chan->data); - if (chan->primary) { - ret = n; - if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) - reactivate_fd(chan->fd, write_irq); - } + n = chan->ops->write(chan->fd, buf, len, chan->data); + if (chan->primary) { + ret = n; + if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) + reactivate_fd(chan->fd, write_irq); } return ret; } -int console_write_chan(struct list_head *chans, const char *buf, int len) +int console_write_chan(struct chan *chan, const char *buf, int len) { - struct list_head *ele; - struct chan *chan; int n, ret = 0; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->output || (chan->ops->console_write == NULL)) - continue; + if (!chan || !chan->ops->console_write) + return 0; - n = chan->ops->console_write(chan->fd, buf, len); - if (chan->primary) - ret = n; - } + n = chan->ops->console_write(chan->fd, buf, len); + if (chan->primary) + ret = n; return ret; } @@ -340,20 +305,24 @@ int console_open_chan(struct line *line, struct console *co) return 0; } -int chan_window_size(struct list_head *chans, unsigned short *rows_out, +int chan_window_size(struct line *line, unsigned short *rows_out, unsigned short *cols_out) { - struct list_head *ele; struct chan *chan; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (chan->primary) { - if (chan->ops->window_size == NULL) - return 0; - return chan->ops->window_size(chan->fd, chan->data, - rows_out, cols_out); - } + chan = line->chan_in; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); + } + chan = line->chan_out; + if (chan && chan->primary) { + if (chan->ops->window_size == NULL) + return 0; + return chan->ops->window_size(chan->fd, chan->data, + rows_out, cols_out); } return 0; } @@ -429,21 +398,15 @@ static int chan_pair_config_string(struct chan *in, struct chan *out, return n; } -int chan_config_string(struct list_head *chans, char *str, int size, +int chan_config_string(struct line *line, char *str, int size, char **error_out) { - struct list_head *ele; - struct chan *chan, *in = NULL, *out = NULL; + struct chan *in = line->chan_in, *out = line->chan_out; - list_for_each(ele, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->primary) - continue; - if (chan->input) - in = chan; - if (chan->output) - out = chan; - } + if (in && !in->primary) + in = NULL; + if (out && !out->primary) + out = NULL; return chan_pair_config_string(in, out, str, size, error_out); } @@ -589,39 +552,36 @@ int parse_chan_pair(char *str, struct line *line, int device, return 0; } -void chan_interrupt(struct list_head *chans, struct delayed_work *task, +void chan_interrupt(struct line *line, struct delayed_work *task, struct tty_struct *tty, int irq) { - struct list_head *ele, *next; - struct chan *chan; + struct chan *chan = line->chan_in; int err; char c; - list_for_each_safe(ele, next, chans) { - chan = list_entry(ele, struct chan, list); - if (!chan->input || (chan->ops->read == NULL)) - continue; - do { - if (tty && !tty_buffer_request_room(tty, 1)) { - schedule_delayed_work(task, 1); - goto out; - } - err = chan->ops->read(chan->fd, &c, chan->data); - if (err > 0) - tty_receive_char(tty, c); - } while (err > 0); - - if (err == 0) - reactivate_fd(chan->fd, irq); - if (err == -EIO) { - if (chan->primary) { - if (tty != NULL) - tty_hangup(tty); - close_chan(chans, 1); - return; - } - else close_one_chan(chan, 1); + if (!chan || !chan->ops->read) + goto out; + + do { + if (tty && !tty_buffer_request_room(tty, 1)) { + schedule_delayed_work(task, 1); + goto out; + } + err = chan->ops->read(chan->fd, &c, chan->data); + if (err > 0) + tty_receive_char(tty, c); + } while (err > 0); + + if (err == 0) + reactivate_fd(chan->fd, irq); + if (err == -EIO) { + if (chan->primary) { + if (tty != NULL) + tty_hangup(tty); + close_chan(&line->chan_list, 1); + return; } + else close_one_chan(chan, 1); } out: if (tty) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 9ffade87a8c..c1aa89cefae 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -21,7 +21,7 @@ static irqreturn_t line_interrupt(int irq, void *data) struct line *line = chan->line; if (line) - chan_interrupt(&line->chan_list, &line->task, line->tty, irq); + chan_interrupt(line, &line->task, line->tty, irq); return IRQ_HANDLED; } @@ -30,7 +30,7 @@ static void line_timer_cb(struct work_struct *work) struct line *line = container_of(work, struct line, task.work); if (!line->throttled) - chan_interrupt(&line->chan_list, &line->task, line->tty, + chan_interrupt(line, &line->task, line->tty, line->driver->read_irq); } @@ -145,7 +145,7 @@ static int flush_buffer(struct line *line) /* line->buffer + LINE_BUFSIZE is the end of the buffer! */ count = line->buffer + LINE_BUFSIZE - line->head; - n = write_chan(&line->chan_list, line->head, count, + n = write_chan(line->chan_out, line->head, count, line->driver->write_irq); if (n < 0) return n; @@ -162,7 +162,7 @@ static int flush_buffer(struct line *line) } count = line->tail - line->head; - n = write_chan(&line->chan_list, line->head, count, + n = write_chan(line->chan_out, line->head, count, line->driver->write_irq); if (n < 0) @@ -206,7 +206,7 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len) if (line->head != line->tail) ret = buffer_data(line, buf, len); else { - n = write_chan(&line->chan_list, buf, len, + n = write_chan(line->chan_out, buf, len, line->driver->write_irq); if (n < 0) { ret = n; @@ -318,7 +318,7 @@ void line_throttle(struct tty_struct *tty) { struct line *line = tty->driver_data; - deactivate_chan(&line->chan_list, line->driver->read_irq); + deactivate_chan(line->chan_in, line->driver->read_irq); line->throttled = 1; } @@ -327,7 +327,7 @@ void line_unthrottle(struct tty_struct *tty) struct line *line = tty->driver_data; line->throttled = 0; - chan_interrupt(&line->chan_list, &line->task, tty, + chan_interrupt(line, &line->task, tty, line->driver->read_irq); /* @@ -336,7 +336,7 @@ void line_unthrottle(struct tty_struct *tty) * again and we shouldn't turn the interrupt back on. */ if (!line->throttled) - reactivate_chan(&line->chan_list, line->driver->read_irq); + reactivate_chan(line->chan_in, line->driver->read_irq); } static irqreturn_t line_write_interrupt(int irq, void *data) @@ -428,11 +428,11 @@ int line_open(struct line *lines, struct tty_struct *tty) INIT_DELAYED_WORK(&line->task, line_timer_cb); if (!line->sigio) { - chan_enable_winch(&line->chan_list, tty); + chan_enable_winch(line->chan_out, tty); line->sigio = 1; } - chan_window_size(&line->chan_list, &tty->winsize.ws_row, + chan_window_size(line, &tty->winsize.ws_row, &tty->winsize.ws_col); out_unlock: mutex_unlock(&line->count_lock); @@ -624,7 +624,7 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, CONFIG_CHUNK(str, size, n, "none", 1); else if (line->tty == NULL) CONFIG_CHUNK(str, size, n, line->init_str, 1); - else n = chan_config_string(&line->chan_list, str, size, error_out); + else n = chan_config_string(line, str, size, error_out); mutex_unlock(&line->count_lock); return n; @@ -761,7 +761,7 @@ static irqreturn_t winch_interrupt(int irq, void *data) if (tty != NULL) { line = tty->driver_data; if (line != NULL) { - chan_window_size(&line->chan_list, &tty->winsize.ws_row, + chan_window_size(line, &tty->winsize.ws_row, &tty->winsize.ws_col); kill_pgrp(tty->pgrp, SIGWINCH, 1); } diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index d0b5ccf2379..e09801a1327 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -151,7 +151,7 @@ static void ssl_console_write(struct console *c, const char *string, unsigned long flags; spin_lock_irqsave(&line->lock, flags); - console_write_chan(&line->chan_list, string, len); + console_write_chan(line->chan_out, string, len); spin_unlock_irqrestore(&line->lock, flags); } diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index fe581209d62..7663541c372 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -124,7 +124,7 @@ static void uml_console_write(struct console *console, const char *string, unsigned long flags; spin_lock_irqsave(&line->lock, flags); - console_write_chan(&line->chan_list, string, len); + console_write_chan(line->chan_out, string, len); spin_unlock_irqrestore(&line->lock, flags); } -- cgit v1.2.3-70-g09d2