diff options
Diffstat (limited to 'arch/um/drivers/line.c')
| -rw-r--r-- | arch/um/drivers/line.c | 116 |
1 files changed, 47 insertions, 69 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index da81d22ec04a..851a7c8caae5 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) |
| 3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
| 4 | */ | 4 | */ |
| @@ -23,8 +23,9 @@ | |||
| 23 | 23 | ||
| 24 | static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) | 24 | static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) |
| 25 | { | 25 | { |
| 26 | struct tty_struct *tty = data; | 26 | struct chan *chan = data; |
| 27 | struct line *line = tty->driver_data; | 27 | struct line *line = chan->line; |
| 28 | struct tty_struct *tty = line->tty; | ||
| 28 | 29 | ||
| 29 | if (line) | 30 | if (line) |
| 30 | chan_interrupt(&line->chan_list, &line->task, tty, irq); | 31 | chan_interrupt(&line->chan_list, &line->task, tty, irq); |
| @@ -33,10 +34,10 @@ static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) | |||
| 33 | 34 | ||
| 34 | static void line_timer_cb(void *arg) | 35 | static void line_timer_cb(void *arg) |
| 35 | { | 36 | { |
| 36 | struct tty_struct *tty = arg; | 37 | struct line *line = arg; |
| 37 | struct line *line = tty->driver_data; | ||
| 38 | 38 | ||
| 39 | line_interrupt(line->driver->read_irq, arg, NULL); | 39 | chan_interrupt(&line->chan_list, &line->task, line->tty, |
| 40 | line->driver->read_irq); | ||
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | /* Returns the free space inside the ring buffer of this line. | 43 | /* Returns the free space inside the ring buffer of this line. |
| @@ -342,8 +343,9 @@ int line_ioctl(struct tty_struct *tty, struct file * file, | |||
| 342 | static irqreturn_t line_write_interrupt(int irq, void *data, | 343 | static irqreturn_t line_write_interrupt(int irq, void *data, |
| 343 | struct pt_regs *unused) | 344 | struct pt_regs *unused) |
| 344 | { | 345 | { |
| 345 | struct tty_struct *tty = data; | 346 | struct chan *chan = data; |
| 346 | struct line *line = tty->driver_data; | 347 | struct line *line = chan->line; |
| 348 | struct tty_struct *tty = line->tty; | ||
| 347 | int err; | 349 | int err; |
| 348 | 350 | ||
| 349 | /* Interrupts are enabled here because we registered the interrupt with | 351 | /* Interrupts are enabled here because we registered the interrupt with |
| @@ -365,7 +367,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data, | |||
| 365 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && | 367 | if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && |
| 366 | (tty->ldisc.write_wakeup != NULL)) | 368 | (tty->ldisc.write_wakeup != NULL)) |
| 367 | (tty->ldisc.write_wakeup)(tty); | 369 | (tty->ldisc.write_wakeup)(tty); |
| 368 | 370 | ||
| 369 | /* BLOCKING mode | 371 | /* BLOCKING mode |
| 370 | * In blocking mode, everything sleeps on tty->write_wait. | 372 | * In blocking mode, everything sleeps on tty->write_wait. |
| 371 | * Sleeping in the console driver would break non-blocking | 373 | * Sleeping in the console driver would break non-blocking |
| @@ -377,52 +379,29 @@ static irqreturn_t line_write_interrupt(int irq, void *data, | |||
| 377 | return IRQ_HANDLED; | 379 | return IRQ_HANDLED; |
| 378 | } | 380 | } |
| 379 | 381 | ||
| 380 | int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) | 382 | int line_setup_irq(int fd, int input, int output, struct line *line, void *data) |
| 381 | { | 383 | { |
| 382 | struct line *line = tty->driver_data; | ||
| 383 | struct line_driver *driver = line->driver; | 384 | struct line_driver *driver = line->driver; |
| 384 | int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; | 385 | int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; |
| 385 | 386 | ||
| 386 | if (input) | 387 | if (input) |
| 387 | err = um_request_irq(driver->read_irq, fd, IRQ_READ, | 388 | err = um_request_irq(driver->read_irq, fd, IRQ_READ, |
| 388 | line_interrupt, flags, | 389 | line_interrupt, flags, |
| 389 | driver->read_irq_name, tty); | 390 | driver->read_irq_name, data); |
| 390 | if (err) | 391 | if (err) |
| 391 | return err; | 392 | return err; |
| 392 | if (output) | 393 | if (output) |
| 393 | err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, | 394 | err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, |
| 394 | line_write_interrupt, flags, | 395 | line_write_interrupt, flags, |
| 395 | driver->write_irq_name, tty); | 396 | driver->write_irq_name, data); |
| 396 | line->have_irq = 1; | 397 | line->have_irq = 1; |
| 397 | return err; | 398 | return err; |
| 398 | } | 399 | } |
| 399 | 400 | ||
| 400 | void line_disable(struct tty_struct *tty, int current_irq) | ||
| 401 | { | ||
| 402 | struct line *line = tty->driver_data; | ||
| 403 | |||
| 404 | if(!line->have_irq) | ||
| 405 | return; | ||
| 406 | |||
| 407 | if(line->driver->read_irq == current_irq) | ||
| 408 | free_irq_later(line->driver->read_irq, tty); | ||
| 409 | else { | ||
| 410 | free_irq(line->driver->read_irq, tty); | ||
| 411 | } | ||
| 412 | |||
| 413 | if(line->driver->write_irq == current_irq) | ||
| 414 | free_irq_later(line->driver->write_irq, tty); | ||
| 415 | else { | ||
| 416 | free_irq(line->driver->write_irq, tty); | ||
| 417 | } | ||
| 418 | |||
| 419 | line->have_irq = 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | int line_open(struct line *lines, struct tty_struct *tty) | 401 | int line_open(struct line *lines, struct tty_struct *tty) |
| 423 | { | 402 | { |
| 424 | struct line *line; | 403 | struct line *line; |
| 425 | int err = 0; | 404 | int err = -ENODEV; |
| 426 | 405 | ||
| 427 | line = &lines[tty->index]; | 406 | line = &lines[tty->index]; |
| 428 | tty->driver_data = line; | 407 | tty->driver_data = line; |
| @@ -430,29 +409,29 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
| 430 | /* The IRQ which takes this lock is not yet enabled and won't be run | 409 | /* The IRQ which takes this lock is not yet enabled and won't be run |
| 431 | * before the end, so we don't need to use spin_lock_irq.*/ | 410 | * before the end, so we don't need to use spin_lock_irq.*/ |
| 432 | spin_lock(&line->lock); | 411 | spin_lock(&line->lock); |
| 433 | if (tty->count == 1) { | ||
| 434 | if (!line->valid) { | ||
| 435 | err = -ENODEV; | ||
| 436 | goto out; | ||
| 437 | } | ||
| 438 | 412 | ||
| 439 | err = open_chan(&line->chan_list); | 413 | tty->driver_data = line; |
| 440 | if(err) | 414 | line->tty = tty; |
| 441 | goto out; | 415 | if(!line->valid) |
| 442 | 416 | goto out; | |
| 443 | /* Here the interrupt is registered.*/ | 417 | |
| 444 | enable_chan(&line->chan_list, tty); | 418 | if(tty->count == 1){ |
| 445 | INIT_WORK(&line->task, line_timer_cb, tty); | 419 | /* Here the device is opened, if necessary, and interrupt |
| 446 | } | 420 | * is registered. |
| 421 | */ | ||
| 422 | enable_chan(line); | ||
| 423 | INIT_WORK(&line->task, line_timer_cb, line); | ||
| 424 | |||
| 425 | if(!line->sigio){ | ||
| 426 | chan_enable_winch(&line->chan_list, tty); | ||
| 427 | line->sigio = 1; | ||
| 428 | } | ||
| 447 | 429 | ||
| 448 | if(!line->sigio){ | 430 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
| 449 | chan_enable_winch(&line->chan_list, tty); | 431 | &tty->winsize.ws_col); |
| 450 | line->sigio = 1; | ||
| 451 | } | 432 | } |
| 452 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | ||
| 453 | &tty->winsize.ws_col); | ||
| 454 | line->count++; | ||
| 455 | 433 | ||
| 434 | err = 0; | ||
| 456 | out: | 435 | out: |
| 457 | spin_unlock(&line->lock); | 436 | spin_unlock(&line->lock); |
| 458 | return err; | 437 | return err; |
| @@ -472,15 +451,14 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
| 472 | /* We ignore the error anyway! */ | 451 | /* We ignore the error anyway! */ |
| 473 | flush_buffer(line); | 452 | flush_buffer(line); |
| 474 | 453 | ||
| 475 | line->count--; | 454 | if(tty->count == 1){ |
| 476 | if (tty->count == 1) { | 455 | line->tty = NULL; |
| 477 | line_disable(tty, -1); | ||
| 478 | tty->driver_data = NULL; | 456 | tty->driver_data = NULL; |
| 479 | } | ||
| 480 | 457 | ||
| 481 | if((line->count == 0) && line->sigio){ | 458 | if(line->sigio){ |
| 482 | unregister_winch(tty); | 459 | unregister_winch(tty); |
| 483 | line->sigio = 0; | 460 | line->sigio = 0; |
| 461 | } | ||
| 484 | } | 462 | } |
| 485 | 463 | ||
| 486 | spin_unlock_irq(&line->lock); | 464 | spin_unlock_irq(&line->lock); |
| @@ -491,7 +469,7 @@ void close_lines(struct line *lines, int nlines) | |||
| 491 | int i; | 469 | int i; |
| 492 | 470 | ||
| 493 | for(i = 0; i < nlines; i++) | 471 | for(i = 0; i < nlines; i++) |
| 494 | close_chan(&lines[i].chan_list); | 472 | close_chan(&lines[i].chan_list, 0); |
| 495 | } | 473 | } |
| 496 | 474 | ||
| 497 | /* Common setup code for both startup command line and mconsole initialization. | 475 | /* Common setup code for both startup command line and mconsole initialization. |
| @@ -526,7 +504,7 @@ int line_setup(struct line *lines, unsigned int num, char *init) | |||
| 526 | return 0; | 504 | return 0; |
| 527 | } | 505 | } |
| 528 | else if (n >= 0){ | 506 | else if (n >= 0){ |
| 529 | if (lines[n].count > 0) { | 507 | if (lines[n].tty != NULL) { |
| 530 | printk("line_setup - device %d is open\n", n); | 508 | printk("line_setup - device %d is open\n", n); |
| 531 | return 0; | 509 | return 0; |
| 532 | } | 510 | } |
| @@ -537,7 +515,7 @@ int line_setup(struct line *lines, unsigned int num, char *init) | |||
| 537 | else { | 515 | else { |
| 538 | lines[n].init_str = init; | 516 | lines[n].init_str = init; |
| 539 | lines[n].valid = 1; | 517 | lines[n].valid = 1; |
| 540 | } | 518 | } |
| 541 | } | 519 | } |
| 542 | } | 520 | } |
| 543 | else { | 521 | else { |
| @@ -578,7 +556,7 @@ int line_config(struct line *lines, unsigned int num, char *str, | |||
| 578 | return 1; | 556 | return 1; |
| 579 | 557 | ||
| 580 | line = &lines[n]; | 558 | line = &lines[n]; |
| 581 | return parse_chan_pair(line->init_str, &line->chan_list, n, opts); | 559 | return parse_chan_pair(line->init_str, line, n, opts); |
| 582 | } | 560 | } |
| 583 | 561 | ||
| 584 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, | 562 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, |
| @@ -604,7 +582,7 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, | |||
| 604 | spin_lock(&line->lock); | 582 | spin_lock(&line->lock); |
| 605 | if(!line->valid) | 583 | if(!line->valid) |
| 606 | CONFIG_CHUNK(str, size, n, "none", 1); | 584 | CONFIG_CHUNK(str, size, n, "none", 1); |
| 607 | else if(line->count == 0) | 585 | else if(line->tty == NULL) |
| 608 | CONFIG_CHUNK(str, size, n, line->init_str, 1); | 586 | CONFIG_CHUNK(str, size, n, line->init_str, 1); |
| 609 | else n = chan_config_string(&line->chan_list, str, size, error_out); | 587 | else n = chan_config_string(&line->chan_list, str, size, error_out); |
| 610 | spin_unlock(&line->lock); | 588 | spin_unlock(&line->lock); |
| @@ -696,7 +674,7 @@ void lines_init(struct line *lines, int nlines, struct chan_opts *opts) | |||
| 696 | if(line->init_str == NULL) | 674 | if(line->init_str == NULL) |
| 697 | printk("lines_init - kstrdup returned NULL\n"); | 675 | printk("lines_init - kstrdup returned NULL\n"); |
| 698 | 676 | ||
| 699 | if(parse_chan_pair(line->init_str, &line->chan_list, i, opts)){ | 677 | if(parse_chan_pair(line->init_str, line, i, opts)){ |
| 700 | printk("parse_chan_pair failed for device %d\n", i); | 678 | printk("parse_chan_pair failed for device %d\n", i); |
| 701 | line->valid = 0; | 679 | line->valid = 0; |
| 702 | } | 680 | } |
| @@ -831,7 +809,7 @@ char *add_xterm_umid(char *base) | |||
| 831 | umid = get_umid(1); | 809 | umid = get_umid(1); |
| 832 | if(umid == NULL) | 810 | if(umid == NULL) |
| 833 | return base; | 811 | return base; |
| 834 | 812 | ||
| 835 | len = strlen(base) + strlen(" ()") + strlen(umid) + 1; | 813 | len = strlen(base) + strlen(" ()") + strlen(umid) + 1; |
| 836 | title = kmalloc(len, GFP_KERNEL); | 814 | title = kmalloc(len, GFP_KERNEL); |
| 837 | if(title == NULL){ | 815 | if(title == NULL){ |
