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 void *data) 94 { 95 my_puts("Using a channel type which is configured out of " 96 "UML\n"); 97 return(-EIO); 98 } 99 100 static int not_configged_window_size(int fd, void *data, unsigned short *rows, 101 unsigned short *cols) 102 { 103 my_puts("Using a channel type which is configured out of " 104 "UML\n"); 105 return(-ENODEV); 106 } 107 108 static void not_configged_free(void *data) 109 { 110 my_puts("Using a channel type which is configured out of " 111 "UML\n"); 112 } 113 114 static struct chan_ops not_configged_ops = { 115 .init = not_configged_init, 116 .open = not_configged_open, 117 .close = not_configged_close, 118 .read = not_configged_read, 119 .write = not_configged_write, 120 .console_write = not_configged_console_write, 121 .window_size = not_configged_window_size, 122 .free = not_configged_free, 123 .winch = 0, 124 }; 125 #endif /* CONFIG_NOCONFIG_CHAN */ 126 127 void generic_close(int fd, void *unused) 128 { 129 os_close_file(fd); 130 } 131 132 int generic_read(int fd, char *c_out, void *unused) 133 { 134 int n; 135 136 n = os_read_file(fd, c_out, sizeof(*c_out)); 137 138 if(n == -EAGAIN) 139 return(0); 140 else if(n == 0) 141 return(-EIO); 142 return(n); 143 } 144 145 /* XXX Trivial wrapper around os_write_file */ 146 147 int generic_write(int fd, const char *buf, int n, void *unused) 148 { 149 return(os_write_file(fd, buf, n)); 150 } 151 152 int generic_window_size(int fd, void *unused, unsigned short *rows_out, 153 unsigned short *cols_out) 154 { 155 int rows, cols; 156 int ret; 157 158 ret = os_window_size(fd, &rows, &cols); 159 if(ret < 0) 160 return(ret); 161 162 ret = ((*rows_out != rows) || (*cols_out != cols)); 163 164 *rows_out = rows; 165 *cols_out = cols; 166 167 return(ret); 168 } 169 170 void generic_free(void *data) 171 { 172 kfree(data); 173 } 174 175 static void tty_receive_char(struct tty_struct *tty, char ch) 176 { 177 if(tty == NULL) return; 178 179 if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) { 180 if(ch == STOP_CHAR(tty)){ 181 stop_tty(tty); 182 return; 183 } 184 else if(ch == START_CHAR(tty)){ 185 start_tty(tty); 186 return; 187 } 188 } 189 190 if((tty->flip.flag_buf_ptr == NULL) || 191 (tty->flip.char_buf_ptr == NULL)) 192 return; 193 tty_insert_flip_char(tty, ch, TTY_NORMAL); 194 } 195 196 static int open_one_chan(struct chan *chan, int input, int output, int primary) 197 { 198 int fd; 199 200 if(chan->opened) return(0); 201 if(chan->ops->open == NULL) fd = 0; 202 else fd = (*chan->ops->open)(input, output, primary, chan->data, 203 &chan->dev); 204 if(fd < 0) 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, chan->input, chan->output, 220 chan->primary); 221 if(chan->primary) 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 list_head *chans, struct tty_struct *tty) 241 { 242 struct list_head *ele; 243 struct chan *chan; 244 245 list_for_each(ele, chans){ 246 chan = list_entry(ele, struct chan, list); 247 if(!chan->opened) continue; 248 249 line_setup_irq(chan->fd, chan->input, chan->output, tty); 250 } 251 } 252 253 void close_chan(struct list_head *chans) 254 { 255 struct chan *chan; 256 257 /* Close in reverse order as open in case more than one of them 258 * refers to the same device and they save and restore that device's 259 * state. Then, the first one opened will have the original state, 260 * so it must be the last closed. 261 */ 262 list_for_each_entry_reverse(chan, chans, list) { 263 if(!chan->opened) continue; 264 if(chan->ops->close != NULL) 265 (*chan->ops->close)(chan->fd, chan->data); 266 chan->opened = 0; 267 chan->fd = -1; 268 } 269 } 270 271 int write_chan(struct list_head *chans, const char *buf, int len, 272 int write_irq) 273 { 274 struct list_head *ele; 275 struct chan *chan = NULL; 276 int n, ret = 0; 277 278 list_for_each(ele, chans) { 279 chan = list_entry(ele, struct chan, list); 280 if (!chan->output || (chan->ops->write == NULL)) 281 continue; 282 n = chan->ops->write(chan->fd, buf, len, chan->data); 283 if (chan->primary) { 284 ret = n; 285 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) 286 reactivate_fd(chan->fd, write_irq); 287 } 288 } 289 return(ret); 290 } 291 292 int console_write_chan(struct list_head *chans, const char *buf, int len) 293 { 294 struct list_head *ele; 295 struct chan *chan; 296 int n, ret = 0; 297 298 list_for_each(ele, chans){ 299 chan = list_entry(ele, struct chan, list); 300 if(!chan->output || (chan->ops->console_write == NULL)) 301 continue; 302 n = chan->ops->console_write(chan->fd, buf, len, chan->data); 303 if(chan->primary) ret = n; 304 } 305 return(ret); 306 } 307 308 int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts) 309 { 310 if (!list_empty(&line->chan_list)) 311 return 0; 312 313 if (0 != parse_chan_pair(line->init_str, &line->chan_list, 314 line->init_pri, co->index, opts)) 315 return -1; 316 if (0 != open_chan(&line->chan_list)) 317 return -1; 318 printk("Console initialized on /dev/%s%d\n",co->name,co->index); 319 return 0; 320 } 321 322 int chan_window_size(struct list_head *chans, unsigned short *rows_out, 323 unsigned short *cols_out) 324 { 325 struct list_head *ele; 326 struct chan *chan; 327 328 list_for_each(ele, chans){ 329 chan = list_entry(ele, struct chan, list); 330 if(chan->primary){ 331 if(chan->ops->window_size == NULL) return(0); 332 return(chan->ops->window_size(chan->fd, chan->data, 333 rows_out, cols_out)); 334 } 335 } 336 return(0); 337 } 338 339 void free_one_chan(struct chan *chan) 340 { 341 list_del(&chan->list); 342 if(chan->ops->free != NULL) 343 (*chan->ops->free)(chan->data); 344 free_irq_by_fd(chan->fd); 345 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd); 346 kfree(chan); 347 } 348 349 void free_chan(struct list_head *chans) 350 { 351 struct list_head *ele, *next; 352 struct chan *chan; 353 354 list_for_each_safe(ele, next, chans){ 355 chan = list_entry(ele, struct chan, list); 356 free_one_chan(chan); 357 } 358 } 359 360 static int one_chan_config_string(struct chan *chan, char *str, int size, 361 char **error_out) 362 { 363 int n = 0; 364 365 if(chan == NULL){ 366 CONFIG_CHUNK(str, size, n, "none", 1); 367 return(n); 368 } 369 370 CONFIG_CHUNK(str, size, n, chan->ops->type, 0); 371 372 if(chan->dev == NULL){ 373 CONFIG_CHUNK(str, size, n, "", 1); 374 return(n); 375 } 376 377 CONFIG_CHUNK(str, size, n, ":", 0); 378 CONFIG_CHUNK(str, size, n, chan->dev, 0); 379 380 return(n); 381 } 382 383 static int chan_pair_config_string(struct chan *in, struct chan *out, 384 char *str, int size, char **error_out) 385 { 386 int n; 387 388 n = one_chan_config_string(in, str, size, error_out); 389 str += n; 390 size -= n; 391 392 if(in == out){ 393 CONFIG_CHUNK(str, size, n, "", 1); 394 return(n); 395 } 396 397 CONFIG_CHUNK(str, size, n, ",", 1); 398 n = one_chan_config_string(out, str, size, error_out); 399 str += n; 400 size -= n; 401 CONFIG_CHUNK(str, size, n, "", 1); 402 403 return(n); 404 } 405 406 int chan_config_string(struct list_head *chans, char *str, int size, 407 char **error_out) 408 { 409 struct list_head *ele; 410 struct chan *chan, *in = NULL, *out = NULL; 411 412 list_for_each(ele, chans){ 413 chan = list_entry(ele, struct chan, list); 414 if(!chan->primary) 415 continue; 416 if(chan->input) 417 in = chan; 418 if(chan->output) 419 out = chan; 420 } 421 422 return(chan_pair_config_string(in, out, str, size, error_out)); 423 } 424 425 struct chan_type { 426 char *key; 427 struct chan_ops *ops; 428 }; 429 430 struct chan_type chan_table[] = { 431 { "fd", &fd_ops }, 432 433 #ifdef CONFIG_NULL_CHAN 434 { "null", &null_ops }, 435 #else 436 { "null", ¬_configged_ops }, 437 #endif 438 439 #ifdef CONFIG_PORT_CHAN 440 { "port", &port_ops }, 441 #else 442 { "port", ¬_configged_ops }, 443 #endif 444 445 #ifdef CONFIG_PTY_CHAN 446 { "pty", &pty_ops }, 447 { "pts", &pts_ops }, 448 #else 449 { "pty", ¬_configged_ops }, 450 { "pts", ¬_configged_ops }, 451 #endif 452 453 #ifdef CONFIG_TTY_CHAN 454 { "tty", &tty_ops }, 455 #else 456 { "tty", ¬_configged_ops }, 457 #endif 458 459 #ifdef CONFIG_XTERM_CHAN 460 { "xterm", &xterm_ops }, 461 #else 462 { "xterm", ¬_configged_ops }, 463 #endif 464 }; 465 466 static struct chan *parse_chan(char *str, int pri, int device, 467 struct chan_opts *opts) 468 { 469 struct chan_type *entry; 470 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 < sizeof(chan_table)/sizeof(chan_table[0]); 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 my_printf("parse_chan couldn't parse \"%s\"\n", 487 str); 488 return(NULL); 489 } 490 if(ops->init == NULL) return(NULL); 491 data = (*ops->init)(str, device, opts); 492 if(data == NULL) return(NULL); 493 494 chan = kmalloc(sizeof(*chan), GFP_ATOMIC); 495 if(chan == NULL) return(NULL); 496 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), 497 .primary = 1, 498 .input = 0, 499 .output = 0, 500 .opened = 0, 501 .fd = -1, 502 .pri = pri, 503 .ops = ops, 504 .data = data }); 505 return(chan); 506 } 507 508 int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, 509 struct chan_opts *opts) 510 { 511 struct chan *new, *chan; 512 char *in, *out; 513 514 if(!list_empty(chans)){ 515 chan = list_entry(chans->next, struct chan, list); 516 if(chan->pri >= pri) return(0); 517 free_chan(chans); 518 INIT_LIST_HEAD(chans); 519 } 520 521 out = strchr(str, ','); 522 if(out != NULL){ 523 in = str; 524 *out = '\0'; 525 out++; 526 new = parse_chan(in, pri, device, opts); 527 if(new == NULL) return(-1); 528 new->input = 1; 529 list_add(&new->list, chans); 530 531 new = parse_chan(out, pri, device, opts); 532 if(new == NULL) return(-1); 533 list_add(&new->list, chans); 534 new->output = 1; 535 } 536 else { 537 new = parse_chan(str, pri, device, opts); 538 if(new == NULL) return(-1); 539 list_add(&new->list, chans); 540 new->input = 1; 541 new->output = 1; 542 } 543 return(0); 544 } 545 546 int chan_out_fd(struct list_head *chans) 547 { 548 struct list_head *ele; 549 struct chan *chan; 550 551 list_for_each(ele, chans){ 552 chan = list_entry(ele, struct chan, list); 553 if(chan->primary && chan->output) 554 return(chan->fd); 555 } 556 return(-1); 557 } 558 559 void chan_interrupt(struct list_head *chans, struct work_struct *task, 560 struct tty_struct *tty, int irq) 561 { 562 struct list_head *ele, *next; 563 struct chan *chan; 564 int err; 565 char c; 566 567 list_for_each_safe(ele, next, chans){ 568 chan = list_entry(ele, struct chan, list); 569 if(!chan->input || (chan->ops->read == NULL)) continue; 570 do { 571 if((tty != NULL) && 572 (tty->flip.count >= TTY_FLIPBUF_SIZE)){ 573 schedule_work(task); 574 goto out; 575 } 576 err = chan->ops->read(chan->fd, &c, chan->data); 577 if(err > 0) 578 tty_receive_char(tty, c); 579 } while(err > 0); 580 581 if(err == 0) reactivate_fd(chan->fd, irq); 582 if(err == -EIO){ 583 if(chan->primary){ 584 if(tty != NULL) 585 tty_hangup(tty); 586 line_disable(tty, irq); 587 close_chan(chans); 588 free_chan(chans); 589 return; 590 } 591 else { 592 if(chan->ops->close != NULL) 593 chan->ops->close(chan->fd, chan->data); 594 free_one_chan(chan); 595 } 596 } 597 } 598 out: 599 if(tty) tty_flip_buffer_push(tty); 600 } 601 602 /* 603 * Overrides for Emacs so that we follow Linus's tabbing style. 604 * Emacs will notice this stuff at the end of the file and automatically 605 * adjust the settings for this buffer only. This must remain at the end 606 * of the file. 607 * --------------------------------------------------------------------------- 608 * Local variables: 609 * c-file-style: "linux" 610 * End: 611 */ 612