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/tty_flip.h>
13 #include "chan_kern.h"
14 #include "user_util.h"
20 static void *not_configged_init(char *str, int device, struct chan_opts *opts)
22 printk(KERN_ERR "Using a channel type which is configured out of "
27 static int not_configged_open(int input, int output, int primary, void *data,
30 printk(KERN_ERR "Using a channel type which is configured out of "
35 static void not_configged_close(int fd, void *data)
37 printk(KERN_ERR "Using a channel type which is configured out of "
41 static int not_configged_read(int fd, char *c_out, void *data)
43 printk(KERN_ERR "Using a channel type which is configured out of "
48 static int not_configged_write(int fd, const char *buf, int len, void *data)
50 printk(KERN_ERR "Using a channel type which is configured out of "
55 static int not_configged_console_write(int fd, const char *buf, int len,
58 printk(KERN_ERR "Using a channel type which is configured out of "
63 static int not_configged_window_size(int fd, void *data, unsigned short *rows,
66 printk(KERN_ERR "Using a channel type which is configured out of "
71 static void not_configged_free(void *data)
73 printk(KERN_ERR "Using a channel type which is configured out of "
77 static struct chan_ops not_configged_ops = {
78 .init = not_configged_init,
79 .open = not_configged_open,
80 .close = not_configged_close,
81 .read = not_configged_read,
82 .write = not_configged_write,
83 .console_write = not_configged_console_write,
84 .window_size = not_configged_window_size,
85 .free = not_configged_free,
89 static void tty_receive_char(struct tty_struct *tty, char ch)
91 if(tty == NULL) return;
93 if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
94 if(ch == STOP_CHAR(tty)){
98 else if(ch == START_CHAR(tty)){
104 if((tty->flip.flag_buf_ptr == NULL) ||
105 (tty->flip.char_buf_ptr == NULL))
107 tty_insert_flip_char(tty, ch, TTY_NORMAL);
110 static int open_one_chan(struct chan *chan, int input, int output, int primary)
114 if(chan->opened) return(0);
115 if(chan->ops->open == NULL) fd = 0;
116 else fd = (*chan->ops->open)(input, output, primary, chan->data,
118 if(fd < 0) return(fd);
125 int open_chan(struct list_head *chans)
127 struct list_head *ele;
131 list_for_each(ele, chans){
132 chan = list_entry(ele, struct chan, list);
133 ret = open_one_chan(chan, chan->input, chan->output,
135 if(chan->primary) err = ret;
140 void chan_enable_winch(struct list_head *chans, void *line)
142 struct list_head *ele;
145 list_for_each(ele, chans){
146 chan = list_entry(ele, struct chan, list);
147 if(chan->primary && chan->output && chan->ops->winch){
148 register_winch(chan->fd, line);
154 void enable_chan(struct list_head *chans, void *data)
156 struct list_head *ele;
159 list_for_each(ele, chans){
160 chan = list_entry(ele, struct chan, list);
161 if(!chan->opened) continue;
163 line_setup_irq(chan->fd, chan->input, chan->output, data);
167 void close_chan(struct list_head *chans)
169 struct list_head *ele;
172 /* Close in reverse order as open in case more than one of them
173 * refers to the same device and they save and restore that device's
174 * state. Then, the first one opened will have the original state,
175 * so it must be the last closed.
177 for(ele = chans->prev; ele != chans; ele = ele->prev){
178 chan = list_entry(ele, struct chan, list);
179 if(!chan->opened) continue;
180 if(chan->ops->close != NULL)
181 (*chan->ops->close)(chan->fd, chan->data);
187 int write_chan(struct list_head *chans, const char *buf, int len,
190 struct list_head *ele;
194 list_for_each(ele, chans){
195 chan = list_entry(ele, struct chan, list);
196 if(!chan->output || (chan->ops->write == NULL)) continue;
197 n = chan->ops->write(chan->fd, buf, len, chan->data);
200 if((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){
201 reactivate_fd(chan->fd, write_irq);
202 if(ret == -EAGAIN) ret = 0;
209 int console_write_chan(struct list_head *chans, const char *buf, int len)
211 struct list_head *ele;
215 list_for_each(ele, chans){
216 chan = list_entry(ele, struct chan, list);
217 if(!chan->output || (chan->ops->console_write == NULL))
219 n = chan->ops->console_write(chan->fd, buf, len, chan->data);
220 if(chan->primary) ret = n;
225 int chan_window_size(struct list_head *chans, unsigned short *rows_out,
226 unsigned short *cols_out)
228 struct list_head *ele;
231 list_for_each(ele, chans){
232 chan = list_entry(ele, struct chan, list);
234 if(chan->ops->window_size == NULL) return(0);
235 return(chan->ops->window_size(chan->fd, chan->data,
236 rows_out, cols_out));
242 void free_one_chan(struct chan *chan)
244 list_del(&chan->list);
245 if(chan->ops->free != NULL)
246 (*chan->ops->free)(chan->data);
247 free_irq_by_fd(chan->fd);
248 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
252 void free_chan(struct list_head *chans)
254 struct list_head *ele, *next;
257 list_for_each_safe(ele, next, chans){
258 chan = list_entry(ele, struct chan, list);
263 static int one_chan_config_string(struct chan *chan, char *str, int size,
268 CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
270 if(chan->dev == NULL){
271 CONFIG_CHUNK(str, size, n, "", 1);
275 CONFIG_CHUNK(str, size, n, ":", 0);
276 CONFIG_CHUNK(str, size, n, chan->dev, 0);
281 static int chan_pair_config_string(struct chan *in, struct chan *out,
282 char *str, int size, char **error_out)
286 n = one_chan_config_string(in, str, size, error_out);
291 CONFIG_CHUNK(str, size, n, "", 1);
295 CONFIG_CHUNK(str, size, n, ",", 1);
296 n = one_chan_config_string(out, str, size, error_out);
299 CONFIG_CHUNK(str, size, n, "", 1);
304 int chan_config_string(struct list_head *chans, char *str, int size,
307 struct list_head *ele;
308 struct chan *chan, *in = NULL, *out = NULL;
310 list_for_each(ele, chans){
311 chan = list_entry(ele, struct chan, list);
320 return(chan_pair_config_string(in, out, str, size, error_out));
325 struct chan_ops *ops;
328 struct chan_type chan_table[] = {
329 #ifdef CONFIG_FD_CHAN
332 { "fd", ¬_configged_ops },
335 #ifdef CONFIG_NULL_CHAN
336 { "null", &null_ops },
338 { "null", ¬_configged_ops },
341 #ifdef CONFIG_PORT_CHAN
342 { "port", &port_ops },
344 { "port", ¬_configged_ops },
347 #ifdef CONFIG_PTY_CHAN
351 { "pty", ¬_configged_ops },
352 { "pts", ¬_configged_ops },
355 #ifdef CONFIG_TTY_CHAN
358 { "tty", ¬_configged_ops },
361 #ifdef CONFIG_XTERM_CHAN
362 { "xterm", &xterm_ops },
364 { "xterm", ¬_configged_ops },
368 static struct chan *parse_chan(char *str, int pri, int device,
369 struct chan_opts *opts)
371 struct chan_type *entry;
372 struct chan_ops *ops;
379 for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
380 entry = &chan_table[i];
381 if(!strncmp(str, entry->key, strlen(entry->key))){
383 str += strlen(entry->key);
388 printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n",
392 if(ops->init == NULL) return(NULL);
393 data = (*ops->init)(str, device, opts);
394 if(data == NULL) return(NULL);
396 chan = kmalloc(sizeof(*chan), GFP_KERNEL);
397 if(chan == NULL) return(NULL);
398 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
410 int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
411 struct chan_opts *opts)
413 struct chan *new, *chan;
416 if(!list_empty(chans)){
417 chan = list_entry(chans->next, struct chan, list);
418 if(chan->pri >= pri) return(0);
420 INIT_LIST_HEAD(chans);
423 if((out = strchr(str, ',')) != NULL){
427 new = parse_chan(in, pri, device, opts);
428 if(new == NULL) return(-1);
430 list_add(&new->list, chans);
432 new = parse_chan(out, pri, device, opts);
433 if(new == NULL) return(-1);
434 list_add(&new->list, chans);
438 new = parse_chan(str, pri, device, opts);
439 if(new == NULL) return(-1);
440 list_add(&new->list, chans);
447 int chan_out_fd(struct list_head *chans)
449 struct list_head *ele;
452 list_for_each(ele, chans){
453 chan = list_entry(ele, struct chan, list);
454 if(chan->primary && chan->output)
460 void chan_interrupt(struct list_head *chans, struct work_struct *task,
461 struct tty_struct *tty, int irq, void *dev)
463 struct list_head *ele, *next;
468 list_for_each_safe(ele, next, chans){
469 chan = list_entry(ele, struct chan, list);
470 if(!chan->input || (chan->ops->read == NULL)) continue;
473 (tty->flip.count >= TTY_FLIPBUF_SIZE)){
477 err = chan->ops->read(chan->fd, &c, chan->data);
478 if(err > 0) tty_receive_char(tty, c);
480 if(err == 0) reactivate_fd(chan->fd, irq);
483 if(tty != NULL) tty_hangup(tty);
484 line_disable(dev, irq);
490 if(chan->ops->close != NULL)
491 chan->ops->close(chan->fd, chan->data);
497 if(tty) tty_flip_buffer_push(tty);
501 * Overrides for Emacs so that we follow Linus's tabbing style.
502 * Emacs will notice this stuff at the end of the file and automatically
503 * adjust the settings for this buffer only. This must remain at the end
505 * ---------------------------------------------------------------------------
507 * c-file-style: "linux"