[PATCH] uml: Formatting changes
[linux-2.6-microblaze.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 "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 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         if((tty->flip.flag_buf_ptr == NULL) ||
190            (tty->flip.char_buf_ptr == NULL))
191                 return;
192         tty_insert_flip_char(tty, ch, TTY_NORMAL);
193 }
194
195 static int open_one_chan(struct chan *chan)
196 {
197         int fd;
198
199         if(chan->opened)
200                 return 0;
201
202         if(chan->ops->open == NULL)
203                 fd = 0;
204         else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
205                                      chan->data, &chan->dev);
206         if(fd < 0)
207                 return fd;
208         chan->fd = fd;
209
210         chan->opened = 1;
211         return 0;
212 }
213
214 int open_chan(struct list_head *chans)
215 {
216         struct list_head *ele;
217         struct chan *chan;
218         int ret, err = 0;
219
220         list_for_each(ele, chans){
221                 chan = list_entry(ele, struct chan, list);
222                 ret = open_one_chan(chan);
223                 if(chan->primary)
224                         err = ret;
225         }
226         return err;
227 }
228
229 void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
230 {
231         struct list_head *ele;
232         struct chan *chan;
233
234         list_for_each(ele, chans){
235                 chan = list_entry(ele, struct chan, list);
236                 if(chan->primary && chan->output && chan->ops->winch){
237                         register_winch(chan->fd, tty);
238                         return;
239                 }
240         }
241 }
242
243 void enable_chan(struct list_head *chans, struct tty_struct *tty)
244 {
245         struct list_head *ele;
246         struct chan *chan;
247
248         list_for_each(ele, chans){
249                 chan = list_entry(ele, struct chan, list);
250                 if(!chan->opened) continue;
251
252                 line_setup_irq(chan->fd, chan->input, chan->output, tty);
253         }
254 }
255
256 void close_chan(struct list_head *chans)
257 {
258         struct chan *chan;
259
260         /* Close in reverse order as open in case more than one of them
261          * refers to the same device and they save and restore that device's
262          * state.  Then, the first one opened will have the original state,
263          * so it must be the last closed.
264          */
265         list_for_each_entry_reverse(chan, chans, list) {
266                 if(!chan->opened) continue;
267                 if(chan->ops->close != NULL)
268                         (*chan->ops->close)(chan->fd, chan->data);
269                 chan->opened = 0;
270                 chan->fd = -1;
271         }
272 }
273
274 int write_chan(struct list_head *chans, const char *buf, int len,
275                int write_irq)
276 {
277         struct list_head *ele;
278         struct chan *chan = NULL;
279         int n, ret = 0;
280
281         list_for_each(ele, chans) {
282                 chan = list_entry(ele, struct chan, list);
283                 if (!chan->output || (chan->ops->write == NULL))
284                         continue;
285                 n = chan->ops->write(chan->fd, buf, len, chan->data);
286                 if (chan->primary) {
287                         ret = n;
288                         if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
289                                 reactivate_fd(chan->fd, write_irq);
290                 }
291         }
292         return ret;
293 }
294
295 int console_write_chan(struct list_head *chans, const char *buf, int len)
296 {
297         struct list_head *ele;
298         struct chan *chan;
299         int n, ret = 0;
300
301         list_for_each(ele, chans){
302                 chan = list_entry(ele, struct chan, list);
303                 if(!chan->output || (chan->ops->console_write == NULL))
304                         continue;
305                 n = chan->ops->console_write(chan->fd, buf, len);
306                 if(chan->primary) ret = n;
307         }
308         return ret;
309 }
310
311 int console_open_chan(struct line *line, struct console *co,
312                       struct chan_opts *opts)
313 {
314         if (!list_empty(&line->chan_list))
315                 return 0;
316
317         if (0 != parse_chan_pair(line->init_str, &line->chan_list,
318                                  line->init_pri, co->index, opts))
319                 return -1;
320         if (0 != open_chan(&line->chan_list))
321                 return -1;
322         printk("Console initialized on /dev/%s%d\n",co->name,co->index);
323         return 0;
324 }
325
326 int chan_window_size(struct list_head *chans, unsigned short *rows_out,
327                       unsigned short *cols_out)
328 {
329         struct list_head *ele;
330         struct chan *chan;
331
332         list_for_each(ele, chans){
333                 chan = list_entry(ele, struct chan, list);
334                 if(chan->primary){
335                         if(chan->ops->window_size == NULL)
336                                 return 0;
337                         return chan->ops->window_size(chan->fd, chan->data,
338                                                       rows_out, cols_out);
339                 }
340         }
341         return 0;
342 }
343
344 void free_one_chan(struct chan *chan)
345 {
346         list_del(&chan->list);
347         if(chan->ops->free != NULL)
348                 (*chan->ops->free)(chan->data);
349         free_irq_by_fd(chan->fd);
350         if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
351         kfree(chan);
352 }
353
354 void free_chan(struct list_head *chans)
355 {
356         struct list_head *ele, *next;
357         struct chan *chan;
358
359         list_for_each_safe(ele, next, chans){
360                 chan = list_entry(ele, struct chan, list);
361                 free_one_chan(chan);
362         }
363 }
364
365 static int one_chan_config_string(struct chan *chan, char *str, int size,
366                                   char **error_out)
367 {
368         int n = 0;
369
370         if(chan == NULL){
371                 CONFIG_CHUNK(str, size, n, "none", 1);
372                 return n;
373         }
374
375         CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
376
377         if(chan->dev == NULL){
378                 CONFIG_CHUNK(str, size, n, "", 1);
379                 return n;
380         }
381
382         CONFIG_CHUNK(str, size, n, ":", 0);
383         CONFIG_CHUNK(str, size, n, chan->dev, 0);
384
385         return n;
386 }
387
388 static int chan_pair_config_string(struct chan *in, struct chan *out,
389                                    char *str, int size, char **error_out)
390 {
391         int n;
392
393         n = one_chan_config_string(in, str, size, error_out);
394         str += n;
395         size -= n;
396
397         if(in == out){
398                 CONFIG_CHUNK(str, size, n, "", 1);
399                 return n;
400         }
401
402         CONFIG_CHUNK(str, size, n, ",", 1);
403         n = one_chan_config_string(out, str, size, error_out);
404         str += n;
405         size -= n;
406         CONFIG_CHUNK(str, size, n, "", 1);
407
408         return n;
409 }
410
411 int chan_config_string(struct list_head *chans, char *str, int size,
412                        char **error_out)
413 {
414         struct list_head *ele;
415         struct chan *chan, *in = NULL, *out = NULL;
416
417         list_for_each(ele, chans){
418                 chan = list_entry(ele, struct chan, list);
419                 if(!chan->primary)
420                         continue;
421                 if(chan->input)
422                         in = chan;
423                 if(chan->output)
424                         out = chan;
425         }
426
427         return chan_pair_config_string(in, out, str, size, error_out);
428 }
429
430 struct chan_type {
431         char *key;
432         struct chan_ops *ops;
433 };
434
435 struct chan_type chan_table[] = {
436         { "fd", &fd_ops },
437
438 #ifdef CONFIG_NULL_CHAN
439         { "null", &null_ops },
440 #else
441         { "null", &not_configged_ops },
442 #endif
443
444 #ifdef CONFIG_PORT_CHAN
445         { "port", &port_ops },
446 #else
447         { "port", &not_configged_ops },
448 #endif
449
450 #ifdef CONFIG_PTY_CHAN
451         { "pty", &pty_ops },
452         { "pts", &pts_ops },
453 #else
454         { "pty", &not_configged_ops },
455         { "pts", &not_configged_ops },
456 #endif
457
458 #ifdef CONFIG_TTY_CHAN
459         { "tty", &tty_ops },
460 #else
461         { "tty", &not_configged_ops },
462 #endif
463
464 #ifdef CONFIG_XTERM_CHAN
465         { "xterm", &xterm_ops },
466 #else
467         { "xterm", &not_configged_ops },
468 #endif
469 };
470
471 static struct chan *parse_chan(char *str, int pri, int device,
472                                struct chan_opts *opts)
473 {
474         struct chan_type *entry;
475         struct chan_ops *ops;
476         struct chan *chan;
477         void *data;
478         int i;
479
480         ops = NULL;
481         data = NULL;
482         for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
483                 entry = &chan_table[i];
484                 if(!strncmp(str, entry->key, strlen(entry->key))){
485                         ops = entry->ops;
486                         str += strlen(entry->key);
487                         break;
488                 }
489         }
490         if(ops == NULL){
491                 my_printf("parse_chan couldn't parse \"%s\"\n",
492                        str);
493                 return NULL;
494         }
495         if(ops->init == NULL)
496                 return NULL;
497         data = (*ops->init)(str, device, opts);
498         if(data == NULL)
499                 return NULL;
500
501         chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
502         if(chan == NULL)
503                 return NULL;
504         *chan = ((struct chan) { .list          = LIST_HEAD_INIT(chan->list),
505                                  .primary       = 1,
506                                  .input         = 0,
507                                  .output        = 0,
508                                  .opened        = 0,
509                                  .fd            = -1,
510                                  .pri           = pri,
511                                  .ops           = ops,
512                                  .data          = data });
513         return chan;
514 }
515
516 int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
517                     struct chan_opts *opts)
518 {
519         struct chan *new, *chan;
520         char *in, *out;
521
522         if(!list_empty(chans)){
523                 chan = list_entry(chans->next, struct chan, list);
524                 if(chan->pri >= pri)
525                         return 0;
526                 free_chan(chans);
527                 INIT_LIST_HEAD(chans);
528         }
529
530         out = strchr(str, ',');
531         if(out != NULL){
532                 in = str;
533                 *out = '\0';
534                 out++;
535                 new = parse_chan(in, pri, device, opts);
536                 if(new == NULL)
537                         return -1;
538
539                 new->input = 1;
540                 list_add(&new->list, chans);
541
542                 new = parse_chan(out, pri, device, opts);
543                 if(new == NULL)
544                         return -1;
545
546                 list_add(&new->list, chans);
547                 new->output = 1;
548         }
549         else {
550                 new = parse_chan(str, pri, device, opts);
551                 if(new == NULL)
552                         return -1;
553
554                 list_add(&new->list, chans);
555                 new->input = 1;
556                 new->output = 1;
557         }
558         return 0;
559 }
560
561 int chan_out_fd(struct list_head *chans)
562 {
563         struct list_head *ele;
564         struct chan *chan;
565
566         list_for_each(ele, chans){
567                 chan = list_entry(ele, struct chan, list);
568                 if(chan->primary && chan->output)
569                         return chan->fd;
570         }
571         return -1;
572 }
573
574 void chan_interrupt(struct list_head *chans, struct work_struct *task,
575                     struct tty_struct *tty, int irq)
576 {
577         struct list_head *ele, *next;
578         struct chan *chan;
579         int err;
580         char c;
581
582         list_for_each_safe(ele, next, chans){
583                 chan = list_entry(ele, struct chan, list);
584                 if(!chan->input || (chan->ops->read == NULL)) continue;
585                 do {
586                         if((tty != NULL) &&
587                            (tty->flip.count >= TTY_FLIPBUF_SIZE)){
588                                 schedule_work(task);
589                                 goto out;
590                         }
591                         err = chan->ops->read(chan->fd, &c, chan->data);
592                         if(err > 0)
593                                 tty_receive_char(tty, c);
594                 } while(err > 0);
595
596                 if(err == 0) reactivate_fd(chan->fd, irq);
597                 if(err == -EIO){
598                         if(chan->primary){
599                                 if(tty != NULL)
600                                         tty_hangup(tty);
601                                 line_disable(tty, irq);
602                                 close_chan(chans);
603                                 free_chan(chans);
604                                 return;
605                         }
606                         else {
607                                 if(chan->ops->close != NULL)
608                                         chan->ops->close(chan->fd, chan->data);
609                                 free_one_chan(chan);
610                         }
611                 }
612         }
613  out:
614         if(tty) tty_flip_buffer_push(tty);
615 }
616
617 /*
618  * Overrides for Emacs so that we follow Linus's tabbing style.
619  * Emacs will notice this stuff at the end of the file and automatically
620  * adjust the settings for this buffer only.  This must remain at the end
621  * of the file.
622  * ---------------------------------------------------------------------------
623  * Local variables:
624  * c-file-style: "linux"
625  * End:
626  */