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