Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched
[linux-2.6] / 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;
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         chan->fd = fd;
172
173         chan->opened = 1;
174         return 0;
175 }
176
177 int open_chan(struct list_head *chans)
178 {
179         struct list_head *ele;
180         struct chan *chan;
181         int ret, err = 0;
182
183         list_for_each(ele, chans){
184                 chan = list_entry(ele, struct chan, list);
185                 ret = open_one_chan(chan);
186                 if(chan->primary)
187                         err = ret;
188         }
189         return err;
190 }
191
192 void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
193 {
194         struct list_head *ele;
195         struct chan *chan;
196
197         list_for_each(ele, chans){
198                 chan = list_entry(ele, struct chan, list);
199                 if(chan->primary && chan->output && chan->ops->winch){
200                         register_winch(chan->fd, tty);
201                         return;
202                 }
203         }
204 }
205
206 int enable_chan(struct line *line)
207 {
208         struct list_head *ele;
209         struct chan *chan;
210         int err;
211
212         list_for_each(ele, &line->chan_list){
213                 chan = list_entry(ele, struct chan, list);
214                 err = open_one_chan(chan);
215                 if (err) {
216                         if (chan->primary)
217                                 goto out_close;
218
219                         continue;
220                 }
221
222                 if(chan->enabled)
223                         continue;
224                 err = line_setup_irq(chan->fd, chan->input, chan->output, line,
225                                      chan);
226                 if (err)
227                         goto out_close;
228
229                 chan->enabled = 1;
230         }
231
232         return 0;
233
234  out_close:
235         close_chan(&line->chan_list, 0);
236         return err;
237 }
238
239 /* Items are added in IRQ context, when free_irq can't be called, and
240  * removed in process context, when it can.
241  * This handles interrupt sources which disappear, and which need to
242  * be permanently disabled.  This is discovered in IRQ context, but
243  * the freeing of the IRQ must be done later.
244  */
245 static DEFINE_SPINLOCK(irqs_to_free_lock);
246 static LIST_HEAD(irqs_to_free);
247
248 void free_irqs(void)
249 {
250         struct chan *chan;
251         LIST_HEAD(list);
252         struct list_head *ele;
253         unsigned long flags;
254
255         spin_lock_irqsave(&irqs_to_free_lock, flags);
256         list_splice_init(&irqs_to_free, &list);
257         spin_unlock_irqrestore(&irqs_to_free_lock, flags);
258
259         list_for_each(ele, &list){
260                 chan = list_entry(ele, struct chan, free_list);
261
262                 if(chan->input)
263                         free_irq(chan->line->driver->read_irq, chan);
264                 if(chan->output)
265                         free_irq(chan->line->driver->write_irq, chan);
266                 chan->enabled = 0;
267         }
268 }
269
270 static void close_one_chan(struct chan *chan, int delay_free_irq)
271 {
272         unsigned long flags;
273
274         if(!chan->opened)
275                 return;
276
277         if(delay_free_irq){
278                 spin_lock_irqsave(&irqs_to_free_lock, flags);
279                 list_add(&chan->free_list, &irqs_to_free);
280                 spin_unlock_irqrestore(&irqs_to_free_lock, flags);
281         }
282         else {
283                 if(chan->input)
284                         free_irq(chan->line->driver->read_irq, chan);
285                 if(chan->output)
286                         free_irq(chan->line->driver->write_irq, chan);
287                 chan->enabled = 0;
288         }
289         if(chan->ops->close != NULL)
290                 (*chan->ops->close)(chan->fd, chan->data);
291
292         chan->opened = 0;
293         chan->fd = -1;
294 }
295
296 void close_chan(struct list_head *chans, int delay_free_irq)
297 {
298         struct chan *chan;
299
300         /* Close in reverse order as open in case more than one of them
301          * refers to the same device and they save and restore that device's
302          * state.  Then, the first one opened will have the original state,
303          * so it must be the last closed.
304          */
305         list_for_each_entry_reverse(chan, chans, list) {
306                 close_one_chan(chan, delay_free_irq);
307         }
308 }
309
310 void deactivate_chan(struct list_head *chans, int irq)
311 {
312         struct list_head *ele;
313
314         struct chan *chan;
315         list_for_each(ele, chans) {
316                 chan = list_entry(ele, struct chan, list);
317
318                 if(chan->enabled && chan->input)
319                         deactivate_fd(chan->fd, irq);
320         }
321 }
322
323 void reactivate_chan(struct list_head *chans, int irq)
324 {
325         struct list_head *ele;
326         struct chan *chan;
327
328         list_for_each(ele, chans) {
329                 chan = list_entry(ele, struct chan, list);
330
331                 if(chan->enabled && chan->input)
332                         reactivate_fd(chan->fd, irq);
333         }
334 }
335
336 int write_chan(struct list_head *chans, const char *buf, int len,
337                int write_irq)
338 {
339         struct list_head *ele;
340         struct chan *chan = NULL;
341         int n, ret = 0;
342
343         list_for_each(ele, chans) {
344                 chan = list_entry(ele, struct chan, list);
345                 if (!chan->output || (chan->ops->write == NULL))
346                         continue;
347                 n = chan->ops->write(chan->fd, buf, len, chan->data);
348                 if (chan->primary) {
349                         ret = n;
350                         if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
351                                 reactivate_fd(chan->fd, write_irq);
352                 }
353         }
354         return ret;
355 }
356
357 int console_write_chan(struct list_head *chans, const char *buf, int len)
358 {
359         struct list_head *ele;
360         struct chan *chan;
361         int n, ret = 0;
362
363         list_for_each(ele, chans){
364                 chan = list_entry(ele, struct chan, list);
365                 if(!chan->output || (chan->ops->console_write == NULL))
366                         continue;
367                 n = chan->ops->console_write(chan->fd, buf, len);
368                 if(chan->primary) ret = n;
369         }
370         return ret;
371 }
372
373 int console_open_chan(struct line *line, struct console *co)
374 {
375         int err;
376
377         err = open_chan(&line->chan_list);
378         if(err)
379                 return err;
380
381         printk("Console initialized on /dev/%s%d\n", co->name, co->index);
382         return 0;
383 }
384
385 int chan_window_size(struct list_head *chans, unsigned short *rows_out,
386                       unsigned short *cols_out)
387 {
388         struct list_head *ele;
389         struct chan *chan;
390
391         list_for_each(ele, chans){
392                 chan = list_entry(ele, struct chan, list);
393                 if(chan->primary){
394                         if(chan->ops->window_size == NULL)
395                                 return 0;
396                         return chan->ops->window_size(chan->fd, chan->data,
397                                                       rows_out, cols_out);
398                 }
399         }
400         return 0;
401 }
402
403 static void free_one_chan(struct chan *chan, int delay_free_irq)
404 {
405         list_del(&chan->list);
406
407         close_one_chan(chan, delay_free_irq);
408
409         if(chan->ops->free != NULL)
410                 (*chan->ops->free)(chan->data);
411
412         if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
413         kfree(chan);
414 }
415
416 static void free_chan(struct list_head *chans, int delay_free_irq)
417 {
418         struct list_head *ele, *next;
419         struct chan *chan;
420
421         list_for_each_safe(ele, next, chans){
422                 chan = list_entry(ele, struct chan, list);
423                 free_one_chan(chan, delay_free_irq);
424         }
425 }
426
427 static int one_chan_config_string(struct chan *chan, char *str, int size,
428                                   char **error_out)
429 {
430         int n = 0;
431
432         if(chan == NULL){
433                 CONFIG_CHUNK(str, size, n, "none", 1);
434                 return n;
435         }
436
437         CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
438
439         if(chan->dev == NULL){
440                 CONFIG_CHUNK(str, size, n, "", 1);
441                 return n;
442         }
443
444         CONFIG_CHUNK(str, size, n, ":", 0);
445         CONFIG_CHUNK(str, size, n, chan->dev, 0);
446
447         return n;
448 }
449
450 static int chan_pair_config_string(struct chan *in, struct chan *out,
451                                    char *str, int size, char **error_out)
452 {
453         int n;
454
455         n = one_chan_config_string(in, str, size, error_out);
456         str += n;
457         size -= n;
458
459         if(in == out){
460                 CONFIG_CHUNK(str, size, n, "", 1);
461                 return n;
462         }
463
464         CONFIG_CHUNK(str, size, n, ",", 1);
465         n = one_chan_config_string(out, str, size, error_out);
466         str += n;
467         size -= n;
468         CONFIG_CHUNK(str, size, n, "", 1);
469
470         return n;
471 }
472
473 int chan_config_string(struct list_head *chans, char *str, int size,
474                        char **error_out)
475 {
476         struct list_head *ele;
477         struct chan *chan, *in = NULL, *out = NULL;
478
479         list_for_each(ele, chans){
480                 chan = list_entry(ele, struct chan, list);
481                 if(!chan->primary)
482                         continue;
483                 if(chan->input)
484                         in = chan;
485                 if(chan->output)
486                         out = chan;
487         }
488
489         return chan_pair_config_string(in, out, str, size, error_out);
490 }
491
492 struct chan_type {
493         char *key;
494         const struct chan_ops *ops;
495 };
496
497 static const struct chan_type chan_table[] = {
498         { "fd", &fd_ops },
499
500 #ifdef CONFIG_NULL_CHAN
501         { "null", &null_ops },
502 #else
503         { "null", &not_configged_ops },
504 #endif
505
506 #ifdef CONFIG_PORT_CHAN
507         { "port", &port_ops },
508 #else
509         { "port", &not_configged_ops },
510 #endif
511
512 #ifdef CONFIG_PTY_CHAN
513         { "pty", &pty_ops },
514         { "pts", &pts_ops },
515 #else
516         { "pty", &not_configged_ops },
517         { "pts", &not_configged_ops },
518 #endif
519
520 #ifdef CONFIG_TTY_CHAN
521         { "tty", &tty_ops },
522 #else
523         { "tty", &not_configged_ops },
524 #endif
525
526 #ifdef CONFIG_XTERM_CHAN
527         { "xterm", &xterm_ops },
528 #else
529         { "xterm", &not_configged_ops },
530 #endif
531 };
532
533 static struct chan *parse_chan(struct line *line, char *str, int device,
534                                const struct chan_opts *opts, char **error_out)
535 {
536         const struct chan_type *entry;
537         const struct chan_ops *ops;
538         struct chan *chan;
539         void *data;
540         int i;
541
542         ops = NULL;
543         data = NULL;
544         for(i = 0; i < ARRAY_SIZE(chan_table); i++){
545                 entry = &chan_table[i];
546                 if(!strncmp(str, entry->key, strlen(entry->key))){
547                         ops = entry->ops;
548                         str += strlen(entry->key);
549                         break;
550                 }
551         }
552         if(ops == NULL){
553                 *error_out = "No match for configured backends";
554                 return NULL;
555         }
556
557         data = (*ops->init)(str, device, opts);
558         if(data == NULL){
559                 *error_out = "Configuration failed";
560                 return NULL;
561         }
562
563         chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
564         if(chan == NULL){
565                 *error_out = "Memory allocation failed";
566                 return NULL;
567         }
568         *chan = ((struct chan) { .list          = LIST_HEAD_INIT(chan->list),
569                                  .free_list     =
570                                         LIST_HEAD_INIT(chan->free_list),
571                                  .line          = line,
572                                  .primary       = 1,
573                                  .input         = 0,
574                                  .output        = 0,
575                                  .opened        = 0,
576                                  .enabled       = 0,
577                                  .fd            = -1,
578                                  .ops           = ops,
579                                  .data          = data });
580         return chan;
581 }
582
583 int parse_chan_pair(char *str, struct line *line, int device,
584                     const struct chan_opts *opts, char **error_out)
585 {
586         struct list_head *chans = &line->chan_list;
587         struct chan *new, *chan;
588         char *in, *out;
589
590         if(!list_empty(chans)){
591                 chan = list_entry(chans->next, struct chan, list);
592                 free_chan(chans, 0);
593                 INIT_LIST_HEAD(chans);
594         }
595
596         out = strchr(str, ',');
597         if(out != NULL){
598                 in = str;
599                 *out = '\0';
600                 out++;
601                 new = parse_chan(line, in, device, opts, error_out);
602                 if(new == NULL)
603                         return -1;
604
605                 new->input = 1;
606                 list_add(&new->list, chans);
607
608                 new = parse_chan(line, out, device, opts, error_out);
609                 if(new == NULL)
610                         return -1;
611
612                 list_add(&new->list, chans);
613                 new->output = 1;
614         }
615         else {
616                 new = parse_chan(line, str, device, opts, error_out);
617                 if(new == NULL)
618                         return -1;
619
620                 list_add(&new->list, chans);
621                 new->input = 1;
622                 new->output = 1;
623         }
624         return 0;
625 }
626
627 int chan_out_fd(struct list_head *chans)
628 {
629         struct list_head *ele;
630         struct chan *chan;
631
632         list_for_each(ele, chans){
633                 chan = list_entry(ele, struct chan, list);
634                 if(chan->primary && chan->output)
635                         return chan->fd;
636         }
637         return -1;
638 }
639
640 void chan_interrupt(struct list_head *chans, struct delayed_work *task,
641                     struct tty_struct *tty, int irq)
642 {
643         struct list_head *ele, *next;
644         struct chan *chan;
645         int err;
646         char c;
647
648         list_for_each_safe(ele, next, chans){
649                 chan = list_entry(ele, struct chan, list);
650                 if(!chan->input || (chan->ops->read == NULL)) continue;
651                 do {
652                         if (tty && !tty_buffer_request_room(tty, 1)) {
653                                 schedule_delayed_work(task, 1);
654                                 goto out;
655                         }
656                         err = chan->ops->read(chan->fd, &c, chan->data);
657                         if(err > 0)
658                                 tty_receive_char(tty, c);
659                 } while(err > 0);
660
661                 if(err == 0) reactivate_fd(chan->fd, irq);
662                 if(err == -EIO){
663                         if(chan->primary){
664                                 if(tty != NULL)
665                                         tty_hangup(tty);
666                                 close_chan(chans, 1);
667                                 return;
668                         }
669                         else close_one_chan(chan, 1);
670                 }
671         }
672  out:
673         if(tty) tty_flip_buffer_push(tty);
674 }