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){ |