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