diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 18:34:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 18:34:40 -0500 |
commit | 0f4974c439dd7826c85bae4e6a8088ce2db0f498 (patch) | |
tree | fdabc7d9bb7d7bc49aad547c0aac3a633ce01f09 /drivers/mmc | |
parent | 3126c136bc30225d7a43af741778aa50e95e467a (diff) | |
parent | 36ba782e9674cdc29ec7003757df0b375e99fa96 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (58 commits)
tty: split the lock up a bit further
tty: Move the leader test in disassociate
tty: Push the bkl down a bit in the hangup code
tty: Push the lock down further into the ldisc code
tty: push the BKL down into the handlers a bit
tty: moxa: split open lock
tty: moxa: Kill the use of lock_kernel
tty: moxa: Fix modem op locking
tty: moxa: Kill off the throttle method
tty: moxa: Locking clean up
tty: moxa: rework the locking a bit
tty: moxa: Use more tty_port ops
tty: isicom: fix deadlock on shutdown
tty: mxser: Use the new locking rules to fix setserial properly
tty: mxser: use the tty_port_open method
tty: isicom: sort out the board init logic
tty: isicom: switch to the new tty_port_open helper
tty: tty_port: Add a kref object to the tty port
tty: istallion: tty port open/close methods
tty: stallion: Convert to the tty_port_open/close methods
...
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/sdio_uart.c | 303 |
1 files changed, 199 insertions, 104 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index b8e7c5ae981e..f53755533e7e 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
32 | #include <linux/sched.h> | ||
32 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
33 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
34 | #include <linux/serial_reg.h> | 35 | #include <linux/serial_reg.h> |
@@ -73,11 +74,10 @@ struct uart_icount { | |||
73 | }; | 74 | }; |
74 | 75 | ||
75 | struct sdio_uart_port { | 76 | struct sdio_uart_port { |
77 | struct tty_port port; | ||
76 | struct kref kref; | 78 | struct kref kref; |
77 | struct tty_struct *tty; | 79 | struct tty_struct *tty; |
78 | unsigned int index; | 80 | unsigned int index; |
79 | unsigned int opened; | ||
80 | struct mutex open_lock; | ||
81 | struct sdio_func *func; | 81 | struct sdio_func *func; |
82 | struct mutex func_lock; | 82 | struct mutex func_lock; |
83 | struct task_struct *in_sdio_uart_irq; | 83 | struct task_struct *in_sdio_uart_irq; |
@@ -87,6 +87,7 @@ struct sdio_uart_port { | |||
87 | struct uart_icount icount; | 87 | struct uart_icount icount; |
88 | unsigned int uartclk; | 88 | unsigned int uartclk; |
89 | unsigned int mctrl; | 89 | unsigned int mctrl; |
90 | unsigned int rx_mctrl; | ||
90 | unsigned int read_status_mask; | 91 | unsigned int read_status_mask; |
91 | unsigned int ignore_status_mask; | 92 | unsigned int ignore_status_mask; |
92 | unsigned char x_char; | 93 | unsigned char x_char; |
@@ -102,7 +103,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) | |||
102 | int index, ret = -EBUSY; | 103 | int index, ret = -EBUSY; |
103 | 104 | ||
104 | kref_init(&port->kref); | 105 | kref_init(&port->kref); |
105 | mutex_init(&port->open_lock); | ||
106 | mutex_init(&port->func_lock); | 106 | mutex_init(&port->func_lock); |
107 | spin_lock_init(&port->write_lock); | 107 | spin_lock_init(&port->write_lock); |
108 | 108 | ||
@@ -151,6 +151,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port) | |||
151 | static void sdio_uart_port_remove(struct sdio_uart_port *port) | 151 | static void sdio_uart_port_remove(struct sdio_uart_port *port) |
152 | { | 152 | { |
153 | struct sdio_func *func; | 153 | struct sdio_func *func; |
154 | struct tty_struct *tty; | ||
154 | 155 | ||
155 | BUG_ON(sdio_uart_table[port->index] != port); | 156 | BUG_ON(sdio_uart_table[port->index] != port); |
156 | 157 | ||
@@ -165,15 +166,19 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) | |||
165 | * give up on that port ASAP. | 166 | * give up on that port ASAP. |
166 | * Beware: the lock ordering is critical. | 167 | * Beware: the lock ordering is critical. |
167 | */ | 168 | */ |
168 | mutex_lock(&port->open_lock); | 169 | mutex_lock(&port->port.mutex); |
169 | mutex_lock(&port->func_lock); | 170 | mutex_lock(&port->func_lock); |
170 | func = port->func; | 171 | func = port->func; |
171 | sdio_claim_host(func); | 172 | sdio_claim_host(func); |
172 | port->func = NULL; | 173 | port->func = NULL; |
173 | mutex_unlock(&port->func_lock); | 174 | mutex_unlock(&port->func_lock); |
174 | if (port->opened) | 175 | tty = tty_port_tty_get(&port->port); |
175 | tty_hangup(port->tty); | 176 | /* tty_hangup is async so is this safe as is ?? */ |
176 | mutex_unlock(&port->open_lock); | 177 | if (tty) { |
178 | tty_hangup(tty); | ||
179 | tty_kref_put(tty); | ||
180 | } | ||
181 | mutex_unlock(&port->port.mutex); | ||
177 | sdio_release_irq(func); | 182 | sdio_release_irq(func); |
178 | sdio_disable_func(func); | 183 | sdio_disable_func(func); |
179 | sdio_release_host(func); | 184 | sdio_release_host(func); |
@@ -217,6 +222,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) | |||
217 | unsigned char status; | 222 | unsigned char status; |
218 | unsigned int ret; | 223 | unsigned int ret; |
219 | 224 | ||
225 | /* FIXME: What stops this losing the delta bits and breaking | ||
226 | sdio_uart_check_modem_status ? */ | ||
220 | status = sdio_in(port, UART_MSR); | 227 | status = sdio_in(port, UART_MSR); |
221 | 228 | ||
222 | ret = 0; | 229 | ret = 0; |
@@ -391,7 +398,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) | |||
391 | static void sdio_uart_receive_chars(struct sdio_uart_port *port, | 398 | static void sdio_uart_receive_chars(struct sdio_uart_port *port, |
392 | unsigned int *status) | 399 | unsigned int *status) |
393 | { | 400 | { |
394 | struct tty_struct *tty = port->tty; | 401 | struct tty_struct *tty = tty_port_tty_get(&port->port); |
395 | unsigned int ch, flag; | 402 | unsigned int ch, flag; |
396 | int max_count = 256; | 403 | int max_count = 256; |
397 | 404 | ||
@@ -428,24 +435,30 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, | |||
428 | } | 435 | } |
429 | 436 | ||
430 | if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) | 437 | if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) |
431 | tty_insert_flip_char(tty, ch, flag); | 438 | if (tty) |
439 | tty_insert_flip_char(tty, ch, flag); | ||
432 | 440 | ||
433 | /* | 441 | /* |
434 | * Overrun is special. Since it's reported immediately, | 442 | * Overrun is special. Since it's reported immediately, |
435 | * it doesn't affect the current character. | 443 | * it doesn't affect the current character. |
436 | */ | 444 | */ |
437 | if (*status & ~port->ignore_status_mask & UART_LSR_OE) | 445 | if (*status & ~port->ignore_status_mask & UART_LSR_OE) |
438 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | 446 | if (tty) |
447 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
439 | 448 | ||
440 | *status = sdio_in(port, UART_LSR); | 449 | *status = sdio_in(port, UART_LSR); |
441 | } while ((*status & UART_LSR_DR) && (max_count-- > 0)); | 450 | } while ((*status & UART_LSR_DR) && (max_count-- > 0)); |
442 | tty_flip_buffer_push(tty); | 451 | if (tty) { |
452 | tty_flip_buffer_push(tty); | ||
453 | tty_kref_put(tty); | ||
454 | } | ||
443 | } | 455 | } |
444 | 456 | ||
445 | static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | 457 | static void sdio_uart_transmit_chars(struct sdio_uart_port *port) |
446 | { | 458 | { |
447 | struct circ_buf *xmit = &port->xmit; | 459 | struct circ_buf *xmit = &port->xmit; |
448 | int count; | 460 | int count; |
461 | struct tty_struct *tty; | ||
449 | 462 | ||
450 | if (port->x_char) { | 463 | if (port->x_char) { |
451 | sdio_out(port, UART_TX, port->x_char); | 464 | sdio_out(port, UART_TX, port->x_char); |
@@ -453,8 +466,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | |||
453 | port->x_char = 0; | 466 | port->x_char = 0; |
454 | return; | 467 | return; |
455 | } | 468 | } |
456 | if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) { | 469 | |
470 | tty = tty_port_tty_get(&port->port); | ||
471 | |||
472 | if (tty == NULL || circ_empty(xmit) || | ||
473 | tty->stopped || tty->hw_stopped) { | ||
457 | sdio_uart_stop_tx(port); | 474 | sdio_uart_stop_tx(port); |
475 | tty_kref_put(tty); | ||
458 | return; | 476 | return; |
459 | } | 477 | } |
460 | 478 | ||
@@ -468,15 +486,17 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) | |||
468 | } while (--count > 0); | 486 | } while (--count > 0); |
469 | 487 | ||
470 | if (circ_chars_pending(xmit) < WAKEUP_CHARS) | 488 | if (circ_chars_pending(xmit) < WAKEUP_CHARS) |
471 | tty_wakeup(port->tty); | 489 | tty_wakeup(tty); |
472 | 490 | ||
473 | if (circ_empty(xmit)) | 491 | if (circ_empty(xmit)) |
474 | sdio_uart_stop_tx(port); | 492 | sdio_uart_stop_tx(port); |
493 | tty_kref_put(tty); | ||
475 | } | 494 | } |
476 | 495 | ||
477 | static void sdio_uart_check_modem_status(struct sdio_uart_port *port) | 496 | static void sdio_uart_check_modem_status(struct sdio_uart_port *port) |
478 | { | 497 | { |
479 | int status; | 498 | int status; |
499 | struct tty_struct *tty; | ||
480 | 500 | ||
481 | status = sdio_in(port, UART_MSR); | 501 | status = sdio_in(port, UART_MSR); |
482 | 502 | ||
@@ -487,25 +507,39 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) | |||
487 | port->icount.rng++; | 507 | port->icount.rng++; |
488 | if (status & UART_MSR_DDSR) | 508 | if (status & UART_MSR_DDSR) |
489 | port->icount.dsr++; | 509 | port->icount.dsr++; |
490 | if (status & UART_MSR_DDCD) | 510 | if (status & UART_MSR_DDCD) { |
491 | port->icount.dcd++; | 511 | port->icount.dcd++; |
512 | /* DCD raise - wake for open */ | ||
513 | if (status & UART_MSR_DCD) | ||
514 | wake_up_interruptible(&port->port.open_wait); | ||
515 | else { | ||
516 | /* DCD drop - hang up if tty attached */ | ||
517 | tty = tty_port_tty_get(&port->port); | ||
518 | if (tty) { | ||
519 | tty_hangup(tty); | ||
520 | tty_kref_put(tty); | ||
521 | } | ||
522 | } | ||
523 | } | ||
492 | if (status & UART_MSR_DCTS) { | 524 | if (status & UART_MSR_DCTS) { |
493 | port->icount.cts++; | 525 | port->icount.cts++; |
494 | if (port->tty->termios->c_cflag & CRTSCTS) { | 526 | tty = tty_port_tty_get(&port->port); |
527 | if (tty && (tty->termios->c_cflag & CRTSCTS)) { | ||
495 | int cts = (status & UART_MSR_CTS); | 528 | int cts = (status & UART_MSR_CTS); |
496 | if (port->tty->hw_stopped) { | 529 | if (tty->hw_stopped) { |
497 | if (cts) { | 530 | if (cts) { |
498 | port->tty->hw_stopped = 0; | 531 | tty->hw_stopped = 0; |
499 | sdio_uart_start_tx(port); | 532 | sdio_uart_start_tx(port); |
500 | tty_wakeup(port->tty); | 533 | tty_wakeup(tty); |
501 | } | 534 | } |
502 | } else { | 535 | } else { |
503 | if (!cts) { | 536 | if (!cts) { |
504 | port->tty->hw_stopped = 1; | 537 | tty->hw_stopped = 1; |
505 | sdio_uart_stop_tx(port); | 538 | sdio_uart_stop_tx(port); |
506 | } | 539 | } |
507 | } | 540 | } |
508 | } | 541 | } |
542 | tty_kref_put(tty); | ||
509 | } | 543 | } |
510 | } | 544 | } |
511 | 545 | ||
@@ -542,8 +576,62 @@ static void sdio_uart_irq(struct sdio_func *func) | |||
542 | port->in_sdio_uart_irq = NULL; | 576 | port->in_sdio_uart_irq = NULL; |
543 | } | 577 | } |
544 | 578 | ||
545 | static int sdio_uart_startup(struct sdio_uart_port *port) | 579 | static int uart_carrier_raised(struct tty_port *tport) |
580 | { | ||
581 | struct sdio_uart_port *port = | ||
582 | container_of(tport, struct sdio_uart_port, port); | ||
583 | unsigned int ret = sdio_uart_claim_func(port); | ||
584 | if (ret) /* Missing hardware shoudn't block for carrier */ | ||
585 | return 1; | ||
586 | ret = sdio_uart_get_mctrl(port); | ||
587 | sdio_uart_release_func(port); | ||
588 | if (ret & TIOCM_CAR) | ||
589 | return 1; | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | /** | ||
594 | * uart_dtr_rts - port helper to set uart signals | ||
595 | * @tport: tty port to be updated | ||
596 | * @onoff: set to turn on DTR/RTS | ||
597 | * | ||
598 | * Called by the tty port helpers when the modem signals need to be | ||
599 | * adjusted during an open, close and hangup. | ||
600 | */ | ||
601 | |||
602 | static void uart_dtr_rts(struct tty_port *tport, int onoff) | ||
603 | { | ||
604 | struct sdio_uart_port *port = | ||
605 | container_of(tport, struct sdio_uart_port, port); | ||
606 | int ret = sdio_uart_claim_func(port); | ||
607 | if (ret) | ||
608 | return; | ||
609 | if (onoff == 0) | ||
610 | sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
611 | else | ||
612 | sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
613 | sdio_uart_release_func(port); | ||
614 | } | ||
615 | |||
616 | /** | ||
617 | * sdio_uart_activate - start up hardware | ||
618 | * @tport: tty port to activate | ||
619 | * @tty: tty bound to this port | ||
620 | * | ||
621 | * Activate a tty port. The port locking guarantees us this will be | ||
622 | * run exactly once per set of opens, and if successful will see the | ||
623 | * shutdown method run exactly once to match. Start up and shutdown are | ||
624 | * protected from each other by the internal locking and will not run | ||
625 | * at the same time even during a hangup event. | ||
626 | * | ||
627 | * If we successfully start up the port we take an extra kref as we | ||
628 | * will keep it around until shutdown when the kref is dropped. | ||
629 | */ | ||
630 | |||
631 | static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) | ||
546 | { | 632 | { |
633 | struct sdio_uart_port *port = | ||
634 | container_of(tport, struct sdio_uart_port, port); | ||
547 | unsigned long page; | 635 | unsigned long page; |
548 | int ret; | 636 | int ret; |
549 | 637 | ||
@@ -551,7 +639,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) | |||
551 | * Set the TTY IO error marker - we will only clear this | 639 | * Set the TTY IO error marker - we will only clear this |
552 | * once we have successfully opened the port. | 640 | * once we have successfully opened the port. |
553 | */ | 641 | */ |
554 | set_bit(TTY_IO_ERROR, &port->tty->flags); | 642 | set_bit(TTY_IO_ERROR, &tty->flags); |
555 | 643 | ||
556 | /* Initialise and allocate the transmit buffer. */ | 644 | /* Initialise and allocate the transmit buffer. */ |
557 | page = __get_free_page(GFP_KERNEL); | 645 | page = __get_free_page(GFP_KERNEL); |
@@ -592,19 +680,19 @@ static int sdio_uart_startup(struct sdio_uart_port *port) | |||
592 | */ | 680 | */ |
593 | sdio_out(port, UART_LCR, UART_LCR_WLEN8); | 681 | sdio_out(port, UART_LCR, UART_LCR_WLEN8); |
594 | 682 | ||
595 | port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; | 683 | port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; |
596 | port->mctrl = TIOCM_OUT2; | 684 | port->mctrl = TIOCM_OUT2; |
597 | 685 | ||
598 | sdio_uart_change_speed(port, port->tty->termios, NULL); | 686 | sdio_uart_change_speed(port, tty->termios, NULL); |
599 | 687 | ||
600 | if (port->tty->termios->c_cflag & CBAUD) | 688 | if (tty->termios->c_cflag & CBAUD) |
601 | sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); | 689 | sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); |
602 | 690 | ||
603 | if (port->tty->termios->c_cflag & CRTSCTS) | 691 | if (tty->termios->c_cflag & CRTSCTS) |
604 | if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) | 692 | if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) |
605 | port->tty->hw_stopped = 1; | 693 | tty->hw_stopped = 1; |
606 | 694 | ||
607 | clear_bit(TTY_IO_ERROR, &port->tty->flags); | 695 | clear_bit(TTY_IO_ERROR, &tty->flags); |
608 | 696 | ||
609 | /* Kick the IRQ handler once while we're still holding the host lock */ | 697 | /* Kick the IRQ handler once while we're still holding the host lock */ |
610 | sdio_uart_irq(port->func); | 698 | sdio_uart_irq(port->func); |
@@ -621,8 +709,20 @@ err1: | |||
621 | return ret; | 709 | return ret; |
622 | } | 710 | } |
623 | 711 | ||
624 | static void sdio_uart_shutdown(struct sdio_uart_port *port) | 712 | /** |
713 | * sdio_uart_shutdown - stop hardware | ||
714 | * @tport: tty port to shut down | ||
715 | * | ||
716 | * Deactivate a tty port. The port locking guarantees us this will be | ||
717 | * run only if a successful matching activate already ran. The two are | ||
718 | * protected from each other by the internal locking and will not run | ||
719 | * at the same time even during a hangup event. | ||
720 | */ | ||
721 | |||
722 | static void sdio_uart_shutdown(struct tty_port *tport) | ||
625 | { | 723 | { |
724 | struct sdio_uart_port *port = | ||
725 | container_of(tport, struct sdio_uart_port, port); | ||
626 | int ret; | 726 | int ret; |
627 | 727 | ||
628 | ret = sdio_uart_claim_func(port); | 728 | ret = sdio_uart_claim_func(port); |
@@ -631,12 +731,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) | |||
631 | 731 | ||
632 | sdio_uart_stop_rx(port); | 732 | sdio_uart_stop_rx(port); |
633 | 733 | ||
634 | /* TODO: wait here for TX FIFO to drain */ | ||
635 | |||
636 | /* Turn off DTR and RTS early. */ | ||
637 | if (port->tty->termios->c_cflag & HUPCL) | ||
638 | sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); | ||
639 | |||
640 | /* Disable interrupts from this port */ | 734 | /* Disable interrupts from this port */ |
641 | sdio_release_irq(port->func); | 735 | sdio_release_irq(port->func); |
642 | port->ier = 0; | 736 | port->ier = 0; |
@@ -661,77 +755,70 @@ skip: | |||
661 | free_page((unsigned long)port->xmit.buf); | 755 | free_page((unsigned long)port->xmit.buf); |
662 | } | 756 | } |
663 | 757 | ||
664 | static int sdio_uart_open(struct tty_struct *tty, struct file *filp) | 758 | /** |
759 | * sdio_uart_install - install method | ||
760 | * @driver: the driver in use (sdio_uart in our case) | ||
761 | * @tty: the tty being bound | ||
762 | * | ||
763 | * Look up and bind the tty and the driver together. Initialize | ||
764 | * any needed private data (in our case the termios) | ||
765 | */ | ||
766 | |||
767 | static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) | ||
665 | { | 768 | { |
666 | struct sdio_uart_port *port; | 769 | int idx = tty->index; |
667 | int ret; | 770 | struct sdio_uart_port *port = sdio_uart_port_get(idx); |
771 | int ret = tty_init_termios(tty); | ||
772 | |||
773 | if (ret == 0) { | ||
774 | tty_driver_kref_get(driver); | ||
775 | tty->count++; | ||
776 | /* This is the ref sdio_uart_port get provided */ | ||
777 | tty->driver_data = port; | ||
778 | driver->ttys[idx] = tty; | ||
779 | } else | ||
780 | sdio_uart_port_put(port); | ||
781 | return ret; | ||
782 | } | ||
668 | 783 | ||
669 | port = sdio_uart_port_get(tty->index); | 784 | /** |
670 | if (!port) | 785 | * sdio_uart_cleanup - called on the last tty kref drop |
671 | return -ENODEV; | 786 | * @tty: the tty being destroyed |
787 | * | ||
788 | * Called asynchronously when the last reference to the tty is dropped. | ||
789 | * We cannot destroy the tty->driver_data port kref until this point | ||
790 | */ | ||
672 | 791 | ||
673 | mutex_lock(&port->open_lock); | 792 | static void sdio_uart_cleanup(struct tty_struct *tty) |
793 | { | ||
794 | struct sdio_uart_port *port = tty->driver_data; | ||
795 | tty->driver_data = NULL; /* Bug trap */ | ||
796 | sdio_uart_port_put(port); | ||
797 | } | ||
674 | 798 | ||
675 | /* | 799 | /* |
676 | * Make sure not to mess up with a dead port | 800 | * Open/close/hangup is now entirely boilerplate |
677 | * which has not been closed yet. | 801 | */ |
678 | */ | ||
679 | if (tty->driver_data && tty->driver_data != port) { | ||
680 | mutex_unlock(&port->open_lock); | ||
681 | sdio_uart_port_put(port); | ||
682 | return -EBUSY; | ||
683 | } | ||
684 | 802 | ||
685 | if (!port->opened) { | 803 | static int sdio_uart_open(struct tty_struct *tty, struct file *filp) |
686 | tty->driver_data = port; | 804 | { |
687 | port->tty = tty; | 805 | struct sdio_uart_port *port = tty->driver_data; |
688 | ret = sdio_uart_startup(port); | 806 | return tty_port_open(&port->port, tty, filp); |
689 | if (ret) { | ||
690 | tty->driver_data = NULL; | ||
691 | port->tty = NULL; | ||
692 | mutex_unlock(&port->open_lock); | ||
693 | sdio_uart_port_put(port); | ||
694 | return ret; | ||
695 | } | ||
696 | } | ||
697 | port->opened++; | ||
698 | mutex_unlock(&port->open_lock); | ||
699 | return 0; | ||
700 | } | 807 | } |
701 | 808 | ||
702 | static void sdio_uart_close(struct tty_struct *tty, struct file * filp) | 809 | static void sdio_uart_close(struct tty_struct *tty, struct file * filp) |
703 | { | 810 | { |
704 | struct sdio_uart_port *port = tty->driver_data; | 811 | struct sdio_uart_port *port = tty->driver_data; |
812 | tty_port_close(&port->port, tty, filp); | ||
813 | } | ||
705 | 814 | ||
706 | if (!port) | 815 | static void sdio_uart_hangup(struct tty_struct *tty) |
707 | return; | 816 | { |
708 | 817 | struct sdio_uart_port *port = tty->driver_data; | |
709 | mutex_lock(&port->open_lock); | 818 | tty_port_hangup(&port->port); |
710 | BUG_ON(!port->opened); | ||
711 | |||
712 | /* | ||
713 | * This is messy. The tty layer calls us even when open() | ||
714 | * returned an error. Ignore this close request if tty->count | ||
715 | * is larger than port->count. | ||
716 | */ | ||
717 | if (tty->count > port->opened) { | ||
718 | mutex_unlock(&port->open_lock); | ||
719 | return; | ||
720 | } | ||
721 | |||
722 | if (--port->opened == 0) { | ||
723 | tty->closing = 1; | ||
724 | sdio_uart_shutdown(port); | ||
725 | tty_ldisc_flush(tty); | ||
726 | port->tty = NULL; | ||
727 | tty->driver_data = NULL; | ||
728 | tty->closing = 0; | ||
729 | } | ||
730 | mutex_unlock(&port->open_lock); | ||
731 | sdio_uart_port_put(port); | ||
732 | } | 819 | } |
733 | 820 | ||
734 | static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, | 821 | static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, |
735 | int count) | 822 | int count) |
736 | { | 823 | { |
737 | struct sdio_uart_port *port = tty->driver_data; | 824 | struct sdio_uart_port *port = tty->driver_data; |
@@ -756,7 +843,7 @@ static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, | |||
756 | } | 843 | } |
757 | spin_unlock(&port->write_lock); | 844 | spin_unlock(&port->write_lock); |
758 | 845 | ||
759 | if ( !(port->ier & UART_IER_THRI)) { | 846 | if (!(port->ier & UART_IER_THRI)) { |
760 | int err = sdio_uart_claim_func(port); | 847 | int err = sdio_uart_claim_func(port); |
761 | if (!err) { | 848 | if (!err) { |
762 | sdio_uart_start_tx(port); | 849 | sdio_uart_start_tx(port); |
@@ -843,17 +930,12 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) | |||
843 | sdio_uart_release_func(port); | 930 | sdio_uart_release_func(port); |
844 | } | 931 | } |
845 | 932 | ||
846 | static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | 933 | static void sdio_uart_set_termios(struct tty_struct *tty, |
934 | struct ktermios *old_termios) | ||
847 | { | 935 | { |
848 | struct sdio_uart_port *port = tty->driver_data; | 936 | struct sdio_uart_port *port = tty->driver_data; |
849 | unsigned int cflag = tty->termios->c_cflag; | 937 | unsigned int cflag = tty->termios->c_cflag; |
850 | 938 | ||
851 | #define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) | ||
852 | |||
853 | if ((cflag ^ old_termios->c_cflag) == 0 && | ||
854 | RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) | ||
855 | return; | ||
856 | |||
857 | if (sdio_uart_claim_func(port) != 0) | 939 | if (sdio_uart_claim_func(port) != 0) |
858 | return; | 940 | return; |
859 | 941 | ||
@@ -928,7 +1010,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, | |||
928 | int result; | 1010 | int result; |
929 | 1011 | ||
930 | result = sdio_uart_claim_func(port); | 1012 | result = sdio_uart_claim_func(port); |
931 | if(!result) { | 1013 | if (!result) { |
932 | sdio_uart_update_mctrl(port, set, clear); | 1014 | sdio_uart_update_mctrl(port, set, clear); |
933 | sdio_uart_release_func(port); | 1015 | sdio_uart_release_func(port); |
934 | } | 1016 | } |
@@ -946,7 +1028,7 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v) | |||
946 | struct sdio_uart_port *port = sdio_uart_port_get(i); | 1028 | struct sdio_uart_port *port = sdio_uart_port_get(i); |
947 | if (port) { | 1029 | if (port) { |
948 | seq_printf(m, "%d: uart:SDIO", i); | 1030 | seq_printf(m, "%d: uart:SDIO", i); |
949 | if(capable(CAP_SYS_ADMIN)) { | 1031 | if (capable(CAP_SYS_ADMIN)) { |
950 | seq_printf(m, " tx:%d rx:%d", | 1032 | seq_printf(m, " tx:%d rx:%d", |
951 | port->icount.tx, port->icount.rx); | 1033 | port->icount.tx, port->icount.rx); |
952 | if (port->icount.frame) | 1034 | if (port->icount.frame) |
@@ -994,6 +1076,13 @@ static const struct file_operations sdio_uart_proc_fops = { | |||
994 | .release = single_release, | 1076 | .release = single_release, |
995 | }; | 1077 | }; |
996 | 1078 | ||
1079 | static const struct tty_port_operations sdio_uart_port_ops = { | ||
1080 | .dtr_rts = uart_dtr_rts, | ||
1081 | .carrier_raised = uart_carrier_raised, | ||
1082 | .shutdown = sdio_uart_shutdown, | ||
1083 | .activate = sdio_uart_activate, | ||
1084 | }; | ||
1085 | |||
997 | static const struct tty_operations sdio_uart_ops = { | 1086 | static const struct tty_operations sdio_uart_ops = { |
998 | .open = sdio_uart_open, | 1087 | .open = sdio_uart_open, |
999 | .close = sdio_uart_close, | 1088 | .close = sdio_uart_close, |
@@ -1004,9 +1093,12 @@ static const struct tty_operations sdio_uart_ops = { | |||
1004 | .throttle = sdio_uart_throttle, | 1093 | .throttle = sdio_uart_throttle, |
1005 | .unthrottle = sdio_uart_unthrottle, | 1094 | .unthrottle = sdio_uart_unthrottle, |
1006 | .set_termios = sdio_uart_set_termios, | 1095 | .set_termios = sdio_uart_set_termios, |
1096 | .hangup = sdio_uart_hangup, | ||
1007 | .break_ctl = sdio_uart_break_ctl, | 1097 | .break_ctl = sdio_uart_break_ctl, |
1008 | .tiocmget = sdio_uart_tiocmget, | 1098 | .tiocmget = sdio_uart_tiocmget, |
1009 | .tiocmset = sdio_uart_tiocmset, | 1099 | .tiocmset = sdio_uart_tiocmset, |
1100 | .install = sdio_uart_install, | ||
1101 | .cleanup = sdio_uart_cleanup, | ||
1010 | .proc_fops = &sdio_uart_proc_fops, | 1102 | .proc_fops = &sdio_uart_proc_fops, |
1011 | }; | 1103 | }; |
1012 | 1104 | ||
@@ -1043,7 +1135,7 @@ static int sdio_uart_probe(struct sdio_func *func, | |||
1043 | } | 1135 | } |
1044 | if (!tpl) { | 1136 | if (!tpl) { |
1045 | printk(KERN_WARNING | 1137 | printk(KERN_WARNING |
1046 | "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", | 1138 | "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", |
1047 | sdio_func_id(func)); | 1139 | sdio_func_id(func)); |
1048 | kfree(port); | 1140 | kfree(port); |
1049 | return -EINVAL; | 1141 | return -EINVAL; |
@@ -1068,13 +1160,16 @@ static int sdio_uart_probe(struct sdio_func *func, | |||
1068 | 1160 | ||
1069 | port->func = func; | 1161 | port->func = func; |
1070 | sdio_set_drvdata(func, port); | 1162 | sdio_set_drvdata(func, port); |
1163 | tty_port_init(&port->port); | ||
1164 | port->port.ops = &sdio_uart_port_ops; | ||
1071 | 1165 | ||
1072 | ret = sdio_uart_add_port(port); | 1166 | ret = sdio_uart_add_port(port); |
1073 | if (ret) { | 1167 | if (ret) { |
1074 | kfree(port); | 1168 | kfree(port); |
1075 | } else { | 1169 | } else { |
1076 | struct device *dev; | 1170 | struct device *dev; |
1077 | dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev); | 1171 | dev = tty_register_device(sdio_uart_tty_driver, |
1172 | port->index, &func->dev); | ||
1078 | if (IS_ERR(dev)) { | 1173 | if (IS_ERR(dev)) { |
1079 | sdio_uart_port_remove(port); | 1174 | sdio_uart_port_remove(port); |
1080 | ret = PTR_ERR(dev); | 1175 | ret = PTR_ERR(dev); |