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