diff options
author | Linus Torvalds | 2012-03-27 18:29:53 -0700 |
---|---|---|
committer | Linus Torvalds | 2012-03-27 18:29:53 -0700 |
commit | fa453a625de5b8ee9ada0a5b329df3f88751c615 (patch) | |
tree | 7a9e04d4a44bb929e96bd9bebb7b97cb733d1ecb /arch/um/drivers | |
parent | 30eebb54b13ef198a3f1a143ee9dd68f295c60de (diff) | |
parent | 3463ff4439661d8107ac024329b5fe01d6e5117b (diff) |
Merge branch 'for-linus-3.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML changes from Richard Weinberger:
"Mostly bug fixes and cleanups"
* 'for-linus-3.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: (35 commits)
um: Update defconfig
um: Switch to large mcmodel on x86_64
MTD: Relax dependencies
um: Wire CONFIG_GENERIC_IO up
um: Serve io_remap_pfn_range()
Introduce CONFIG_GENERIC_IO
um: allow SUBARCH=x86
um: most of the SUBARCH uses can be killed
um: deadlock in line_write_interrupt()
um: don't bother trying to rebuild CHECKFLAGS for USER_OBJS
um: use the right ifdef around exports in user_syms.c
um: a bunch of headers can be killed by using generic-y
um: ptrace-generic.h doesn't need user.h
um: kill HOST_TASK_PID
um: remove pointless include of asm/fixmap.h from asm/pgtable.h
um: asm-offsets.h might as well come from underlying arch...
um: merge processor_{32,64}.h a bit...
um: switch close_chan() to struct line
um: race fix: initialize delayed_work *before* registering IRQ
um: line->have_irq is never checked...
...
Diffstat (limited to 'arch/um/drivers')
-rw-r--r-- | arch/um/drivers/chan.h | 18 | ||||
-rw-r--r-- | arch/um/drivers/chan_kern.c | 198 | ||||
-rw-r--r-- | arch/um/drivers/chan_user.h | 2 | ||||
-rw-r--r-- | arch/um/drivers/line.c | 258 | ||||
-rw-r--r-- | arch/um/drivers/line.h | 29 | ||||
-rw-r--r-- | arch/um/drivers/mconsole_kern.c | 2 | ||||
-rw-r--r-- | arch/um/drivers/net_kern.c | 2 | ||||
-rw-r--r-- | arch/um/drivers/port_kern.c | 4 | ||||
-rw-r--r-- | arch/um/drivers/random.c | 2 | ||||
-rw-r--r-- | arch/um/drivers/ssl.c | 41 | ||||
-rw-r--r-- | arch/um/drivers/stdio_console.c | 46 | ||||
-rw-r--r-- | arch/um/drivers/ubd.h (renamed from arch/um/drivers/ubd_user.h) | 0 | ||||
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 46 | ||||
-rw-r--r-- | arch/um/drivers/ubd_user.c | 8 | ||||
-rw-r--r-- | arch/um/drivers/xterm_kern.c | 2 |
15 files changed, 292 insertions, 366 deletions
diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h index 8df0fd9024dc..02b5a76e98d9 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 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 void close_chan(struct line *line); +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 420e2c800799..ca4c7ebfd0aa 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -140,18 +140,18 @@ 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; + if (chan && chan->primary && chan->ops->winch) + register_winch(chan->fd, tty); +} - 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; - } - } +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, line->tty, line->driver->read_irq); } int enable_chan(struct line *line) @@ -160,6 +160,8 @@ int enable_chan(struct line *line) struct chan *chan; int err; + INIT_DELAYED_WORK(&line->task, line_timer_cb); + list_for_each(ele, &line->chan_list) { chan = list_entry(ele, struct chan, list); err = open_one_chan(chan); @@ -183,7 +185,7 @@ int enable_chan(struct line *line) return 0; out_close: - close_chan(&line->chan_list, 0); + close_chan(line); return err; } @@ -244,7 +246,7 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) chan->fd = -1; } -void close_chan(struct list_head *chans, int delay_free_irq) +void close_chan(struct line *line) { struct chan *chan; @@ -253,77 +255,50 @@ void close_chan(struct list_head *chans, int delay_free_irq) * state. Then, the first one opened will have the original state, * so it must be the last closed. */ - list_for_each_entry_reverse(chan, chans, list) { - close_one_chan(chan, delay_free_irq); + list_for_each_entry_reverse(chan, &line->chan_list, list) { + close_one_chan(chan, 0); } } -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 +315,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 +408,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); } @@ -547,10 +520,14 @@ int parse_chan_pair(char *str, struct line *line, int device, char *in, *out; if (!list_empty(chans)) { + line->chan_in = line->chan_out = NULL; free_chan(chans); INIT_LIST_HEAD(chans); } + if (!str) + return 0; + out = strchr(str, ','); if (out != NULL) { in = str; @@ -562,6 +539,7 @@ int parse_chan_pair(char *str, struct line *line, int device, new->input = 1; list_add(&new->list, chans); + line->chan_in = new; new = parse_chan(line, out, device, opts, error_out); if (new == NULL) @@ -569,6 +547,7 @@ int parse_chan_pair(char *str, struct line *line, int device, list_add(&new->list, chans); new->output = 1; + line->chan_out = new; } else { new = parse_chan(line, str, device, opts, error_out); @@ -578,43 +557,42 @@ int parse_chan_pair(char *str, struct line *line, int device, list_add(&new->list, chans); new->input = 1; new->output = 1; + line->chan_in = line->chan_out = new; } return 0; } -void chan_interrupt(struct list_head *chans, struct delayed_work *task, - struct tty_struct *tty, int irq) +void chan_interrupt(struct line *line, 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(&line->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); + if (line->chan_out != chan) + close_one_chan(line->chan_out, 1); + } + close_one_chan(chan, 1); + if (chan->primary) + return; } out: if (tty) diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h index 9b9ced85b703..6257b7a6e1af 100644 --- a/arch/um/drivers/chan_user.h +++ b/arch/um/drivers/chan_user.h @@ -14,8 +14,6 @@ struct chan_opts { const int raw; }; -enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; - struct chan_ops { char *type; void *(*init)(char *, int, const struct chan_opts *); diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index c1cf2206b84b..4ab0d9c0911c 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -21,19 +21,10 @@ 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->tty, irq); return IRQ_HANDLED; } -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, - line->driver->read_irq); -} - /* * Returns the free space inside the ring buffer of this line. * @@ -145,7 +136,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 +153,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 +197,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 +309,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,8 +318,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, - line->driver->read_irq); + chan_interrupt(line, tty, line->driver->read_irq); /* * Maybe there is enough stuff pending that calling the interrupt @@ -336,7 +326,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) @@ -347,13 +337,14 @@ static irqreturn_t line_write_interrupt(int irq, void *data) int err; /* - * Interrupts are disabled here because we registered the interrupt with - * IRQF_DISABLED (see line_setup_irq). + * Interrupts are disabled here because genirq keep irqs disabled when + * calling the action handler. */ spin_lock(&line->lock); err = flush_buffer(line); if (err == 0) { + spin_unlock(&line->lock); return IRQ_NONE; } else if (err < 0) { line->head = line->buffer; @@ -371,7 +362,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data) int line_setup_irq(int fd, int input, int output, struct line *line, void *data) { const struct line_driver *driver = line->driver; - int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM; + int err = 0, flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM; if (input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, @@ -383,7 +374,6 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, line_write_interrupt, flags, driver->write_irq_name, data); - line->have_irq = 1; return err; } @@ -409,7 +399,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,25 +411,19 @@ 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; - - INIT_DELAYED_WORK(&line->task, line_timer_cb); + goto out_unlock; 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); - - return 0; - out_unlock: - spin_unlock(&line->count_lock); + mutex_unlock(&line->count_lock); return err; } @@ -459,7 +443,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 +452,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) @@ -486,34 +466,60 @@ void close_lines(struct line *lines, int nlines) int i; for(i = 0; i < nlines; i++) - close_chan(&lines[i].chan_list, 0); + close_chan(&lines[i]); } -static int setup_one_line(struct line *lines, int n, char *init, int init_prio, - 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; int err = -EINVAL; - spin_lock(&line->count_lock); + mutex_lock(&line->count_lock); if (line->count) { *error_out = "Device is already open"; goto out; } - if (line->init_pri <= init_prio) { - line->init_pri = init_prio; - if (!strcmp(init, "none")) + if (!strcmp(init, "none")) { + 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; + } + } else { + char *new = kstrdup(init, GFP_KERNEL); + if (!new) { + *error_out = "Failed to allocate memory"; + return -ENOMEM; + } + if (line->valid) { + tty_unregister_device(driver, n); + kfree(line->init_str); + } + 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; - else { - line->init_str = init; - line->valid = 1; + kfree(new); } } - err = 0; out: - spin_unlock(&line->count_lock); + mutex_unlock(&line->count_lock); return err; } @@ -524,54 +530,43 @@ out: * @error_out is an error string in the case of failure; */ -int line_setup(struct line *lines, unsigned int num, char *init, - char **error_out) +int line_setup(char **conf, unsigned int num, char **def, + char *init, char *name) { - int i, n, err; - char *end; + char *error; if (*init == '=') { /* * We said con=/ssl= instead of con#=, so we are configuring all * consoles at once. */ - n = -1; - } - else { - n = simple_strtoul(init, &end, 0); + *def = init + 1; + } else { + char *end; + unsigned n = simple_strtoul(init, &end, 0); + if (*end != '=') { - *error_out = "Couldn't parse device number"; - return -EINVAL; + error = "Couldn't parse device number"; + goto out; } - init = end; - } - init++; - - if (n >= (signed int) num) { - *error_out = "Device number out of range"; - return -EINVAL; - } - else if (n >= 0) { - err = setup_one_line(lines, n, init, INIT_ONE, error_out); - if (err) - return err; - } - else { - for(i = 0; i < num; i++) { - err = setup_one_line(lines, i, init, INIT_ALL, - error_out); - if (err) - return err; + if (n >= num) { + error = "Device number out of range"; + goto out; } + conf[n] = end + 1; } - return n == -1 ? num : n; + return 0; + +out: + printk(KERN_ERR "Failed to set up %s with " + "configuration string \"%s\" : %s\n", name, init, error); + return -EINVAL; } int line_config(struct line *lines, unsigned int num, char *str, const struct chan_opts *opts, char **error_out) { - struct line *line; - char *new; + char *end; int n; if (*str == '=') { @@ -579,17 +574,17 @@ int line_config(struct line *lines, unsigned int num, char *str, return -EINVAL; } - new = kstrdup(str, GFP_KERNEL); - if (new == NULL) { - *error_out = "Failed to allocate memory"; - return -ENOMEM; + n = simple_strtoul(str, &end, 0); + if (*end++ != '=') { + *error_out = "Couldn't parse device number"; + return -EINVAL; + } + if (n >= num) { + *error_out = "Device number out of range"; + return -EINVAL; } - n = line_setup(lines, num, new, error_out); - if (n < 0) - return n; - line = &lines[n]; - return parse_chan_pair(line->init_str, line, n, opts, error_out); + return setup_one_line(lines, n, end, opts, error_out); } int line_get_config(char *name, struct line *lines, unsigned int num, char *str, @@ -612,13 +607,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); + else n = chan_config_string(line, str, size, error_out); + mutex_unlock(&line->count_lock); return n; } @@ -640,25 +635,23 @@ int line_id(char **str, int *start_out, int *end_out) int line_remove(struct line *lines, unsigned int num, int n, char **error_out) { - int err; - char config[sizeof("conxxxx=none\0")]; - - sprintf(config, "%d=none", n); - err = line_setup(lines, num, config, error_out); - if (err >= 0) - err = 0; - return err; + if (n >= num) { + *error_out = "Device number out of range"; + return -EINVAL; + } + 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; + int i; if (!driver) - return NULL; + return -ENOMEM; driver->driver_name = line_driver->name; driver->name = line_driver->device_name; @@ -666,54 +659,33 @@ 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; + + 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); - 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); 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; - - line->init_str = kstrdup(line->init_str, GFP_KERNEL); - if (line->init_str == NULL) - printk(KERN_ERR "lines_init - kstrdup returned NULL\n"); - - if (parse_chan_pair(line->init_str, line, i, opts, &error)) { - printk(KERN_ERR "parse_chan_pair failed for " - "device %d : %s\n", i, error); - line->valid = 0; - } - } -} - struct winch { struct list_head list; int fd; @@ -777,7 +749,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); } @@ -807,7 +779,7 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, .stack = stack }); if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, "winch", winch) < 0) { printk(KERN_ERR "register_winch_irq - failed to register " "IRQ\n"); diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 63df3ca02ac2..0a1834719dba 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,17 +28,18 @@ struct line_driver { const int write_irq; const char *write_irq_name; struct mc_device mc; + struct tty_driver *driver; }; struct line { struct tty_struct *tty; - spinlock_t count_lock; + struct mutex count_lock; unsigned long count; int valid; char *init_str; - int init_pri; struct list_head chan_list; + struct chan *chan_in, *chan_out; /*This lock is actually, mostly, local to*/ spinlock_t lock; @@ -55,21 +56,12 @@ struct line { int sigio; struct delayed_work task; const struct line_driver *driver; - int have_irq; }; -#define LINE_INIT(str, d) \ - { .count_lock = __SPIN_LOCK_UNLOCKED((str).count_lock), \ - .init_str = str, \ - .init_pri = INIT_STATIC, \ - .valid = 1, \ - .lock = __SPIN_LOCK_UNLOCKED((str).lock), \ - .driver = d } - extern void line_close(struct tty_struct *tty, struct file * filp); extern int line_open(struct line *lines, struct tty_struct *tty); -extern int line_setup(struct line *lines, unsigned int sizeof_lines, - char *init, char **error_out); +extern int line_setup(char **conf, unsigned nlines, char **def, + char *init, char *name); extern int line_write(struct tty_struct *tty, const unsigned char *buf, int len); extern int line_put_char(struct tty_struct *tty, unsigned char ch); @@ -87,10 +79,11 @@ 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 void lines_init(struct line *lines, int nlines, struct chan_opts *opts); +extern int register_lines(struct line_driver *line_driver, + const struct tty_operations *driver, + struct line *lines, int nlines); +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/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index c70e047eed72..e672bd6d43e3 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -773,7 +773,7 @@ static int __init mconsole_init(void) register_reboot_notifier(&reboot_notifier); err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, "mconsole", (void *)sock); if (err) { printk(KERN_ERR "Failed to get IRQ for management console\n"); diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index d2996183e584..95f4416e6d9f 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -161,7 +161,7 @@ static int uml_net_open(struct net_device *dev) } err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt, - IRQF_DISABLED | IRQF_SHARED, dev->name, dev); + IRQF_SHARED, dev->name, dev); if (err != 0) { printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err); err = -ENETUNREACH; diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index a11573be0961..e31680e662a4 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -100,7 +100,7 @@ static int port_accept(struct port_list *port) .port = port }); if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, "telnetd", conn)) { printk(KERN_ERR "port_accept : failed to get IRQ for " "telnetd\n"); @@ -184,7 +184,7 @@ void *port_data(int port_num) } if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, "port", port)) { printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); goto out_close; diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index 981085a93f30..b25296e6218a 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -131,7 +131,7 @@ static int __init rng_init (void) random_fd = err; err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "random", + IRQF_SAMPLE_RANDOM, "random", NULL); if (err) goto err_out_cleanup_hw; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 9d8c20af6f80..e09801a1327b 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) @@ -71,8 +65,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 serial_lines[NR_PORTS] = - { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; +static char *conf[NR_PORTS]; +static char *def_conf = CONFIG_SSL_CHAN; +static struct line serial_lines[NR_PORTS]; static int ssl_config(char *str, char **error_out) { @@ -156,14 +151,14 @@ 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); } 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) @@ -186,17 +181,30 @@ 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", ssl_version); - 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) 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); @@ -214,14 +222,7 @@ __uml_exitcall(ssl_exit); static int ssl_chan_setup(char *str) { - char *error; - int ret; - - ret = line_setup(serial_lines, ARRAY_SIZE(serial_lines), str, &error); - if(ret < 0) - printk(KERN_ERR "Failed to set up serial line with " - "configuration string \"%s\" : %s\n", str, error); - + line_setup(conf, NR_PORTS, &def_conf, str, "serial line"); return 1; } diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 088776f01908..7663541c372e 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, @@ -76,9 +70,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) { @@ -130,14 +124,14 @@ 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); } 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,18 +154,31 @@ static struct console stdiocons = { static int stdio_init(void) { char *new_title; + int err; + int i; - 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); 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); @@ -189,14 +196,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); diff --git a/arch/um/drivers/ubd_user.h b/arch/um/drivers/ubd.h index 3845051f1b10..3845051f1b10 100644 --- a/arch/um/drivers/ubd_user.h +++ b/arch/um/drivers/ubd.h diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 944453a3ec99..20505cafa299 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -19,40 +19,26 @@ #define UBD_SHIFT 4 -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/blkdev.h" -#include "linux/ata.h" -#include "linux/hdreg.h" -#include "linux/init.h" -#include "linux/cdrom.h" -#include "linux/proc_fs.h" -#include "linux/seq_file.h" -#include "linux/ctype.h" -#include "linux/capability.h" -#include "linux/mm.h" -#include "linux/slab.h" -#include "linux/vmalloc.h" -#include "linux/mutex.h" -#include "linux/blkpg.h" -#include "linux/genhd.h" -#include "linux/spinlock.h" -#include "linux/platform_device.h" -#include "linux/scatterlist.h" -#include "asm/segment.h" -#include "asm/uaccess.h" -#include "asm/irq.h" -#include "asm/types.h" -#include "asm/tlbflush.h" -#include "mem_user.h" +#include <linux/module.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/ata.h> +#include <linux/hdreg.h> +#include <linux/cdrom.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/ctype.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> +#include <asm/tlbflush.h> #include "kern_util.h" #include "mconsole_kern.h" #include "init.h" -#include "irq_user.h" #include "irq_kern.h" -#include "ubd_user.h" +#include "ubd.h" #include "os.h" -#include "mem.h" #include "cow.h" enum ubd_req { UBD_READ, UBD_WRITE }; @@ -1115,7 +1101,7 @@ static int __init ubd_driver_init(void){ return 0; } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, - IRQF_DISABLED, "ubd", ubd_devs); + 0, "ubd", ubd_devs); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return 0; diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index 007b94d97726..ffe02c431dea 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -15,14 +15,12 @@ #include <sys/socket.h> #include <sys/mman.h> #include <sys/param.h> -#include "asm/types.h" -#include "ubd_user.h" -#include "os.h" -#include "cow.h" - #include <endian.h> #include <byteswap.h> +#include "ubd.h" +#include "os.h" + void ignore_sigwinch_sig(void) { signal(SIGWINCH, SIG_IGN); diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index b646bccef37a..8bd130f0bda3 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -50,7 +50,7 @@ int xterm_fd(int socket, int *pid_out) init_completion(&data->ready); err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + IRQF_SHARED | IRQF_SAMPLE_RANDOM, "xterm", data); if (err) { printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " |