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