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