llc2: Remove dead code for state machine
[linux/fpc-iii.git] / arch / um / drivers / chan_kern.c
blob87eebfe03c61aa7de2524ede5d3aac3128aaccb5
1 /*
2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
3 * Licensed under the GPL
4 */
6 #include <linux/slab.h>
7 #include <linux/tty.h>
8 #include <linux/tty_flip.h>
9 #include "chan.h"
10 #include "os.h"
11 #include "irq_kern.h"
13 #ifdef CONFIG_NOCONFIG_CHAN
14 static void *not_configged_init(char *str, int device,
15 const struct chan_opts *opts)
17 printk(KERN_ERR "Using a channel type which is configured out of "
18 "UML\n");
19 return NULL;
22 static int not_configged_open(int input, int output, int primary, void *data,
23 char **dev_out)
25 printk(KERN_ERR "Using a channel type which is configured out of "
26 "UML\n");
27 return -ENODEV;
30 static void not_configged_close(int fd, void *data)
32 printk(KERN_ERR "Using a channel type which is configured out of "
33 "UML\n");
36 static int not_configged_read(int fd, char *c_out, void *data)
38 printk(KERN_ERR "Using a channel type which is configured out of "
39 "UML\n");
40 return -EIO;
43 static int not_configged_write(int fd, const char *buf, int len, void *data)
45 printk(KERN_ERR "Using a channel type which is configured out of "
46 "UML\n");
47 return -EIO;
50 static int not_configged_console_write(int fd, const char *buf, int len)
52 printk(KERN_ERR "Using a channel type which is configured out of "
53 "UML\n");
54 return -EIO;
57 static int not_configged_window_size(int fd, void *data, unsigned short *rows,
58 unsigned short *cols)
60 printk(KERN_ERR "Using a channel type which is configured out of "
61 "UML\n");
62 return -ENODEV;
65 static void not_configged_free(void *data)
67 printk(KERN_ERR "Using a channel type which is configured out of "
68 "UML\n");
71 static const struct chan_ops not_configged_ops = {
72 .init = not_configged_init,
73 .open = not_configged_open,
74 .close = not_configged_close,
75 .read = not_configged_read,
76 .write = not_configged_write,
77 .console_write = not_configged_console_write,
78 .window_size = not_configged_window_size,
79 .free = not_configged_free,
80 .winch = 0,
82 #endif /* CONFIG_NOCONFIG_CHAN */
84 static void tty_receive_char(struct tty_struct *tty, char ch)
86 if (tty == NULL)
87 return;
89 if (I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
90 if (ch == STOP_CHAR(tty)) {
91 stop_tty(tty);
92 return;
94 else if (ch == START_CHAR(tty)) {
95 start_tty(tty);
96 return;
100 tty_insert_flip_char(tty, ch, TTY_NORMAL);
103 static int open_one_chan(struct chan *chan)
105 int fd, err;
107 if (chan->opened)
108 return 0;
110 if (chan->ops->open == NULL)
111 fd = 0;
112 else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
113 chan->data, &chan->dev);
114 if (fd < 0)
115 return fd;
117 err = os_set_fd_block(fd, 0);
118 if (err) {
119 (*chan->ops->close)(fd, chan->data);
120 return err;
123 chan->fd = fd;
125 chan->opened = 1;
126 return 0;
129 static int open_chan(struct list_head *chans)
131 struct list_head *ele;
132 struct chan *chan;
133 int ret, err = 0;
135 list_for_each(ele, chans) {
136 chan = list_entry(ele, struct chan, list);
137 ret = open_one_chan(chan);
138 if (chan->primary)
139 err = ret;
141 return err;
144 void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
146 if (chan && chan->primary && chan->ops->winch)
147 register_winch(chan->fd, tty);
150 static void line_timer_cb(struct work_struct *work)
152 struct line *line = container_of(work, struct line, task.work);
153 struct tty_struct *tty = tty_port_tty_get(&line->port);
155 if (!line->throttled)
156 chan_interrupt(line, tty, line->driver->read_irq);
157 tty_kref_put(tty);
160 int enable_chan(struct line *line)
162 struct list_head *ele;
163 struct chan *chan;
164 int err;
166 INIT_DELAYED_WORK(&line->task, line_timer_cb);
168 list_for_each(ele, &line->chan_list) {
169 chan = list_entry(ele, struct chan, list);
170 err = open_one_chan(chan);
171 if (err) {
172 if (chan->primary)
173 goto out_close;
175 continue;
178 if (chan->enabled)
179 continue;
180 err = line_setup_irq(chan->fd, chan->input, chan->output, line,
181 chan);
182 if (err)
183 goto out_close;
185 chan->enabled = 1;
188 return 0;
190 out_close:
191 close_chan(line);
192 return err;
195 /* Items are added in IRQ context, when free_irq can't be called, and
196 * removed in process context, when it can.
197 * This handles interrupt sources which disappear, and which need to
198 * be permanently disabled. This is discovered in IRQ context, but
199 * the freeing of the IRQ must be done later.
201 static DEFINE_SPINLOCK(irqs_to_free_lock);
202 static LIST_HEAD(irqs_to_free);
204 void free_irqs(void)
206 struct chan *chan;
207 LIST_HEAD(list);
208 struct list_head *ele;
209 unsigned long flags;
211 spin_lock_irqsave(&irqs_to_free_lock, flags);
212 list_splice_init(&irqs_to_free, &list);
213 spin_unlock_irqrestore(&irqs_to_free_lock, flags);
215 list_for_each(ele, &list) {
216 chan = list_entry(ele, struct chan, free_list);
218 if (chan->input && chan->enabled)
219 um_free_irq(chan->line->driver->read_irq, chan);
220 if (chan->output && chan->enabled)
221 um_free_irq(chan->line->driver->write_irq, chan);
222 chan->enabled = 0;
226 static void close_one_chan(struct chan *chan, int delay_free_irq)
228 unsigned long flags;
230 if (!chan->opened)
231 return;
233 if (delay_free_irq) {
234 spin_lock_irqsave(&irqs_to_free_lock, flags);
235 list_add(&chan->free_list, &irqs_to_free);
236 spin_unlock_irqrestore(&irqs_to_free_lock, flags);
238 else {
239 if (chan->input && chan->enabled)
240 um_free_irq(chan->line->driver->read_irq, chan);
241 if (chan->output && chan->enabled)
242 um_free_irq(chan->line->driver->write_irq, chan);
243 chan->enabled = 0;
245 if (chan->ops->close != NULL)
246 (*chan->ops->close)(chan->fd, chan->data);
248 chan->opened = 0;
249 chan->fd = -1;
252 void close_chan(struct line *line)
254 struct chan *chan;
256 /* Close in reverse order as open in case more than one of them
257 * refers to the same device and they save and restore that device's
258 * state. Then, the first one opened will have the original state,
259 * so it must be the last closed.
261 list_for_each_entry_reverse(chan, &line->chan_list, list) {
262 close_one_chan(chan, 0);
266 void deactivate_chan(struct chan *chan, int irq)
268 if (chan && chan->enabled)
269 deactivate_fd(chan->fd, irq);
272 void reactivate_chan(struct chan *chan, int irq)
274 if (chan && chan->enabled)
275 reactivate_fd(chan->fd, irq);
278 int write_chan(struct chan *chan, const char *buf, int len,
279 int write_irq)
281 int n, ret = 0;
283 if (len == 0 || !chan || !chan->ops->write)
284 return 0;
286 n = chan->ops->write(chan->fd, buf, len, chan->data);
287 if (chan->primary) {
288 ret = n;
289 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
290 reactivate_fd(chan->fd, write_irq);
292 return ret;
295 int console_write_chan(struct chan *chan, const char *buf, int len)
297 int n, ret = 0;
299 if (!chan || !chan->ops->console_write)
300 return 0;
302 n = chan->ops->console_write(chan->fd, buf, len);
303 if (chan->primary)
304 ret = n;
305 return ret;
308 int console_open_chan(struct line *line, struct console *co)
310 int err;
312 err = open_chan(&line->chan_list);
313 if (err)
314 return err;
316 printk(KERN_INFO "Console initialized on /dev/%s%d\n", co->name,
317 co->index);
318 return 0;
321 int chan_window_size(struct line *line, unsigned short *rows_out,
322 unsigned short *cols_out)
324 struct chan *chan;
326 chan = line->chan_in;
327 if (chan && chan->primary) {
328 if (chan->ops->window_size == NULL)
329 return 0;
330 return chan->ops->window_size(chan->fd, chan->data,
331 rows_out, cols_out);
333 chan = line->chan_out;
334 if (chan && 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);
340 return 0;
343 static void free_one_chan(struct chan *chan)
345 list_del(&chan->list);
347 close_one_chan(chan, 0);
349 if (chan->ops->free != NULL)
350 (*chan->ops->free)(chan->data);
352 if (chan->primary && chan->output)
353 ignore_sigio_fd(chan->fd);
354 kfree(chan);
357 static void free_chan(struct list_head *chans)
359 struct list_head *ele, *next;
360 struct chan *chan;
362 list_for_each_safe(ele, next, chans) {
363 chan = list_entry(ele, struct chan, list);
364 free_one_chan(chan);
368 static int one_chan_config_string(struct chan *chan, char *str, int size,
369 char **error_out)
371 int n = 0;
373 if (chan == NULL) {
374 CONFIG_CHUNK(str, size, n, "none", 1);
375 return n;
378 CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
380 if (chan->dev == NULL) {
381 CONFIG_CHUNK(str, size, n, "", 1);
382 return n;
385 CONFIG_CHUNK(str, size, n, ":", 0);
386 CONFIG_CHUNK(str, size, n, chan->dev, 0);
388 return n;
391 static int chan_pair_config_string(struct chan *in, struct chan *out,
392 char *str, int size, char **error_out)
394 int n;
396 n = one_chan_config_string(in, str, size, error_out);
397 str += n;
398 size -= n;
400 if (in == out) {
401 CONFIG_CHUNK(str, size, n, "", 1);
402 return n;
405 CONFIG_CHUNK(str, size, n, ",", 1);
406 n = one_chan_config_string(out, str, size, error_out);
407 str += n;
408 size -= n;
409 CONFIG_CHUNK(str, size, n, "", 1);
411 return n;
414 int chan_config_string(struct line *line, char *str, int size,
415 char **error_out)
417 struct chan *in = line->chan_in, *out = line->chan_out;
419 if (in && !in->primary)
420 in = NULL;
421 if (out && !out->primary)
422 out = NULL;
424 return chan_pair_config_string(in, out, str, size, error_out);
427 struct chan_type {
428 char *key;
429 const struct chan_ops *ops;
432 static const struct chan_type chan_table[] = {
433 { "fd", &fd_ops },
435 #ifdef CONFIG_NULL_CHAN
436 { "null", &null_ops },
437 #else
438 { "null", &not_configged_ops },
439 #endif
441 #ifdef CONFIG_PORT_CHAN
442 { "port", &port_ops },
443 #else
444 { "port", &not_configged_ops },
445 #endif
447 #ifdef CONFIG_PTY_CHAN
448 { "pty", &pty_ops },
449 { "pts", &pts_ops },
450 #else
451 { "pty", &not_configged_ops },
452 { "pts", &not_configged_ops },
453 #endif
455 #ifdef CONFIG_TTY_CHAN
456 { "tty", &tty_ops },
457 #else
458 { "tty", &not_configged_ops },
459 #endif
461 #ifdef CONFIG_XTERM_CHAN
462 { "xterm", &xterm_ops },
463 #else
464 { "xterm", &not_configged_ops },
465 #endif
468 static struct chan *parse_chan(struct line *line, char *str, int device,
469 const struct chan_opts *opts, char **error_out)
471 const struct chan_type *entry;
472 const struct chan_ops *ops;
473 struct chan *chan;
474 void *data;
475 int i;
477 ops = NULL;
478 data = NULL;
479 for(i = 0; i < ARRAY_SIZE(chan_table); i++) {
480 entry = &chan_table[i];
481 if (!strncmp(str, entry->key, strlen(entry->key))) {
482 ops = entry->ops;
483 str += strlen(entry->key);
484 break;
487 if (ops == NULL) {
488 *error_out = "No match for configured backends";
489 return NULL;
492 data = (*ops->init)(str, device, opts);
493 if (data == NULL) {
494 *error_out = "Configuration failed";
495 return NULL;
498 chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
499 if (chan == NULL) {
500 *error_out = "Memory allocation failed";
501 return NULL;
503 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
504 .free_list =
505 LIST_HEAD_INIT(chan->free_list),
506 .line = line,
507 .primary = 1,
508 .input = 0,
509 .output = 0,
510 .opened = 0,
511 .enabled = 0,
512 .fd = -1,
513 .ops = ops,
514 .data = data });
515 return chan;
518 int parse_chan_pair(char *str, struct line *line, int device,
519 const struct chan_opts *opts, char **error_out)
521 struct list_head *chans = &line->chan_list;
522 struct chan *new;
523 char *in, *out;
525 if (!list_empty(chans)) {
526 line->chan_in = line->chan_out = NULL;
527 free_chan(chans);
528 INIT_LIST_HEAD(chans);
531 if (!str)
532 return 0;
534 out = strchr(str, ',');
535 if (out != NULL) {
536 in = str;
537 *out = '\0';
538 out++;
539 new = parse_chan(line, in, device, opts, error_out);
540 if (new == NULL)
541 return -1;
543 new->input = 1;
544 list_add(&new->list, chans);
545 line->chan_in = new;
547 new = parse_chan(line, out, device, opts, error_out);
548 if (new == NULL)
549 return -1;
551 list_add(&new->list, chans);
552 new->output = 1;
553 line->chan_out = new;
555 else {
556 new = parse_chan(line, str, device, opts, error_out);
557 if (new == NULL)
558 return -1;
560 list_add(&new->list, chans);
561 new->input = 1;
562 new->output = 1;
563 line->chan_in = line->chan_out = new;
565 return 0;
568 void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
570 struct chan *chan = line->chan_in;
571 int err;
572 char c;
574 if (!chan || !chan->ops->read)
575 goto out;
577 do {
578 if (tty && !tty_buffer_request_room(tty, 1)) {
579 schedule_delayed_work(&line->task, 1);
580 goto out;
582 err = chan->ops->read(chan->fd, &c, chan->data);
583 if (err > 0)
584 tty_receive_char(tty, c);
585 } while (err > 0);
587 if (err == 0)
588 reactivate_fd(chan->fd, irq);
589 if (err == -EIO) {
590 if (chan->primary) {
591 if (tty != NULL)
592 tty_hangup(tty);
593 if (line->chan_out != chan)
594 close_one_chan(line->chan_out, 1);
596 close_one_chan(chan, 1);
597 if (chan->primary)
598 return;
600 out:
601 if (tty)
602 tty_flip_buffer_push(tty);