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