xref: /openbmc/linux/arch/um/drivers/chan_kern.c (revision c21b37f6)
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;
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 	chan->fd = fd;
172 
173 	chan->opened = 1;
174 	return 0;
175 }
176 
177 int open_chan(struct list_head *chans)
178 {
179 	struct list_head *ele;
180 	struct chan *chan;
181 	int ret, err = 0;
182 
183 	list_for_each(ele, chans){
184 		chan = list_entry(ele, struct chan, list);
185 		ret = open_one_chan(chan);
186 		if(chan->primary)
187 			err = ret;
188 	}
189 	return err;
190 }
191 
192 void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
193 {
194 	struct list_head *ele;
195 	struct chan *chan;
196 
197 	list_for_each(ele, chans){
198 		chan = list_entry(ele, struct chan, list);
199 		if(chan->primary && chan->output && chan->ops->winch){
200 			register_winch(chan->fd, tty);
201 			return;
202 		}
203 	}
204 }
205 
206 int enable_chan(struct line *line)
207 {
208 	struct list_head *ele;
209 	struct chan *chan;
210 	int err;
211 
212 	list_for_each(ele, &line->chan_list){
213 		chan = list_entry(ele, struct chan, list);
214 		err = open_one_chan(chan);
215 		if (err) {
216 			if (chan->primary)
217 				goto out_close;
218 
219 			continue;
220 		}
221 
222 		if(chan->enabled)
223 			continue;
224 		err = line_setup_irq(chan->fd, chan->input, chan->output, line,
225 				     chan);
226 		if (err)
227 			goto out_close;
228 
229 		chan->enabled = 1;
230 	}
231 
232 	return 0;
233 
234  out_close:
235 	close_chan(&line->chan_list, 0);
236 	return err;
237 }
238 
239 /* Items are added in IRQ context, when free_irq can't be called, and
240  * removed in process context, when it can.
241  * This handles interrupt sources which disappear, and which need to
242  * be permanently disabled.  This is discovered in IRQ context, but
243  * the freeing of the IRQ must be done later.
244  */
245 static DEFINE_SPINLOCK(irqs_to_free_lock);
246 static LIST_HEAD(irqs_to_free);
247 
248 void free_irqs(void)
249 {
250 	struct chan *chan;
251 	LIST_HEAD(list);
252 	struct list_head *ele;
253 	unsigned long flags;
254 
255 	spin_lock_irqsave(&irqs_to_free_lock, flags);
256 	list_splice_init(&irqs_to_free, &list);
257 	spin_unlock_irqrestore(&irqs_to_free_lock, flags);
258 
259 	list_for_each(ele, &list){
260 		chan = list_entry(ele, struct chan, free_list);
261 
262 		if(chan->input)
263 			free_irq(chan->line->driver->read_irq, chan);
264 		if(chan->output)
265 			free_irq(chan->line->driver->write_irq, chan);
266 		chan->enabled = 0;
267 	}
268 }
269 
270 static void close_one_chan(struct chan *chan, int delay_free_irq)
271 {
272 	unsigned long flags;
273 
274 	if(!chan->opened)
275 		return;
276 
277 	if(delay_free_irq){
278 		spin_lock_irqsave(&irqs_to_free_lock, flags);
279 		list_add(&chan->free_list, &irqs_to_free);
280 		spin_unlock_irqrestore(&irqs_to_free_lock, flags);
281 	}
282 	else {
283 		if(chan->input)
284 			free_irq(chan->line->driver->read_irq, chan);
285 		if(chan->output)
286 			free_irq(chan->line->driver->write_irq, chan);
287 		chan->enabled = 0;
288 	}
289 	if(chan->ops->close != NULL)
290 		(*chan->ops->close)(chan->fd, chan->data);
291 
292 	chan->opened = 0;
293 	chan->fd = -1;
294 }
295 
296 void close_chan(struct list_head *chans, int delay_free_irq)
297 {
298 	struct chan *chan;
299 
300 	/* Close in reverse order as open in case more than one of them
301 	 * refers to the same device and they save and restore that device's
302 	 * state.  Then, the first one opened will have the original state,
303 	 * so it must be the last closed.
304 	 */
305 	list_for_each_entry_reverse(chan, chans, list) {
306 		close_one_chan(chan, delay_free_irq);
307 	}
308 }
309 
310 void deactivate_chan(struct list_head *chans, int irq)
311 {
312 	struct list_head *ele;
313 
314 	struct chan *chan;
315 	list_for_each(ele, chans) {
316 		chan = list_entry(ele, struct chan, list);
317 
318 		if(chan->enabled && chan->input)
319 			deactivate_fd(chan->fd, irq);
320 	}
321 }
322 
323 void reactivate_chan(struct list_head *chans, int irq)
324 {
325 	struct list_head *ele;
326 	struct chan *chan;
327 
328 	list_for_each(ele, chans) {
329 		chan = list_entry(ele, struct chan, list);
330 
331 		if(chan->enabled && chan->input)
332 			reactivate_fd(chan->fd, irq);
333 	}
334 }
335 
336 int write_chan(struct list_head *chans, const char *buf, int len,
337 	       int write_irq)
338 {
339 	struct list_head *ele;
340 	struct chan *chan = NULL;
341 	int n, ret = 0;
342 
343 	list_for_each(ele, chans) {
344 		chan = list_entry(ele, struct chan, list);
345 		if (!chan->output || (chan->ops->write == NULL))
346 			continue;
347 		n = chan->ops->write(chan->fd, buf, len, chan->data);
348 		if (chan->primary) {
349 			ret = n;
350 			if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
351 				reactivate_fd(chan->fd, write_irq);
352 		}
353 	}
354 	return ret;
355 }
356 
357 int console_write_chan(struct list_head *chans, const char *buf, int len)
358 {
359 	struct list_head *ele;
360 	struct chan *chan;
361 	int n, ret = 0;
362 
363 	list_for_each(ele, chans){
364 		chan = list_entry(ele, struct chan, list);
365 		if(!chan->output || (chan->ops->console_write == NULL))
366 			continue;
367 		n = chan->ops->console_write(chan->fd, buf, len);
368 		if(chan->primary) ret = n;
369 	}
370 	return ret;
371 }
372 
373 int console_open_chan(struct line *line, struct console *co)
374 {
375 	int err;
376 
377 	err = open_chan(&line->chan_list);
378 	if(err)
379 		return err;
380 
381 	printk("Console initialized on /dev/%s%d\n", co->name, co->index);
382 	return 0;
383 }
384 
385 int chan_window_size(struct list_head *chans, unsigned short *rows_out,
386 		      unsigned short *cols_out)
387 {
388 	struct list_head *ele;
389 	struct chan *chan;
390 
391 	list_for_each(ele, chans){
392 		chan = list_entry(ele, struct chan, list);
393 		if(chan->primary){
394 			if(chan->ops->window_size == NULL)
395 				return 0;
396 			return chan->ops->window_size(chan->fd, chan->data,
397 						      rows_out, cols_out);
398 		}
399 	}
400 	return 0;
401 }
402 
403 static void free_one_chan(struct chan *chan, int delay_free_irq)
404 {
405 	list_del(&chan->list);
406 
407 	close_one_chan(chan, delay_free_irq);
408 
409 	if(chan->ops->free != NULL)
410 		(*chan->ops->free)(chan->data);
411 
412 	if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
413 	kfree(chan);
414 }
415 
416 static void free_chan(struct list_head *chans, int delay_free_irq)
417 {
418 	struct list_head *ele, *next;
419 	struct chan *chan;
420 
421 	list_for_each_safe(ele, next, chans){
422 		chan = list_entry(ele, struct chan, list);
423 		free_one_chan(chan, delay_free_irq);
424 	}
425 }
426 
427 static int one_chan_config_string(struct chan *chan, char *str, int size,
428 				  char **error_out)
429 {
430 	int n = 0;
431 
432 	if(chan == NULL){
433 		CONFIG_CHUNK(str, size, n, "none", 1);
434 		return n;
435 	}
436 
437 	CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
438 
439 	if(chan->dev == NULL){
440 		CONFIG_CHUNK(str, size, n, "", 1);
441 		return n;
442 	}
443 
444 	CONFIG_CHUNK(str, size, n, ":", 0);
445 	CONFIG_CHUNK(str, size, n, chan->dev, 0);
446 
447 	return n;
448 }
449 
450 static int chan_pair_config_string(struct chan *in, struct chan *out,
451 				   char *str, int size, char **error_out)
452 {
453 	int n;
454 
455 	n = one_chan_config_string(in, str, size, error_out);
456 	str += n;
457 	size -= n;
458 
459 	if(in == out){
460 		CONFIG_CHUNK(str, size, n, "", 1);
461 		return n;
462 	}
463 
464 	CONFIG_CHUNK(str, size, n, ",", 1);
465 	n = one_chan_config_string(out, str, size, error_out);
466 	str += n;
467 	size -= n;
468 	CONFIG_CHUNK(str, size, n, "", 1);
469 
470 	return n;
471 }
472 
473 int chan_config_string(struct list_head *chans, char *str, int size,
474 		       char **error_out)
475 {
476 	struct list_head *ele;
477 	struct chan *chan, *in = NULL, *out = NULL;
478 
479 	list_for_each(ele, chans){
480 		chan = list_entry(ele, struct chan, list);
481 		if(!chan->primary)
482 			continue;
483 		if(chan->input)
484 			in = chan;
485 		if(chan->output)
486 			out = chan;
487 	}
488 
489 	return chan_pair_config_string(in, out, str, size, error_out);
490 }
491 
492 struct chan_type {
493 	char *key;
494 	const struct chan_ops *ops;
495 };
496 
497 static const struct chan_type chan_table[] = {
498 	{ "fd", &fd_ops },
499 
500 #ifdef CONFIG_NULL_CHAN
501 	{ "null", &null_ops },
502 #else
503 	{ "null", &not_configged_ops },
504 #endif
505 
506 #ifdef CONFIG_PORT_CHAN
507 	{ "port", &port_ops },
508 #else
509 	{ "port", &not_configged_ops },
510 #endif
511 
512 #ifdef CONFIG_PTY_CHAN
513 	{ "pty", &pty_ops },
514 	{ "pts", &pts_ops },
515 #else
516 	{ "pty", &not_configged_ops },
517 	{ "pts", &not_configged_ops },
518 #endif
519 
520 #ifdef CONFIG_TTY_CHAN
521 	{ "tty", &tty_ops },
522 #else
523 	{ "tty", &not_configged_ops },
524 #endif
525 
526 #ifdef CONFIG_XTERM_CHAN
527 	{ "xterm", &xterm_ops },
528 #else
529 	{ "xterm", &not_configged_ops },
530 #endif
531 };
532 
533 static struct chan *parse_chan(struct line *line, char *str, int device,
534 			       const struct chan_opts *opts, char **error_out)
535 {
536 	const struct chan_type *entry;
537 	const struct chan_ops *ops;
538 	struct chan *chan;
539 	void *data;
540 	int i;
541 
542 	ops = NULL;
543 	data = NULL;
544 	for(i = 0; i < ARRAY_SIZE(chan_table); i++){
545 		entry = &chan_table[i];
546 		if(!strncmp(str, entry->key, strlen(entry->key))){
547 			ops = entry->ops;
548 			str += strlen(entry->key);
549 			break;
550 		}
551 	}
552 	if(ops == NULL){
553 		*error_out = "No match for configured backends";
554 		return NULL;
555 	}
556 
557 	data = (*ops->init)(str, device, opts);
558 	if(data == NULL){
559 		*error_out = "Configuration failed";
560 		return NULL;
561 	}
562 
563 	chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
564 	if(chan == NULL){
565 		*error_out = "Memory allocation failed";
566 		return NULL;
567 	}
568 	*chan = ((struct chan) { .list	 	= LIST_HEAD_INIT(chan->list),
569 				 .free_list 	=
570 				 	LIST_HEAD_INIT(chan->free_list),
571 				 .line		= line,
572 				 .primary	= 1,
573 				 .input		= 0,
574 				 .output 	= 0,
575 				 .opened  	= 0,
576 				 .enabled  	= 0,
577 				 .fd 		= -1,
578 				 .ops 		= ops,
579 				 .data 		= data });
580 	return chan;
581 }
582 
583 int parse_chan_pair(char *str, struct line *line, int device,
584 		    const struct chan_opts *opts, char **error_out)
585 {
586 	struct list_head *chans = &line->chan_list;
587 	struct chan *new, *chan;
588 	char *in, *out;
589 
590 	if(!list_empty(chans)){
591 		chan = list_entry(chans->next, struct chan, list);
592 		free_chan(chans, 0);
593 		INIT_LIST_HEAD(chans);
594 	}
595 
596 	out = strchr(str, ',');
597 	if(out != NULL){
598 		in = str;
599 		*out = '\0';
600 		out++;
601 		new = parse_chan(line, in, device, opts, error_out);
602 		if(new == NULL)
603 			return -1;
604 
605 		new->input = 1;
606 		list_add(&new->list, chans);
607 
608 		new = parse_chan(line, out, device, opts, error_out);
609 		if(new == NULL)
610 			return -1;
611 
612 		list_add(&new->list, chans);
613 		new->output = 1;
614 	}
615 	else {
616 		new = parse_chan(line, str, device, opts, error_out);
617 		if(new == NULL)
618 			return -1;
619 
620 		list_add(&new->list, chans);
621 		new->input = 1;
622 		new->output = 1;
623 	}
624 	return 0;
625 }
626 
627 int chan_out_fd(struct list_head *chans)
628 {
629 	struct list_head *ele;
630 	struct chan *chan;
631 
632 	list_for_each(ele, chans){
633 		chan = list_entry(ele, struct chan, list);
634 		if(chan->primary && chan->output)
635 			return chan->fd;
636 	}
637 	return -1;
638 }
639 
640 void chan_interrupt(struct list_head *chans, struct delayed_work *task,
641 		    struct tty_struct *tty, int irq)
642 {
643 	struct list_head *ele, *next;
644 	struct chan *chan;
645 	int err;
646 	char c;
647 
648 	list_for_each_safe(ele, next, chans){
649 		chan = list_entry(ele, struct chan, list);
650 		if(!chan->input || (chan->ops->read == NULL)) continue;
651 		do {
652 			if (tty && !tty_buffer_request_room(tty, 1)) {
653 				schedule_delayed_work(task, 1);
654 				goto out;
655 			}
656 			err = chan->ops->read(chan->fd, &c, chan->data);
657 			if(err > 0)
658 				tty_receive_char(tty, c);
659 		} while(err > 0);
660 
661 		if(err == 0) reactivate_fd(chan->fd, irq);
662 		if(err == -EIO){
663 			if(chan->primary){
664 				if(tty != NULL)
665 					tty_hangup(tty);
666 				close_chan(chans, 1);
667 				return;
668 			}
669 			else close_one_chan(chan, 1);
670 		}
671 	}
672  out:
673 	if(tty) tty_flip_buffer_push(tty);
674 }
675