diff options
Diffstat (limited to 'arch/um/drivers/chan_kern.c')
-rw-r--r-- | arch/um/drivers/chan_kern.c | 103 |
1 files changed, 43 insertions, 60 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 7d4190e55654..7b8baf146acc 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -19,44 +19,11 @@ | |||
19 | #include "line.h" | 19 | #include "line.h" |
20 | #include "os.h" | 20 | #include "os.h" |
21 | 21 | ||
22 | /* XXX: could well be moved to somewhere else, if needed. */ | ||
23 | static int my_printf(const char * fmt, ...) | ||
24 | __attribute__ ((format (printf, 1, 2))); | ||
25 | |||
26 | static int my_printf(const char * fmt, ...) | ||
27 | { | ||
28 | /* Yes, can be called on atomic context.*/ | ||
29 | char *buf = kmalloc(4096, GFP_ATOMIC); | ||
30 | va_list args; | ||
31 | int r; | ||
32 | |||
33 | if (!buf) { | ||
34 | /* We print directly fmt. | ||
35 | * Yes, yes, yes, feel free to complain. */ | ||
36 | r = strlen(fmt); | ||
37 | } else { | ||
38 | va_start(args, fmt); | ||
39 | r = vsprintf(buf, fmt, args); | ||
40 | va_end(args); | ||
41 | fmt = buf; | ||
42 | } | ||
43 | |||
44 | if (r) | ||
45 | r = os_write_file(1, fmt, r); | ||
46 | return r; | ||
47 | |||
48 | } | ||
49 | |||
50 | #ifdef CONFIG_NOCONFIG_CHAN | 22 | #ifdef CONFIG_NOCONFIG_CHAN |
51 | /* Despite its name, there's no added trailing newline. */ | 23 | static void *not_configged_init(char *str, int device, |
52 | static int my_puts(const char * buf) | 24 | const struct chan_opts *opts) |
53 | { | ||
54 | return os_write_file(1, buf, strlen(buf)); | ||
55 | } | ||
56 | |||
57 | static void *not_configged_init(char *str, int device, struct chan_opts *opts) | ||
58 | { | 25 | { |
59 | my_puts("Using a channel type which is configured out of " | 26 | printk("Using a channel type which is configured out of " |
60 | "UML\n"); | 27 | "UML\n"); |
61 | return NULL; | 28 | return NULL; |
62 | } | 29 | } |
@@ -64,34 +31,34 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) | |||
64 | static int not_configged_open(int input, int output, int primary, void *data, | 31 | static int not_configged_open(int input, int output, int primary, void *data, |
65 | char **dev_out) | 32 | char **dev_out) |
66 | { | 33 | { |
67 | my_puts("Using a channel type which is configured out of " | 34 | printk("Using a channel type which is configured out of " |
68 | "UML\n"); | 35 | "UML\n"); |
69 | return -ENODEV; | 36 | return -ENODEV; |
70 | } | 37 | } |
71 | 38 | ||
72 | static void not_configged_close(int fd, void *data) | 39 | static void not_configged_close(int fd, void *data) |
73 | { | 40 | { |
74 | my_puts("Using a channel type which is configured out of " | 41 | printk("Using a channel type which is configured out of " |
75 | "UML\n"); | 42 | "UML\n"); |
76 | } | 43 | } |
77 | 44 | ||
78 | static int not_configged_read(int fd, char *c_out, void *data) | 45 | static int not_configged_read(int fd, char *c_out, void *data) |
79 | { | 46 | { |
80 | my_puts("Using a channel type which is configured out of " | 47 | printk("Using a channel type which is configured out of " |
81 | "UML\n"); | 48 | "UML\n"); |
82 | return -EIO; | 49 | return -EIO; |
83 | } | 50 | } |
84 | 51 | ||
85 | static int not_configged_write(int fd, const char *buf, int len, void *data) | 52 | static int not_configged_write(int fd, const char *buf, int len, void *data) |
86 | { | 53 | { |
87 | my_puts("Using a channel type which is configured out of " | 54 | printk("Using a channel type which is configured out of " |
88 | "UML\n"); | 55 | "UML\n"); |
89 | return -EIO; | 56 | return -EIO; |
90 | } | 57 | } |
91 | 58 | ||
92 | static int not_configged_console_write(int fd, const char *buf, int len) | 59 | static int not_configged_console_write(int fd, const char *buf, int len) |
93 | { | 60 | { |
94 | my_puts("Using a channel type which is configured out of " | 61 | printk("Using a channel type which is configured out of " |
95 | "UML\n"); | 62 | "UML\n"); |
96 | return -EIO; | 63 | return -EIO; |
97 | } | 64 | } |
@@ -99,14 +66,14 @@ static int not_configged_console_write(int fd, const char *buf, int len) | |||
99 | static int not_configged_window_size(int fd, void *data, unsigned short *rows, | 66 | static int not_configged_window_size(int fd, void *data, unsigned short *rows, |
100 | unsigned short *cols) | 67 | unsigned short *cols) |
101 | { | 68 | { |
102 | my_puts("Using a channel type which is configured out of " | 69 | printk("Using a channel type which is configured out of " |
103 | "UML\n"); | 70 | "UML\n"); |
104 | return -ENODEV; | 71 | return -ENODEV; |
105 | } | 72 | } |
106 | 73 | ||
107 | static void not_configged_free(void *data) | 74 | static void not_configged_free(void *data) |
108 | { | 75 | { |
109 | my_puts("Using a channel type which is configured out of " | 76 | printk("Using a channel type which is configured out of " |
110 | "UML\n"); | 77 | "UML\n"); |
111 | } | 78 | } |
112 | 79 | ||
@@ -255,15 +222,28 @@ void enable_chan(struct line *line) | |||
255 | } | 222 | } |
256 | } | 223 | } |
257 | 224 | ||
225 | /* Items are added in IRQ context, when free_irq can't be called, and | ||
226 | * removed in process context, when it can. | ||
227 | * This handles interrupt sources which disappear, and which need to | ||
228 | * be permanently disabled. This is discovered in IRQ context, but | ||
229 | * the freeing of the IRQ must be done later. | ||
230 | */ | ||
231 | static DEFINE_SPINLOCK(irqs_to_free_lock); | ||
258 | static LIST_HEAD(irqs_to_free); | 232 | static LIST_HEAD(irqs_to_free); |
259 | 233 | ||
260 | void free_irqs(void) | 234 | void free_irqs(void) |
261 | { | 235 | { |
262 | struct chan *chan; | 236 | struct chan *chan; |
237 | LIST_HEAD(list); | ||
238 | struct list_head *ele; | ||
263 | 239 | ||
264 | while(!list_empty(&irqs_to_free)){ | 240 | spin_lock_irq(&irqs_to_free_lock); |
265 | chan = list_entry(irqs_to_free.next, struct chan, free_list); | 241 | list_splice_init(&irqs_to_free, &list); |
266 | list_del(&chan->free_list); | 242 | INIT_LIST_HEAD(&irqs_to_free); |
243 | spin_unlock_irq(&irqs_to_free_lock); | ||
244 | |||
245 | list_for_each(ele, &list){ | ||
246 | chan = list_entry(ele, struct chan, free_list); | ||
267 | 247 | ||
268 | if(chan->input) | 248 | if(chan->input) |
269 | free_irq(chan->line->driver->read_irq, chan); | 249 | free_irq(chan->line->driver->read_irq, chan); |
@@ -279,7 +259,9 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) | |||
279 | return; | 259 | return; |
280 | 260 | ||
281 | if(delay_free_irq){ | 261 | if(delay_free_irq){ |
262 | spin_lock_irq(&irqs_to_free_lock); | ||
282 | list_add(&chan->free_list, &irqs_to_free); | 263 | list_add(&chan->free_list, &irqs_to_free); |
264 | spin_unlock_irq(&irqs_to_free_lock); | ||
283 | } | 265 | } |
284 | else { | 266 | else { |
285 | if(chan->input) | 267 | if(chan->input) |
@@ -372,8 +354,7 @@ int console_write_chan(struct list_head *chans, const char *buf, int len) | |||
372 | return ret; | 354 | return ret; |
373 | } | 355 | } |
374 | 356 | ||
375 | int console_open_chan(struct line *line, struct console *co, | 357 | int console_open_chan(struct line *line, struct console *co) |
376 | const struct chan_opts *opts) | ||
377 | { | 358 | { |
378 | int err; | 359 | int err; |
379 | 360 | ||
@@ -381,7 +362,7 @@ int console_open_chan(struct line *line, struct console *co, | |||
381 | if(err) | 362 | if(err) |
382 | return err; | 363 | return err; |
383 | 364 | ||
384 | printk("Console initialized on /dev/%s%d\n",co->name,co->index); | 365 | printk("Console initialized on /dev/%s%d\n", co->name, co->index); |
385 | return 0; | 366 | return 0; |
386 | } | 367 | } |
387 | 368 | ||
@@ -534,7 +515,7 @@ static const struct chan_type chan_table[] = { | |||
534 | }; | 515 | }; |
535 | 516 | ||
536 | static struct chan *parse_chan(struct line *line, char *str, int device, | 517 | static struct chan *parse_chan(struct line *line, char *str, int device, |
537 | const struct chan_opts *opts) | 518 | const struct chan_opts *opts, char **error_out) |
538 | { | 519 | { |
539 | const struct chan_type *entry; | 520 | const struct chan_type *entry; |
540 | const struct chan_ops *ops; | 521 | const struct chan_ops *ops; |
@@ -553,19 +534,21 @@ static struct chan *parse_chan(struct line *line, char *str, int device, | |||
553 | } | 534 | } |
554 | } | 535 | } |
555 | if(ops == NULL){ | 536 | if(ops == NULL){ |
556 | my_printf("parse_chan couldn't parse \"%s\"\n", | 537 | *error_out = "No match for configured backends"; |
557 | str); | ||
558 | return NULL; | 538 | return NULL; |
559 | } | 539 | } |
560 | if(ops->init == NULL) | 540 | |
561 | return NULL; | ||
562 | data = (*ops->init)(str, device, opts); | 541 | data = (*ops->init)(str, device, opts); |
563 | if(data == NULL) | 542 | if(data == NULL){ |
543 | *error_out = "Configuration failed"; | ||
564 | return NULL; | 544 | return NULL; |
545 | } | ||
565 | 546 | ||
566 | chan = kmalloc(sizeof(*chan), GFP_ATOMIC); | 547 | chan = kmalloc(sizeof(*chan), GFP_ATOMIC); |
567 | if(chan == NULL) | 548 | if(chan == NULL){ |
549 | *error_out = "Memory allocation failed"; | ||
568 | return NULL; | 550 | return NULL; |
551 | } | ||
569 | *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), | 552 | *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), |
570 | .free_list = | 553 | .free_list = |
571 | LIST_HEAD_INIT(chan->free_list), | 554 | LIST_HEAD_INIT(chan->free_list), |
@@ -582,7 +565,7 @@ static struct chan *parse_chan(struct line *line, char *str, int device, | |||
582 | } | 565 | } |
583 | 566 | ||
584 | int parse_chan_pair(char *str, struct line *line, int device, | 567 | int parse_chan_pair(char *str, struct line *line, int device, |
585 | const struct chan_opts *opts) | 568 | const struct chan_opts *opts, char **error_out) |
586 | { | 569 | { |
587 | struct list_head *chans = &line->chan_list; | 570 | struct list_head *chans = &line->chan_list; |
588 | struct chan *new, *chan; | 571 | struct chan *new, *chan; |
@@ -599,14 +582,14 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
599 | in = str; | 582 | in = str; |
600 | *out = '\0'; | 583 | *out = '\0'; |
601 | out++; | 584 | out++; |
602 | new = parse_chan(line, in, device, opts); | 585 | new = parse_chan(line, in, device, opts, error_out); |
603 | if(new == NULL) | 586 | if(new == NULL) |
604 | return -1; | 587 | return -1; |
605 | 588 | ||
606 | new->input = 1; | 589 | new->input = 1; |
607 | list_add(&new->list, chans); | 590 | list_add(&new->list, chans); |
608 | 591 | ||
609 | new = parse_chan(line, out, device, opts); | 592 | new = parse_chan(line, out, device, opts, error_out); |
610 | if(new == NULL) | 593 | if(new == NULL) |
611 | return -1; | 594 | return -1; |
612 | 595 | ||
@@ -614,7 +597,7 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
614 | new->output = 1; | 597 | new->output = 1; |
615 | } | 598 | } |
616 | else { | 599 | else { |
617 | new = parse_chan(line, str, device, opts); | 600 | new = parse_chan(line, str, device, opts, error_out); |
618 | if(new == NULL) | 601 | if(new == NULL) |
619 | return -1; | 602 | return -1; |
620 | 603 | ||