]> err.no Git - linux-2.6/blob - arch/um/drivers/chan_kern.c
uml: console subsystem tidying
[linux-2.6] / arch / um / drivers / chan_kern.c
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
3  * Licensed under the GPL
4  */
5
6 #include <linux/slab.h>
7 #include <linux/tty.h>
8 #include <linux/tty_flip.h>
9 #include "chan_kern.h"
10 #include "os.h"
11
12 #ifdef CONFIG_NOCONFIG_CHAN
13 static void *not_configged_init(char *str, int device,
14                                 const struct chan_opts *opts)
15 {
16         printk(KERN_ERR "Using a channel type which is configured out of "
17                "UML\n");
18         return NULL;
19 }
20
21 static int not_configged_open(int input, int output, int primary, void *data,
22                               char **dev_out)
23 {
24         printk(KERN_ERR "Using a channel type which is configured out of "
25                "UML\n");
26         return -ENODEV;
27 }
28
29 static void not_configged_close(int fd, void *data)
30 {
31         printk(KERN_ERR "Using a channel type which is configured out of "
32                "UML\n");
33 }
34
35 static int not_configged_read(int fd, char *c_out, void *data)
36 {
37         printk(KERN_ERR "Using a channel type which is configured out of "
38                "UML\n");
39         return -EIO;
40 }
41
42 static int not_configged_write(int fd, const char *buf, int len, void *data)
43 {
44         printk(KERN_ERR "Using a channel type which is configured out of "
45                "UML\n");
46         return -EIO;
47 }
48
49 static int not_configged_console_write(int fd, const char *buf, int len)
50 {
51         printk(KERN_ERR "Using a channel type which is configured out of "
52                "UML\n");
53         return -EIO;
54 }
55
56 static int not_configged_window_size(int fd, void *data, unsigned short *rows,
57                                      unsigned short *cols)
58 {
59         printk(KERN_ERR "Using a channel type which is configured out of "
60                "UML\n");
61         return -ENODEV;
62 }
63
64 static void not_configged_free(void *data)
65 {
66         printk(KERN_ERR "Using a channel type which is configured out of "
67                "UML\n");
68 }
69
70 static const struct chan_ops not_configged_ops = {
71         .init           = not_configged_init,
72         .open           = not_configged_open,
73         .close          = not_configged_close,
74         .read           = not_configged_read,
75         .write          = not_configged_write,
76         .console_write  = not_configged_console_write,
77         .window_size    = not_configged_window_size,
78         .free           = not_configged_free,
79         .winch          = 0,
80 };
81 #endif /* CONFIG_NOCONFIG_CHAN */
82
83 static void tty_receive_char(struct tty_struct *tty, char ch)
84 {
85         if (tty == NULL)
86                 return;
87
88         if (I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
89                 if (ch == STOP_CHAR(tty)) {
90                         stop_tty(tty);
91                         return;
92                 }
93                 else if (ch == START_CHAR(tty)) {
94                         start_tty(tty);
95                         return;
96                 }
97         }
98
99         tty_insert_flip_char(tty, ch, TTY_NORMAL);
100 }
101
102 static int open_one_chan(struct chan *chan)
103 {
104         int fd, err;
105
106         if (chan->opened)
107                 return 0;
108
109         if (chan->ops->open == NULL)
110                 fd = 0;
111         else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
112                                      chan->data, &chan->dev);
113         if (fd < 0)
114                 return fd;
115
116         err = os_set_fd_block(fd, 0);
117         if (err) {
118                 (*chan->ops->close)(fd, chan->data);
119                 return err;
120         }
121
122         chan->fd = fd;
123
124         chan->opened = 1;
125         return 0;
126 }
127
128 int open_chan(struct list_head *chans)
129 {
130         struct list_head *ele;
131         struct chan *chan;
132         int ret, err = 0;
133
134         list_for_each(ele, chans) {
135                 chan = list_entry(ele, struct chan, list);
136                 ret = open_one_chan(chan);
137                 if (chan->primary)
138                         err = ret;
139         }
140         return err;
141 }
142
143 void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
144 {
145         struct list_head *ele;
146         struct chan *chan;
147
148         list_for_each(ele, chans) {
149                 chan = list_entry(ele, struct chan, list);
150                 if (chan->primary && chan->output && chan->ops->winch) {
151                         register_winch(chan->fd, tty);
152                         return;
153                 }
154         }
155 }
156
157 int enable_chan(struct line *line)
158 {
159         struct list_head *ele;
160         struct chan *chan;
161         int err;
162
163         list_for_each(ele, &line->chan_list) {
164                 chan = list_entry(ele, struct chan, list);
165                 err = open_one_chan(chan);
166                 if (err) {
167                         if (chan->primary)
168                                 goto out_close;
169
170                         continue;
171                 }
172
173                 if (chan->enabled)
174                         continue;
175                 err = line_setup_irq(chan->fd, chan->input, chan->output, line,
176                                      chan);
177                 if (err)
178                         goto out_close;
179
180                 chan->enabled = 1;
181         }
182
183         return 0;
184
185  out_close:
186         close_chan(&line->chan_list, 0);
187         return err;
188 }
189
190 /* Items are added in IRQ context, when free_irq can't be called, and
191  * removed in process context, when it can.
192  * This handles interrupt sources which disappear, and which need to
193  * be permanently disabled.  This is discovered in IRQ context, but
194  * the freeing of the IRQ must be done later.
195  */
196 static DEFINE_SPINLOCK(irqs_to_free_lock);
197 static LIST_HEAD(irqs_to_free);
198
199 void free_irqs(void)
200 {
201         struct chan *chan;
202         LIST_HEAD(list);
203         struct list_head *ele;
204         unsigned long flags;
205
206         spin_lock_irqsave(&irqs_to_free_lock, flags);
207         list_splice_init(&irqs_to_free, &list);
208         spin_unlock_irqrestore(&irqs_to_free_lock, flags);
209
210         list_for_each(ele, &list) {
211                 chan = list_entry(ele, struct chan, free_list);
212
213                 if (chan->input)
214                         free_irq(chan->line->driver->read_irq, chan);
215                 if (chan->output)
216                         free_irq(chan->line->driver->write_irq, chan);
217                 chan->enabled = 0;
218         }
219 }
220
221 static void close_one_chan(struct chan *chan, int delay_free_irq)
222 {
223         unsigned long flags;
224
225         if (!chan->opened)
226                 return;
227
228         if (delay_free_irq) {
229                 spin_lock_irqsave(&irqs_to_free_lock, flags);
230                 list_add(&chan->free_list, &irqs_to_free);
231                 spin_unlock_irqrestore(&irqs_to_free_lock, flags);
232         }
233         else {
234                 if (chan->input)
235                         free_irq(chan->line->driver->read_irq, chan);
236                 if (chan->output)
237                         free_irq(chan->line->driver->write_irq, chan);
238                 chan->enabled = 0;
239         }
240         if (chan->ops->close != NULL)
241                 (*chan->ops->close)(chan->fd, chan->data);
242
243         chan->opened = 0;
244         chan->fd = -1;
245 }
246
247 void close_chan(struct list_head *chans, int delay_free_irq)
248 {
249         struct chan *chan;
250
251         /* Close in reverse order as open in case more than one of them
252          * refers to the same device and they save and restore that device's
253          * state.  Then, the first one opened will have the original state,
254          * so it must be the last closed.
255          */
256         list_for_each_entry_reverse(chan, chans, list) {
257                 close_one_chan(chan, delay_free_irq);
258         }
259 }
260
261 void deactivate_chan(struct list_head *chans, int irq)
262 {
263         struct list_head *ele;
264
265         struct chan *chan;
266         list_for_each(ele, chans) {
267                 chan = list_entry(ele, struct chan, list);
268
269                 if (chan->enabled && chan->input)
270                         deactivate_fd(chan->fd, irq);
271         }
272 }
273
274 void reactivate_chan(struct list_head *chans, int irq)
275 {
276         struct list_head *ele;
277         struct chan *chan;
278
279         list_for_each(ele, chans) {
280                 chan = list_entry(ele, struct chan, list);
281
282                 if (chan->enabled && chan->input)
283                         reactivate_fd(chan->fd, irq);
284         }
285 }
286
287 int write_chan(struct list_head *chans, const char *buf, int len,
288                int write_irq)
289 {
290         struct list_head *ele;
291         struct chan *chan = NULL;
292         int n, ret = 0;
293
294         list_for_each(ele, chans) {
295                 chan = list_entry(ele, struct chan, list);
296                 if (!chan->output || (chan->ops->write == NULL))
297                         continue;
298
299                 n = chan->ops->write(chan->fd, buf, len, chan->data);
300                 if (chan->primary) {
301                         ret = n;
302                         if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
303                                 reactivate_fd(chan->fd, write_irq);
304                 }
305         }
306         return ret;
307 }
308
309 int console_write_chan(struct list_head *chans, const char *buf, int len)
310 {
311         struct list_head *ele;
312         struct chan *chan;
313         int n, ret = 0;
314
315         list_for_each(ele, chans) {
316                 chan = list_entry(ele, struct chan, list);
317                 if (!chan->output || (chan->ops->console_write == NULL))
318                         continue;
319
320                 n = chan->ops->console_write(chan->fd, buf, len);
321                 if (chan->primary)
322                         ret = n;
323         }
324         return ret;
325 }
326
327 int console_open_chan(struct line *line, struct console *co)
328 {
329         int err;
330
331         err = open_chan(&line->chan_list);
332         if (err)
333                 return err;
334
335         printk(KERN_INFO "Console initialized on /dev/%s%d\n", co->name,
336                co->index);
337         return 0;
338 }
339
340 int chan_window_size(struct list_head *chans, unsigned short *rows_out,
341                       unsigned short *cols_out)
342 {
343         struct list_head *ele;
344         struct chan *chan;
345
346         list_for_each(ele, chans) {
347                 chan = list_entry(ele, struct chan, list);
348                 if (chan->primary) {
349                         if (chan->ops->window_size == NULL)
350                                 return 0;
351                         return chan->ops->window_size(chan->fd, chan->data,
352                                                       rows_out, cols_out);
353                 }
354         }
355         return 0;
356 }
357
358 static void free_one_chan(struct chan *chan, int delay_free_irq)
359 {
360         list_del(&chan->list);
361
362         close_one_chan(chan, delay_free_irq);
363
364         if (chan->ops->free != NULL)
365                 (*chan->ops->free)(chan->data);
366
367         if (chan->primary && chan->output)
368                 ignore_sigio_fd(chan->fd);
369         kfree(chan);
370 }
371
372 static void free_chan(struct list_head *chans, int delay_free_irq)
373 {
374         struct list_head *ele, *next;
375         struct chan *chan;
376
377         list_for_each_safe(ele, next, chans) {
378                 chan = list_entry(ele, struct chan, list);
379                 free_one_chan(chan, delay_free_irq);
380         }
381 }
382
383 static int one_chan_config_string(struct chan *chan, char *str, int size,
384                                   char **error_out)
385 {
386         int n = 0;
387
388         if (chan == NULL) {
389                 CONFIG_CHUNK(str, size, n, "none", 1);
390                 return n;
391         }
392
393         CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
394
395         if (chan->dev == NULL) {
396                 CONFIG_CHUNK(str, size, n, "", 1);
397                 return n;
398         }
399
400         CONFIG_CHUNK(str, size, n, ":", 0);
401         CONFIG_CHUNK(str, size, n, chan->dev, 0);
402
403         return n;
404 }
405
406 static int chan_pair_config_string(struct chan *in, struct chan *out,
407                                    char *str, int size, char **error_out)
408 {
409         int n;
410
411         n = one_chan_config_string(in, str, size, error_out);
412         str += n;
413         size -= n;
414
415         if (in == out) {
416                 CONFIG_CHUNK(str, size, n, "", 1);
417                 return n;
418         }
419
420         CONFIG_CHUNK(str, size, n, ",", 1);
421         n = one_chan_config_string(out, str, size, error_out);
422         str += n;
423         size -= n;
424         CONFIG_CHUNK(str, size, n, "", 1);
425
426         return n;
427 }
428
429 int chan_config_string(struct list_head *chans, char *str, int size,
430                        char **error_out)
431 {
432         struct list_head *ele;
433         struct chan *chan, *in = NULL, *out = NULL;
434
435         list_for_each(ele, chans) {
436                 chan = list_entry(ele, struct chan, list);
437                 if (!chan->primary)
438                         continue;
439                 if (chan->input)
440                         in = chan;
441                 if (chan->output)
442                         out = chan;
443         }
444
445         return chan_pair_config_string(in, out, str, size, error_out);
446 }
447
448 struct chan_type {
449         char *key;
450         const struct chan_ops *ops;
451 };
452
453 static const struct chan_type chan_table[] = {
454         { "fd", &fd_ops },
455
456 #ifdef CONFIG_NULL_CHAN
457         { "null", &null_ops },
458 #else
459         { "null", &not_configged_ops },
460 #endif
461
462 #ifdef CONFIG_PORT_CHAN
463         { "port", &port_ops },
464 #else
465         { "port", &not_configged_ops },
466 #endif
467
468 #ifdef CONFIG_PTY_CHAN
469         { "pty", &pty_ops },
470         { "pts", &pts_ops },
471 #else
472         { "pty", &not_configged_ops },
473         { "pts", &not_configged_ops },
474 #endif
475
476 #ifdef CONFIG_TTY_CHAN
477         { "tty", &tty_ops },
478 #else
479         { "tty", &not_configged_ops },
480 #endif
481
482 #ifdef CONFIG_XTERM_CHAN
483         { "xterm", &xterm_ops },
484 #else
485         { "xterm", &not_configged_ops },
486 #endif
487 };
488
489 static struct chan *parse_chan(struct line *line, char *str, int device,
490                                const struct chan_opts *opts, char **error_out)
491 {
492         const struct chan_type *entry;
493         const struct chan_ops *ops;
494         struct chan *chan;
495         void *data;
496         int i;
497
498         ops = NULL;
499         data = NULL;
500         for(i = 0; i < ARRAY_SIZE(chan_table); i++) {
501                 entry = &chan_table[i];
502                 if (!strncmp(str, entry->key, strlen(entry->key))) {
503                         ops = entry->ops;
504                         str += strlen(entry->key);
505                         break;
506                 }
507         }
508         if (ops == NULL) {
509                 *error_out = "No match for configured backends";
510                 return NULL;
511         }
512
513         data = (*ops->init)(str, device, opts);
514         if (data == NULL) {
515                 *error_out = "Configuration failed";
516                 return NULL;
517         }
518
519         chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
520         if (chan == NULL) {
521                 *error_out = "Memory allocation failed";
522                 return NULL;
523         }
524         *chan = ((struct chan) { .list          = LIST_HEAD_INIT(chan->list),
525                                  .free_list     =
526                                         LIST_HEAD_INIT(chan->free_list),
527                                  .line          = line,
528                                  .primary       = 1,
529                                  .input         = 0,
530                                  .output        = 0,
531                                  .opened        = 0,
532                                  .enabled       = 0,
533                                  .fd            = -1,
534                                  .ops           = ops,
535                                  .data          = data });
536         return chan;
537 }
538
539 int parse_chan_pair(char *str, struct line *line, int device,
540                     const struct chan_opts *opts, char **error_out)
541 {
542         struct list_head *chans = &line->chan_list;
543         struct chan *new, *chan;
544         char *in, *out;
545
546         if (!list_empty(chans)) {
547                 chan = list_entry(chans->next, struct chan, list);
548                 free_chan(chans, 0);
549                 INIT_LIST_HEAD(chans);
550         }
551
552         out = strchr(str, ',');
553         if (out != NULL) {
554                 in = str;
555                 *out = '\0';
556                 out++;
557                 new = parse_chan(line, in, device, opts, error_out);
558                 if (new == NULL)
559                         return -1;
560
561                 new->input = 1;
562                 list_add(&new->list, chans);
563
564                 new = parse_chan(line, out, device, opts, error_out);
565                 if (new == NULL)
566                         return -1;
567
568                 list_add(&new->list, chans);
569                 new->output = 1;
570         }
571         else {
572                 new = parse_chan(line, str, device, opts, error_out);
573                 if (new == NULL)
574                         return -1;
575
576                 list_add(&new->list, chans);
577                 new->input = 1;
578                 new->output = 1;
579         }
580         return 0;
581 }
582
583 int chan_out_fd(struct list_head *chans)
584 {
585         struct list_head *ele;
586         struct chan *chan;
587
588         list_for_each(ele, chans) {
589                 chan = list_entry(ele, struct chan, list);
590                 if (chan->primary && chan->output)
591                         return chan->fd;
592         }
593         return -1;
594 }
595
596 void chan_interrupt(struct list_head *chans, struct delayed_work *task,
597                     struct tty_struct *tty, int irq)
598 {
599         struct list_head *ele, *next;
600         struct chan *chan;
601         int err;
602         char c;
603
604         list_for_each_safe(ele, next, chans) {
605                 chan = list_entry(ele, struct chan, list);
606                 if (!chan->input || (chan->ops->read == NULL))
607                         continue;
608                 do {
609                         if (tty && !tty_buffer_request_room(tty, 1)) {
610                                 schedule_delayed_work(task, 1);
611                                 goto out;
612                         }
613                         err = chan->ops->read(chan->fd, &c, chan->data);
614                         if (err > 0)
615                                 tty_receive_char(tty, c);
616                 } while (err > 0);
617
618                 if (err == 0)
619                         reactivate_fd(chan->fd, irq);
620                 if (err == -EIO) {
621                         if (chan->primary) {
622                                 if (tty != NULL)
623                                         tty_hangup(tty);
624                                 close_chan(chans, 1);
625                                 return;
626                         }
627                         else close_one_chan(chan, 1);
628                 }
629         }
630  out:
631         if (tty)
632                 tty_flip_buffer_push(tty);
633 }