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