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