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