2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
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>
14 #include "chan_kern.h"
21 #ifdef CONFIG_NOCONFIG_CHAN
22 static void *not_configged_init(char *str, int device,
23 const struct chan_opts *opts)
25 printk("Using a channel type which is configured out of "
30 static int not_configged_open(int input, int output, int primary, void *data,
33 printk("Using a channel type which is configured out of "
38 static void not_configged_close(int fd, void *data)
40 printk("Using a channel type which is configured out of "
44 static int not_configged_read(int fd, char *c_out, void *data)
46 printk("Using a channel type which is configured out of "
51 static int not_configged_write(int fd, const char *buf, int len, void *data)
53 printk("Using a channel type which is configured out of "
58 static int not_configged_console_write(int fd, const char *buf, int len)
60 printk("Using a channel type which is configured out of "
65 static int not_configged_window_size(int fd, void *data, unsigned short *rows,
68 printk("Using a channel type which is configured out of "
73 static void not_configged_free(void *data)
75 printk("Using a channel type which is configured out of "
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,
90 #endif /* CONFIG_NOCONFIG_CHAN */
92 static void tty_receive_char(struct tty_struct *tty, char ch)
94 if(tty == NULL) return;
96 if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
97 if(ch == STOP_CHAR(tty)){
101 else if(ch == START_CHAR(tty)){
107 tty_insert_flip_char(tty, ch, TTY_NORMAL);
110 static int open_one_chan(struct chan *chan)
117 if(chan->ops->open == NULL)
119 else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
120 chan->data, &chan->dev);
124 err = os_set_fd_block(fd, 0);
126 (*chan->ops->close)(fd, chan->data);
136 int open_chan(struct list_head *chans)
138 struct list_head *ele;
142 list_for_each(ele, chans){
143 chan = list_entry(ele, struct chan, list);
144 ret = open_one_chan(chan);
151 void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
153 struct list_head *ele;
156 list_for_each(ele, chans){
157 chan = list_entry(ele, struct chan, list);
158 if(chan->primary && chan->output && chan->ops->winch){
159 register_winch(chan->fd, tty);
165 int enable_chan(struct line *line)
167 struct list_head *ele;
171 list_for_each(ele, &line->chan_list){
172 chan = list_entry(ele, struct chan, list);
173 err = open_one_chan(chan);
183 err = line_setup_irq(chan->fd, chan->input, chan->output, line,
194 close_chan(&line->chan_list, 0);
198 /* Items are added in IRQ context, when free_irq can't be called, and
199 * removed in process context, when it can.
200 * This handles interrupt sources which disappear, and which need to
201 * be permanently disabled. This is discovered in IRQ context, but
202 * the freeing of the IRQ must be done later.
204 static DEFINE_SPINLOCK(irqs_to_free_lock);
205 static LIST_HEAD(irqs_to_free);
211 struct list_head *ele;
214 spin_lock_irqsave(&irqs_to_free_lock, flags);
215 list_splice_init(&irqs_to_free, &list);
216 spin_unlock_irqrestore(&irqs_to_free_lock, flags);
218 list_for_each(ele, &list){
219 chan = list_entry(ele, struct chan, free_list);
222 free_irq(chan->line->driver->read_irq, chan);
224 free_irq(chan->line->driver->write_irq, chan);
229 static void close_one_chan(struct chan *chan, int delay_free_irq)
237 spin_lock_irqsave(&irqs_to_free_lock, flags);
238 list_add(&chan->free_list, &irqs_to_free);
239 spin_unlock_irqrestore(&irqs_to_free_lock, flags);
243 free_irq(chan->line->driver->read_irq, chan);
245 free_irq(chan->line->driver->write_irq, chan);
248 if(chan->ops->close != NULL)
249 (*chan->ops->close)(chan->fd, chan->data);
255 void close_chan(struct list_head *chans, int delay_free_irq)
259 /* Close in reverse order as open in case more than one of them
260 * refers to the same device and they save and restore that device's
261 * state. Then, the first one opened will have the original state,
262 * so it must be the last closed.
264 list_for_each_entry_reverse(chan, chans, list) {
265 close_one_chan(chan, delay_free_irq);
269 void deactivate_chan(struct list_head *chans, int irq)
271 struct list_head *ele;
274 list_for_each(ele, chans) {
275 chan = list_entry(ele, struct chan, list);
277 if(chan->enabled && chan->input)
278 deactivate_fd(chan->fd, irq);
282 void reactivate_chan(struct list_head *chans, int irq)
284 struct list_head *ele;
287 list_for_each(ele, chans) {
288 chan = list_entry(ele, struct chan, list);
290 if(chan->enabled && chan->input)
291 reactivate_fd(chan->fd, irq);
295 int write_chan(struct list_head *chans, const char *buf, int len,
298 struct list_head *ele;
299 struct chan *chan = NULL;
302 list_for_each(ele, chans) {
303 chan = list_entry(ele, struct chan, list);
304 if (!chan->output || (chan->ops->write == NULL))
306 n = chan->ops->write(chan->fd, buf, len, chan->data);
309 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
310 reactivate_fd(chan->fd, write_irq);
316 int console_write_chan(struct list_head *chans, const char *buf, int len)
318 struct list_head *ele;
322 list_for_each(ele, chans){
323 chan = list_entry(ele, struct chan, list);
324 if(!chan->output || (chan->ops->console_write == NULL))
326 n = chan->ops->console_write(chan->fd, buf, len);
327 if(chan->primary) ret = n;
332 int console_open_chan(struct line *line, struct console *co)
336 err = open_chan(&line->chan_list);
340 printk("Console initialized on /dev/%s%d\n", co->name, co->index);
344 int chan_window_size(struct list_head *chans, unsigned short *rows_out,
345 unsigned short *cols_out)
347 struct list_head *ele;
350 list_for_each(ele, chans){
351 chan = list_entry(ele, struct chan, list);
353 if(chan->ops->window_size == NULL)
355 return chan->ops->window_size(chan->fd, chan->data,
362 static void free_one_chan(struct chan *chan, int delay_free_irq)
364 list_del(&chan->list);
366 close_one_chan(chan, delay_free_irq);
368 if(chan->ops->free != NULL)
369 (*chan->ops->free)(chan->data);
371 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
375 static void free_chan(struct list_head *chans, int delay_free_irq)
377 struct list_head *ele, *next;
380 list_for_each_safe(ele, next, chans){
381 chan = list_entry(ele, struct chan, list);
382 free_one_chan(chan, delay_free_irq);
386 static int one_chan_config_string(struct chan *chan, char *str, int size,
392 CONFIG_CHUNK(str, size, n, "none", 1);
396 CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
398 if(chan->dev == NULL){
399 CONFIG_CHUNK(str, size, n, "", 1);
403 CONFIG_CHUNK(str, size, n, ":", 0);
404 CONFIG_CHUNK(str, size, n, chan->dev, 0);
409 static int chan_pair_config_string(struct chan *in, struct chan *out,
410 char *str, int size, char **error_out)
414 n = one_chan_config_string(in, str, size, error_out);
419 CONFIG_CHUNK(str, size, n, "", 1);
423 CONFIG_CHUNK(str, size, n, ",", 1);
424 n = one_chan_config_string(out, str, size, error_out);
427 CONFIG_CHUNK(str, size, n, "", 1);
432 int chan_config_string(struct list_head *chans, char *str, int size,
435 struct list_head *ele;
436 struct chan *chan, *in = NULL, *out = NULL;
438 list_for_each(ele, chans){
439 chan = list_entry(ele, struct chan, list);
448 return chan_pair_config_string(in, out, str, size, error_out);
453 const struct chan_ops *ops;
456 static const struct chan_type chan_table[] = {
459 #ifdef CONFIG_NULL_CHAN
460 { "null", &null_ops },
462 { "null", ¬_configged_ops },
465 #ifdef CONFIG_PORT_CHAN
466 { "port", &port_ops },
468 { "port", ¬_configged_ops },
471 #ifdef CONFIG_PTY_CHAN
475 { "pty", ¬_configged_ops },
476 { "pts", ¬_configged_ops },
479 #ifdef CONFIG_TTY_CHAN
482 { "tty", ¬_configged_ops },
485 #ifdef CONFIG_XTERM_CHAN
486 { "xterm", &xterm_ops },
488 { "xterm", ¬_configged_ops },
492 static struct chan *parse_chan(struct line *line, char *str, int device,
493 const struct chan_opts *opts, char **error_out)
495 const struct chan_type *entry;
496 const struct chan_ops *ops;
503 for(i = 0; i < ARRAY_SIZE(chan_table); i++){
504 entry = &chan_table[i];
505 if(!strncmp(str, entry->key, strlen(entry->key))){
507 str += strlen(entry->key);
512 *error_out = "No match for configured backends";
516 data = (*ops->init)(str, device, opts);
518 *error_out = "Configuration failed";
522 chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
524 *error_out = "Memory allocation failed";
527 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
529 LIST_HEAD_INIT(chan->free_list),
542 int parse_chan_pair(char *str, struct line *line, int device,
543 const struct chan_opts *opts, char **error_out)
545 struct list_head *chans = &line->chan_list;
546 struct chan *new, *chan;
549 if(!list_empty(chans)){
550 chan = list_entry(chans->next, struct chan, list);
552 INIT_LIST_HEAD(chans);
555 out = strchr(str, ',');
560 new = parse_chan(line, in, device, opts, error_out);
565 list_add(&new->list, chans);
567 new = parse_chan(line, out, device, opts, error_out);
571 list_add(&new->list, chans);
575 new = parse_chan(line, str, device, opts, error_out);
579 list_add(&new->list, chans);
586 int chan_out_fd(struct list_head *chans)
588 struct list_head *ele;
591 list_for_each(ele, chans){
592 chan = list_entry(ele, struct chan, list);
593 if(chan->primary && chan->output)
599 void chan_interrupt(struct list_head *chans, struct delayed_work *task,
600 struct tty_struct *tty, int irq)
602 struct list_head *ele, *next;
607 list_for_each_safe(ele, next, chans){
608 chan = list_entry(ele, struct chan, list);
609 if(!chan->input || (chan->ops->read == NULL)) continue;
611 if (tty && !tty_buffer_request_room(tty, 1)) {
612 schedule_delayed_work(task, 1);
615 err = chan->ops->read(chan->fd, &c, chan->data);
617 tty_receive_char(tty, c);
620 if(err == 0) reactivate_fd(chan->fd, irq);
625 close_chan(chans, 1);
628 else close_one_chan(chan, 1);
632 if(tty) tty_flip_buffer_push(tty);