diff options
author | Alan Cox <alan@linux.intel.com> | 2009-11-05 08:28:29 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 18:18:05 -0500 |
commit | 530646f4695b396aeeec2ca912dcc3a9c95e0f52 (patch) | |
tree | 497560a2cd9c8d1e6022e0553bf2fe9c794bf95a | |
parent | 0395b48c78ed822f251ab15d0fbc3ce06f41ffb1 (diff) |
sdio_uart: refcount the tty objects
The tty can go away underneath us, so we must refcount it. Do the naïve
implementation initially. We will worry about startup shortly.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/mmc/card/sdio_uart.c | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 671fe5efabf3..86ad54341128 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c | |||
@@ -172,8 +172,13 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) | |||
172 | sdio_claim_host(func); | 172 | sdio_claim_host(func); |
173 | port->func = NULL; | 173 | port->func = NULL; |
174 | mutex_unlock(&port->func_lock); | 174 | mutex_unlock(&port->func_lock); |
175 | if (port->opened) | 175 | if (port->opened) { |
176 | tty_hangup(port->port.tty); | 176 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
177 | /* tty_hangup is async so is this safe as is ?? */ | ||
178 | if (tty) | ||
179 | tty_hangup(tty); | ||
180 | tty_kref_put(tty); | ||
181 | } | ||
177 | mutex_unlock(&port->open_lock); | 182 | mutex_unlock(&port->open_lock); |
178 | sdio_release_irq(func); | 183 | sdio_release_irq(func); |
179 | sdio_disable_func(func); | 184 | sdio_disable_func(func); |
@@ -392,7 +397,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) | |||
392 | static void sdio_uart_receive_chars(struct sdio_uart_port *port, | 397 | static void sdio_uart_receive_chars(struct sdio_uart_port *port, |
393 | unsigned int *status) | 398 | unsigned int *status) |
394 | { | 399 | { |
395 | struct tty_struct *tty = port->port.tty; | 400 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
396 | unsigned int ch, flag; | 401 | unsigned int ch, flag; |
397 | int max_count = 256; | 402 | int max_count = 256; |
398 | 403 | ||
@@ -429,25 +434,30 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, | |||
429 | } | 434 | } |
430 | 435 | ||
431 | if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) | 436 | if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) |
432 | tty_insert_flip_char(tty, ch, flag); | 437 | if (tty) |
438 | tty_insert_flip_char(tty, ch, flag); | ||
433 | 439 | ||
434 | /* | 440 | /* |
435 | * Overrun is special. Since it's reported immediately, | 441 | * Overrun is special. Since it's reported immediately, |
436 | * it doesn't affect the current character. | 442 | * it doesn't affect the current character. |
437 | */ | 443 | */ |
438 | if (*status & ~port->ignore_status_mask & UART_LSR_OE) | 444 | if (*status & ~port->ignore_status_mask & UART_LSR_OE) |
439 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | 445 | if (tty) |
446 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
440 | 447 | ||
441 | *status = sdio_in(port, UART_LSR); | 448 | *status = sdio_in(port, UART_LSR); |
442 | } while ((*status & UART_LSR_DR) && (max_count-- > 0)); | 449 | } while ((*status & UART_LSR_DR) && (max_count-- > 0)); |
443 | tty_flip_buffer_push(tty); | 450 | if (tty) { |
451 | tty_flip_buffer_push(tty); | ||
452 | tty_kref_put(tty); | ||
453 | } | ||
444 | } | 454 | } |
445 | 455 | ||
446 | static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | 456 | static void sdio_uart_transmit_chars(struct sdio_uart_port *port) |
447 | { | 457 | { |
448 | struct circ_buf *xmit = &port->xmit; | 458 | struct circ_buf *xmit = &port->xmit; |
449 | int count; | 459 | int count; |
450 | struct tty_struct *tty = port->port.tty; | 460 | struct tty_struct *tty; |
451 | 461 | ||
452 | if (port->x_char) { | 462 | if (port->x_char) { |
453 | sdio_out(port, UART_TX, port->x_char); | 463 | sdio_out(port, UART_TX, port->x_char); |
@@ -455,8 +465,12 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | |||
455 | port->x_char = 0; | 465 | port->x_char = 0; |
456 | return; | 466 | return; |
457 | } | 467 | } |
458 | if (circ_empty(xmit) || tty->stopped || tty->hw_stopped) { | 468 | |
469 | tty = tty_port_tty_get(&port->port); | ||
470 | |||
471 | if (tty == NULL || circ_empty(xmit) || tty->stopped || tty->hw_stopped) { | ||
459 | sdio_uart_stop_tx(port); | 472 | sdio_uart_stop_tx(port); |
473 | tty_kref_put(tty); | ||
460 | return; | 474 | return; |
461 | } | 475 | } |
462 | 476 | ||
@@ -474,12 +488,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | |||
474 | 488 | ||
475 | if (circ_empty(xmit)) | 489 | if (circ_empty(xmit)) |
476 | sdio_uart_stop_tx(port); | 490 | sdio_uart_stop_tx(port); |
491 | tty_kref_put(tty); | ||
477 | } | 492 | } |
478 | 493 | ||
479 | static void sdio_uart_check_modem_status(struct sdio_uart_port *port) | 494 | static void sdio_uart_check_modem_status(struct sdio_uart_port *port) |
480 | { | 495 | { |
481 | int status; | 496 | int status; |
482 | struct tty_struct *tty = port->port.tty; | 497 | struct tty_struct *tty; |
483 | 498 | ||
484 | status = sdio_in(port, UART_MSR); | 499 | status = sdio_in(port, UART_MSR); |
485 | 500 | ||
@@ -494,7 +509,8 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) | |||
494 | port->icount.dcd++; | 509 | port->icount.dcd++; |
495 | if (status & UART_MSR_DCTS) { | 510 | if (status & UART_MSR_DCTS) { |
496 | port->icount.cts++; | 511 | port->icount.cts++; |
497 | if (tty->termios->c_cflag & CRTSCTS) { | 512 | tty = tty_port_tty_get(&port->port); |
513 | if (tty && (tty->termios->c_cflag & CRTSCTS)) { | ||
498 | int cts = (status & UART_MSR_CTS); | 514 | int cts = (status & UART_MSR_CTS); |
499 | if (tty->hw_stopped) { | 515 | if (tty->hw_stopped) { |
500 | if (cts) { | 516 | if (cts) { |
@@ -509,6 +525,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) | |||
509 | } | 525 | } |
510 | } | 526 | } |
511 | } | 527 | } |
528 | tty_kref_put(tty); | ||
512 | } | 529 | } |
513 | } | 530 | } |
514 | 531 | ||
@@ -548,8 +565,10 @@ static void sdio_uart_irq(struct sdio_func *func) | |||
548 | static int sdio_uart_startup(struct sdio_uart_port *port) | 565 | static int sdio_uart_startup(struct sdio_uart_port *port) |
549 | { | 566 | { |
550 | unsigned long page; | 567 | unsigned long page; |
551 | int ret; | 568 | int ret = -ENOMEM; |
552 | struct tty_struct *tty = port->port.tty; | 569 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
570 | |||
571 | /* FIXME: What if it is NULL ?? */ | ||
553 | 572 | ||
554 | /* | 573 | /* |
555 | * Set the TTY IO error marker - we will only clear this | 574 | * Set the TTY IO error marker - we will only clear this |
@@ -560,7 +579,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) | |||
560 | /* Initialise and allocate the transmit buffer. */ | 579 | /* Initialise and allocate the transmit buffer. */ |
561 | page = __get_free_page(GFP_KERNEL); | 580 | page = __get_free_page(GFP_KERNEL); |
562 | if (!page) | 581 | if (!page) |
563 | return -ENOMEM; | 582 | goto err0; |
564 | port->xmit.buf = (unsigned char *)page; | 583 | port->xmit.buf = (unsigned char *)page; |
565 | circ_clear(&port->xmit); | 584 | circ_clear(&port->xmit); |
566 | 585 | ||
@@ -614,6 +633,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) | |||
614 | sdio_uart_irq(port->func); | 633 | sdio_uart_irq(port->func); |
615 | 634 | ||
616 | sdio_uart_release_func(port); | 635 | sdio_uart_release_func(port); |
636 | tty_kref_put(tty); | ||
617 | return 0; | 637 | return 0; |
618 | 638 | ||
619 | err3: | 639 | err3: |
@@ -622,12 +642,15 @@ err2: | |||
622 | sdio_uart_release_func(port); | 642 | sdio_uart_release_func(port); |
623 | err1: | 643 | err1: |
624 | free_page((unsigned long)port->xmit.buf); | 644 | free_page((unsigned long)port->xmit.buf); |
645 | err0: | ||
646 | tty_kref_put(tty); | ||
625 | return ret; | 647 | return ret; |
626 | } | 648 | } |
627 | 649 | ||
628 | static void sdio_uart_shutdown(struct sdio_uart_port *port) | 650 | static void sdio_uart_shutdown(struct sdio_uart_port *port) |
629 | { | 651 | { |
630 | int ret; | 652 | int ret; |
653 | struct tty_struct *tty; | ||
631 | 654 | ||
632 | ret = sdio_uart_claim_func(port); | 655 | ret = sdio_uart_claim_func(port); |
633 | if (ret) | 656 | if (ret) |
@@ -637,9 +660,11 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) | |||
637 | 660 | ||
638 | /* TODO: wait here for TX FIFO to drain */ | 661 | /* TODO: wait here for TX FIFO to drain */ |
639 | 662 | ||
663 | tty = tty_port_tty_get(&port->port); | ||
640 | /* Turn off DTR and RTS early. */ | 664 | /* Turn off DTR and RTS early. */ |
641 | if (port->port.tty->termios->c_cflag & HUPCL) | 665 | if (tty && (tty->termios->c_cflag & HUPCL)) |
642 | sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | 666 | sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
667 | tty_kref_put(tty); | ||
643 | 668 | ||
644 | /* Disable interrupts from this port */ | 669 | /* Disable interrupts from this port */ |
645 | sdio_release_irq(port->func); | 670 | sdio_release_irq(port->func); |
@@ -688,11 +713,11 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp) | |||
688 | 713 | ||
689 | if (!port->opened) { | 714 | if (!port->opened) { |
690 | tty->driver_data = port; | 715 | tty->driver_data = port; |
691 | port->port.tty = tty; | 716 | tty_port_tty_set(&port->port, tty); |
692 | ret = sdio_uart_startup(port); | 717 | ret = sdio_uart_startup(port); |
693 | if (ret) { | 718 | if (ret) { |
694 | tty->driver_data = NULL; | 719 | tty->driver_data = NULL; |
695 | port->port.tty = NULL; | 720 | tty_port_tty_set(&port->port, NULL); |
696 | mutex_unlock(&port->open_lock); | 721 | mutex_unlock(&port->open_lock); |
697 | sdio_uart_port_put(port); | 722 | sdio_uart_port_put(port); |
698 | return ret; | 723 | return ret; |
@@ -727,7 +752,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp) | |||
727 | tty->closing = 1; | 752 | tty->closing = 1; |
728 | sdio_uart_shutdown(port); | 753 | sdio_uart_shutdown(port); |
729 | tty_ldisc_flush(tty); | 754 | tty_ldisc_flush(tty); |
730 | port->port.tty = NULL; | 755 | tty_port_tty_set(&port->port, NULL); |
731 | tty->driver_data = NULL; | 756 | tty->driver_data = NULL; |
732 | tty->closing = 0; | 757 | tty->closing = 0; |
733 | } | 758 | } |