summaryrefslogtreecommitdiff
path: root/arch/um/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-28 05:29:53 +0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-28 05:29:53 +0400
commitfa453a625de5b8ee9ada0a5b329df3f88751c615 (patch)
tree7a9e04d4a44bb929e96bd9bebb7b97cb733d1ecb /arch/um/drivers
parent30eebb54b13ef198a3f1a143ee9dd68f295c60de (diff)
parent3463ff4439661d8107ac024329b5fe01d6e5117b (diff)
downloadlinux-fa453a625de5b8ee9ada0a5b329df3f88751c615.tar.xz
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.h18
-rw-r--r--arch/um/drivers/chan_kern.c198
-rw-r--r--arch/um/drivers/chan_user.h2
-rw-r--r--arch/um/drivers/line.c258
-rw-r--r--arch/um/drivers/line.h29
-rw-r--r--arch/um/drivers/mconsole_kern.c2
-rw-r--r--arch/um/drivers/net_kern.c2
-rw-r--r--arch/um/drivers/port_kern.c4
-rw-r--r--arch/um/drivers/random.c2
-rw-r--r--arch/um/drivers/ssl.c41
-rw-r--r--arch/um/drivers/stdio_console.c46
-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.c46
-rw-r--r--arch/um/drivers/ubd_user.c8
-rw-r--r--arch/um/drivers/xterm_kern.c2
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, "