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 if((tty->flip.flag_buf_ptr == NULL) || 190 (tty->flip.char_buf_ptr == NULL)) 191 return; 192 tty_insert_flip_char(tty, ch, TTY_NORMAL); 193 } 194 195 static int open_one_chan(struct chan *chan, int input, int output, int primary) 196 { 197 int fd; 198 199 if(chan->opened) return(0); 200 if(chan->ops->open == NULL) fd = 0; 201 else fd = (*chan->ops->open)(input, output, primary, chan->data, 202 &chan->dev); 203 if(fd < 0) return(fd); 204 chan->fd = fd; 205 206 chan->opened = 1; 207 return(0); 208 } 209 210 int open_chan(struct list_head *chans) 211 { 212 struct list_head *ele; 213 struct chan *chan; 214 int ret, err = 0; 215 216 list_for_each(ele, chans){ 217 chan = list_entry(ele, struct chan, list); 218 ret = open_one_chan(chan, chan->input, chan->output, 219 chan->primary); 220 if(chan->primary) err = ret; 221 } 222 return(err); 223 } 224 225 void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) 226 { 227 struct list_head *ele; 228 struct chan *chan; 229 230 list_for_each(ele, chans){ 231 chan = list_entry(ele, struct chan, list); 232 if(chan->primary && chan->output && chan->ops->winch){ 233 register_winch(chan->fd, tty); 234 return; 235 } 236 } 237 } 238 239 void enable_chan(struct list_head *chans, struct tty_struct *tty) 240 { 241 struct list_head *ele; 242 struct chan *chan; 243 244 list_for_each(ele, chans){ 245 chan = list_entry(ele, struct chan, list); 246 if(!chan->opened) continue; 247 248 line_setup_irq(chan->fd, chan->input, chan->output, tty); 249 } 250 } 251 252 void close_chan(struct list_head *chans) 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, chans, list) { 262 if(!chan->opened) continue; 263 if(chan->ops->close != NULL) 264 (*chan->ops->close)(chan->fd, chan->data); 265 chan->opened = 0; 266 chan->fd = -1; 267 } 268 } 269 270 int write_chan(struct list_head *chans, const char *buf, int len, 271 int write_irq) 272 { 273 struct list_head *ele; 274 struct chan *chan = NULL; 275 int n, ret = 0; 276 277 list_for_each(ele, chans) { 278 chan = list_entry(ele, struct chan, list); 279 if (!chan->output || (chan->ops->write == NULL)) 280 continue; 281 n = chan->ops->write(chan->fd, buf, len, chan->data); 282 if (chan->primary) { 283 ret = n; 284 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) 285 reactivate_fd(chan->fd, write_irq); 286 } 287 } 288 return(ret); 289 } 290 291 int console_write_chan(struct list_head *chans, const char *buf, int len) 292 { 293 struct list_head *ele; 294 struct chan *chan; 295 int n, ret = 0; 296 297 list_for_each(ele, chans){ 298 chan = list_entry(ele, struct chan, list); 299 if(!chan->output || (chan->ops->console_write == NULL)) 300 continue; 301 n = chan->ops->console_write(chan->fd, buf, len); 302 if(chan->primary) ret = n; 303 } 304 return(ret); 305 } 306 307 int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts) 308 { 309 if (!list_empty(&line->chan_list)) 310 return 0; 311 312 if (0 != parse_chan_pair(line->init_str, &line->chan_list, 313 line->init_pri, co->index, opts)) 314 return -1; 315 if (0 != open_chan(&line->chan_list)) 316 return -1; 317 printk("Console initialized on /dev/%s%d\n",co->name,co->index); 318 return 0; 319 } 320 321 int chan_window_size(struct list_head *chans, unsigned short *rows_out, 322 unsigned short *cols_out) 323 { 324 struct list_head *ele; 325 struct chan *chan; 326 327 list_for_each(ele, chans){ 328 chan = list_entry(ele, struct chan, list); 329 if(chan->primary){ 330 if(chan->ops->window_size == NULL) return(0); 331 return(chan->ops->window_size(chan->fd, chan->data, 332 rows_out, cols_out)); 333 } 334 } 335 return(0); 336 } 337 338 void free_one_chan(struct chan *chan) 339 { 340 list_del(&chan->list); 341 if(chan->ops->free != NULL) 342 (*chan->ops->free)(chan->data); 343 free_irq_by_fd(chan->fd); 344 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd); 345 kfree(chan); 346 } 347 348 void free_chan(struct list_head *chans) 349 { 350 struct list_head *ele, *next; 351 struct chan *chan; 352 353 list_for_each_safe(ele, next, chans){ 354 chan = list_entry(ele, struct chan, list); 355 free_one_chan(chan); 356 } 357 } 358 359 static int one_chan_config_string(struct chan *chan, char *str, int size, 360 char **error_out) 361 { 362 int n = 0; 363 364 if(chan == NULL){ 365 CONFIG_CHUNK(str, size, n, "none", 1); 366 return(n); 367 } 368 369 CONFIG_CHUNK(str, size, n, chan->ops->type, 0); 370 371 if(chan->dev == NULL){ 372 CONFIG_CHUNK(str, size, n, "", 1); 373 return(n); 374 } 375 376 CONFIG_CHUNK(str, size, n, ":", 0); 377 CONFIG_CHUNK(str, size, n, chan->dev, 0); 378 379 return(n); 380 } 381 382 static int chan_pair_config_string(struct chan *in, struct chan *out, 383 char *str, int size, char **error_out) 384 { 385 int n; 386 387 n = one_chan_config_string(in, str, size, error_out); 388 str += n; 389 size -= n; 390 391 if(in == out){ 392 CONFIG_CHUNK(str, size, n, "", 1); 393 return(n); 394 } 395 396 CONFIG_CHUNK(str, size, n, ",", 1); 397 n = one_chan_config_string(out, str, size, error_out); 398 str += n; 399 size -= n; 400 CONFIG_CHUNK(str, size, n, "", 1); 401 402 return(n); 403 } 404 405 int chan_config_string(struct list_head *chans, char *str, int size, 406 char **error_out) 407 { 408 struct list_head *ele; 409 struct chan *chan, *in = NULL, *out = NULL; 410 411 list_for_each(ele, chans){ 412 chan = list_entry(ele, struct chan, list); 413 if(!chan->primary) 414 continue; 415 if(chan->input) 416 in = chan; 417 if(chan->output) 418 out = chan; 419 } 420 421 return(chan_pair_config_string(in, out, str, size, error_out)); 422 } 423 424 struct chan_type { 425 char *key; 426 struct chan_ops *ops; 427 }; 428 429 struct chan_type chan_table[] = { 430 { "fd", &fd_ops }, 431 432 #ifdef CONFIG_NULL_CHAN 433 { "null", &null_ops }, 434 #else 435 { "null", ¬_configged_ops }, 436 #endif 437 438 #ifdef CONFIG_PORT_CHAN 439 { "port", &port_ops }, 440 #else 441 { "port", ¬_configged_ops }, 442 #endif 443 444 #ifdef CONFIG_PTY_CHAN 445 { "pty", &pty_ops }, 446 { "pts", &pts_ops }, 447 #else 448 { "pty", ¬_configged_ops }, 449 { "pts", ¬_configged_ops }, 450 #endif 451 452 #ifdef CONFIG_TTY_CHAN 453 { "tty", &tty_ops }, 454 #else 455 { "tty", ¬_configged_ops }, 456 #endif 457 458 #ifdef CONFIG_XTERM_CHAN 459 { "xterm", &xterm_ops }, 460 #else 461 { "xterm", ¬_configged_ops }, 462 #endif 463 }; 464 465 static struct chan *parse_chan(char *str, int pri, int device, 466 struct chan_opts *opts) 467 { 468 struct chan_type *entry; 469 struct chan_ops *ops; 470 struct chan *chan; 471 void *data; 472 int i; 473 474 ops = NULL; 475 data = NULL; 476 for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){ 477 entry = &chan_table[i]; 478 if(!strncmp(str, entry->key, strlen(entry->key))){ 479 ops = entry->ops; 480 str += strlen(entry->key); 481 break; 482 } 483 } 484 if(ops == NULL){ 485 my_printf("parse_chan couldn't parse \"%s\"\n", 486 str); 487 return(NULL); 488 } 489 if(ops->init == NULL) return(NULL); 490 data = (*ops->init)(str, device, opts); 491 if(data == NULL) return(NULL); 492 493 chan = kmalloc(sizeof(*chan), GFP_ATOMIC); 494 if(chan == NULL) return(NULL); 495 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), 496 .primary = 1, 497 .input = 0, 498 .output = 0, 499 .opened = 0, 500 .fd = -1, 501 .pri = pri, 502 .ops = ops, 503 .data = data }); 504 return(chan); 505 } 506 507 int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, 508 struct chan_opts *opts) 509 { 510 struct chan *new, *chan; 511 char *in, *out; 512 513 if(!list_empty(chans)){ 514 chan = list_entry(chans->next, struct chan, list); 515 if(chan->pri >= pri) return(0); 516 free_chan(chans); 517 INIT_LIST_HEAD(chans); 518 } 519 520 out = strchr(str, ','); 521 if(out != NULL){ 522 in = str; 523 *out = '\0'; 524 out++; 525 new = parse_chan(in, pri, device, opts); 526 if(new == NULL) return(-1); 527 new->input = 1; 528 list_add(&new->list, chans); 529 530 new = parse_chan(out, pri, device, opts); 531 if(new == NULL) return(-1); 532 list_add(&new->list, chans); 533 new->output = 1; 534 } 535 else { 536 new = parse_chan(str, pri, device, opts); 537 if(new == NULL) return(-1); 538 list_add(&new->list, chans); 539 new->input = 1; 540 new->output = 1; 541 } 542 return(0); 543 } 544 545 int chan_out_fd(struct list_head *chans) 546 { 547 struct list_head *ele; 548 struct chan *chan; 549 550 list_for_each(ele, chans){ 551 chan = list_entry(ele, struct chan, list); 552 if(chan->primary && chan->output) 553 return(chan->fd); 554 } 555 return(-1); 556 } 557 558 void chan_interrupt(struct list_head *chans, struct work_struct *task, 559 struct tty_struct *tty, int irq) 560 { 561 struct list_head *ele, *next; 562 struct chan *chan; 563 int err; 564 char c; 565 566 list_for_each_safe(ele, next, chans){ 567 chan = list_entry(ele, struct chan, list); 568 if(!chan->input || (chan->ops->read == NULL)) continue; 569 do { 570 if((tty != NULL) && 571 (tty->flip.count >= TTY_FLIPBUF_SIZE)){ 572 schedule_work(task); 573 goto out; 574 } 575 err = chan->ops->read(chan->fd, &c, chan->data); 576 if(err > 0) 577 tty_receive_char(tty, c); 578 } while(err > 0); 579 580 if(err == 0) reactivate_fd(chan->fd, irq); 581 if(err == -EIO){ 582 if(chan->primary){ 583 if(tty != NULL) 584 tty_hangup(tty); 585 line_disable(tty, irq); 586 close_chan(chans); 587 free_chan(chans); 588 return; 589 } 590 else { 591 if(chan->ops->close != NULL) 592 chan->ops->close(chan->fd, chan->data); 593 free_one_chan(chan); 594 } 595 } 596 } 597 out: 598 if(tty) tty_flip_buffer_push(tty); 599 } 600 601 /* 602 * Overrides for Emacs so that we follow Linus's tabbing style. 603 * Emacs will notice this stuff at the end of the file and automatically 604 * adjust the settings for this buffer only. This must remain at the end 605 * of the file. 606 * --------------------------------------------------------------------------- 607 * Local variables: 608 * c-file-style: "linux" 609 * End: 610 */ 611