Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
chan_kern.c
Go to the documentation of this file.
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  */
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)
603 }