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