aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-11-30 08:16:09 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 18:18:05 -0500
commit584abc3775e76c1a2abe725355915851ed23ed6c (patch)
tree5808522d561d6529d5b9de2a14f8157d4c033405
parent0a68f64febf365313987c570ad59c9069f61306d (diff)
tty: sdio_uart: Switch to the open/close helpers
Gets us proper tty semantics, removes some code and fixes up a few corner case races (hangup during open etc) 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.c201
1 files changed, 119 insertions, 82 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 31f70233133d..95027b03c646 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -77,7 +77,6 @@ struct sdio_uart_port {
77 struct kref kref; 77 struct kref kref;
78 struct tty_struct *tty; 78 struct tty_struct *tty;
79 unsigned int index; 79 unsigned int index;
80 unsigned int opened;
81 struct sdio_func *func; 80 struct sdio_func *func;
82 struct mutex func_lock; 81 struct mutex func_lock;
83 struct task_struct *in_sdio_uart_irq; 82 struct task_struct *in_sdio_uart_irq;
@@ -150,6 +149,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
150static void sdio_uart_port_remove(struct sdio_uart_port *port) 149static void sdio_uart_port_remove(struct sdio_uart_port *port)
151{ 150{
152 struct sdio_func *func; 151 struct sdio_func *func;
152 struct tty_struct *tty;
153 153
154 BUG_ON(sdio_uart_table[port->index] != port); 154 BUG_ON(sdio_uart_table[port->index] != port);
155 155
@@ -170,11 +170,10 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
170 sdio_claim_host(func); 170 sdio_claim_host(func);
171 port->func = NULL; 171 port->func = NULL;
172 mutex_unlock(&port->func_lock); 172 mutex_unlock(&port->func_lock);
173 if (port->opened) { 173 tty = tty_port_tty_get(&port->port);
174 struct tty_struct *tty = tty_port_tty_get(&port->port); 174 /* tty_hangup is async so is this safe as is ?? */
175 /* tty_hangup is async so is this safe as is ?? */ 175 if (tty) {
176 if (tty) 176 tty_hangup(tty);
177 tty_hangup(tty);
178 tty_kref_put(tty); 177 tty_kref_put(tty);
179 } 178 }
180 mutex_unlock(&port->port.mutex); 179 mutex_unlock(&port->port.mutex);
@@ -560,13 +559,46 @@ static void sdio_uart_irq(struct sdio_func *func)
560 port->in_sdio_uart_irq = NULL; 559 port->in_sdio_uart_irq = NULL;
561} 560}
562 561
563static int sdio_uart_startup(struct sdio_uart_port *port) 562/**
563 * uart_dtr_rts - port helper to set uart signals
564 * @tport: tty port to be updated
565 * @onoff: set to turn on DTR/RTS
566 *
567 * Called by the tty port helpers when the modem signals need to be
568 * adjusted during an open, close and hangup.
569 */
570
571static void uart_dtr_rts(struct tty_port *tport, int onoff)
564{ 572{
565 unsigned long page; 573 struct sdio_uart_port *port =
566 int ret = -ENOMEM; 574 container_of(tport, struct sdio_uart_port, port);
567 struct tty_struct *tty = tty_port_tty_get(&port->port); 575 if (onoff == 0)
576 sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
577 else
578 sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
579}
568 580
569 /* FIXME: What if it is NULL ?? */ 581/**
582 * sdio_uart_activate - start up hardware
583 * @tport: tty port to activate
584 * @tty: tty bound to this port
585 *
586 * Activate a tty port. The port locking guarantees us this will be
587 * run exactly once per set of opens, and if successful will see the
588 * shutdown method run exactly once to match. Start up and shutdown are
589 * protected from each other by the internal locking and will not run
590 * at the same time even during a hangup event.
591 *
592 * If we successfully start up the port we take an extra kref as we
593 * will keep it around until shutdown when the kref is dropped.
594 */
595
596static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
597{
598 struct sdio_uart_port *port =
599 container_of(tport, struct sdio_uart_port, port);
600 unsigned long page;
601 int ret;
570 602
571 /* 603 /*
572 * Set the TTY IO error marker - we will only clear this 604 * Set the TTY IO error marker - we will only clear this
@@ -577,7 +609,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
577 /* Initialise and allocate the transmit buffer. */ 609 /* Initialise and allocate the transmit buffer. */
578 page = __get_free_page(GFP_KERNEL); 610 page = __get_free_page(GFP_KERNEL);
579 if (!page) 611 if (!page)
580 goto err0; 612 return -ENOMEM;
581 port->xmit.buf = (unsigned char *)page; 613 port->xmit.buf = (unsigned char *)page;
582 circ_clear(&port->xmit); 614 circ_clear(&port->xmit);
583 615
@@ -631,7 +663,6 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
631 sdio_uart_irq(port->func); 663 sdio_uart_irq(port->func);
632 664
633 sdio_uart_release_func(port); 665 sdio_uart_release_func(port);
634 tty_kref_put(tty);
635 return 0; 666 return 0;
636 667
637err3: 668err3:
@@ -640,15 +671,25 @@ err2:
640 sdio_uart_release_func(port); 671 sdio_uart_release_func(port);
641err1: 672err1:
642 free_page((unsigned long)port->xmit.buf); 673 free_page((unsigned long)port->xmit.buf);
643err0:
644 tty_kref_put(tty);
645 return ret; 674 return ret;
646} 675}
647 676
648static void sdio_uart_shutdown(struct sdio_uart_port *port) 677
678/**
679 * sdio_uart_shutdown - stop hardware
680 * @tport: tty port to shut down
681 *
682 * Deactivate a tty port. The port locking guarantees us this will be
683 * run only if a successful matching activate already ran. The two are
684 * protected from each other by the internal locking and will not run
685 * at the same time even during a hangup event.
686 */
687
688static void sdio_uart_shutdown(struct tty_port *tport)
649{ 689{
690 struct sdio_uart_port *port =
691 container_of(tport, struct sdio_uart_port, port);
650 int ret; 692 int ret;
651 struct tty_struct *tty;
652 693
653 ret = sdio_uart_claim_func(port); 694 ret = sdio_uart_claim_func(port);
654 if (ret) 695 if (ret)
@@ -656,14 +697,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
656 697
657 sdio_uart_stop_rx(port); 698 sdio_uart_stop_rx(port);
658 699
659 /* TODO: wait here for TX FIFO to drain */
660
661 tty = tty_port_tty_get(&port->port);
662 /* Turn off DTR and RTS early. */
663 if (tty && (tty->termios->c_cflag & HUPCL))
664 sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
665 tty_kref_put(tty);
666
667 /* Disable interrupts from this port */ 700 /* Disable interrupts from this port */
668 sdio_release_irq(port->func); 701 sdio_release_irq(port->func);
669 port->ier = 0; 702 port->ier = 0;
@@ -688,74 +721,68 @@ skip:
688 free_page((unsigned long)port->xmit.buf); 721 free_page((unsigned long)port->xmit.buf);
689} 722}
690 723
691static int sdio_uart_open(struct tty_struct *tty, struct file *filp) 724/**
692{ 725 * sdio_uart_install - install method
693 struct sdio_uart_port *port; 726 * @driver: the driver in use (sdio_uart in our case)
694 int ret; 727 * @tty: the tty being bound
695 728 *
696 port = sdio_uart_port_get(tty->index); 729 * Look up and bind the tty and the driver together. Initialize
697 if (!port) 730 * any needed private data (in our case the termios)
698 return -ENODEV; 731 */
699
700 mutex_lock(&port->port.mutex);
701 732
702 /* 733static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
703 * Make sure not to mess up with a dead port 734{
704 * which has not been closed yet. 735 int idx = tty->index;
705 */ 736 struct sdio_uart_port *port = sdio_uart_port_get(idx);
706 if (tty->driver_data && tty->driver_data != port) { 737 int ret = tty_init_termios(tty);
707 mutex_unlock(&port->port.mutex); 738
739 if (ret == 0) {
740 tty_driver_kref_get(driver);
741 tty->count++;
742 /* This is the ref sdio_uart_port get provided */
743 tty->driver_data = port;
744 driver->ttys[idx] = tty;
745 } else
708 sdio_uart_port_put(port); 746 sdio_uart_port_put(port);
709 return -EBUSY; 747 return ret;
710 }
711 748
712 if (!port->opened) {
713 tty->driver_data = port;
714 tty_port_tty_set(&port->port, tty);
715 ret = sdio_uart_startup(port);
716 if (ret) {
717 tty->driver_data = NULL;
718 tty_port_tty_set(&port->port, NULL);
719 mutex_unlock(&port->port.mutex);
720 sdio_uart_port_put(port);
721 return ret;
722 }
723 }
724 port->opened++;
725 mutex_unlock(&port->port.mutex);
726 return 0;
727} 749}
728 750
729static void sdio_uart_close(struct tty_struct *tty, struct file * filp) 751/**
752 * sdio_uart_cleanup - called on the last tty kref drop
753 * @tty: the tty being destroyed
754 *
755 * Called asynchronously when the last reference to the tty is dropped.
756 * We cannot destroy the tty->driver_data port kref until this point
757 */
758
759static void sdio_uart_cleanup(struct tty_struct *tty)
730{ 760{
731 struct sdio_uart_port *port = tty->driver_data; 761 struct sdio_uart_port *port = tty->driver_data;
762 tty->driver_data = NULL; /* Bug trap */
763 sdio_uart_port_put(port);
764}
732 765
733 if (!port) 766/*
734 return; 767 * Open/close/hangup is now entirely boilerplate
768 */
735 769
736 mutex_lock(&port->port.mutex); 770static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
737 BUG_ON(!port->opened); 771{
772 struct sdio_uart_port *port = tty->driver_data;
773 return tty_port_open(&port->port, tty, filp);
774}
738 775
739 /* 776static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
740 * This is messy. The tty layer calls us even when open() 777{
741 * returned an error. Ignore this close request if tty->count 778 struct sdio_uart_port *port = tty->driver_data;
742 * is larger than port->count. 779 tty_port_close(&port->port, tty, filp);
743 */ 780}
744 if (tty->count > port->opened) {
745 mutex_unlock(&port->port.mutex);
746 return;
747 }
748 781
749 if (--port->opened == 0) { 782static void sdio_uart_hangup(struct tty_struct *tty)
750 tty->closing = 1; 783{
751 sdio_uart_shutdown(port); 784 struct sdio_uart_port *port = tty->driver_data;
752 tty_ldisc_flush(tty); 785 tty_port_hangup(&port->port);
753 tty_port_tty_set(&port->port, NULL);
754 tty->driver_data = NULL;
755 tty->closing = 0;
756 }
757 mutex_unlock(&port->port.mutex);
758 sdio_uart_port_put(port);
759} 786}
760 787
761static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, 788static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
@@ -1021,6 +1048,12 @@ static const struct file_operations sdio_uart_proc_fops = {
1021 .release = single_release, 1048 .release = single_release,
1022}; 1049};
1023 1050
1051static const struct tty_port_operations sdio_uart_port_ops = {
1052 .dtr_rts = uart_dtr_rts,
1053 .shutdown = sdio_uart_shutdown,
1054 .activate = sdio_uart_activate,
1055};
1056
1024static const struct tty_operations sdio_uart_ops = { 1057static const struct tty_operations sdio_uart_ops = {
1025 .open = sdio_uart_open, 1058 .open = sdio_uart_open,
1026 .close = sdio_uart_close, 1059 .close = sdio_uart_close,
@@ -1031,9 +1064,12 @@ static const struct tty_operations sdio_uart_ops = {
1031 .throttle = sdio_uart_throttle, 1064 .throttle = sdio_uart_throttle,
1032 .unthrottle = sdio_uart_unthrottle, 1065 .unthrottle = sdio_uart_unthrottle,
1033 .set_termios = sdio_uart_set_termios, 1066 .set_termios = sdio_uart_set_termios,
1067 .hangup = sdio_uart_hangup,
1034 .break_ctl = sdio_uart_break_ctl, 1068 .break_ctl = sdio_uart_break_ctl,
1035 .tiocmget = sdio_uart_tiocmget, 1069 .tiocmget = sdio_uart_tiocmget,
1036 .tiocmset = sdio_uart_tiocmset, 1070 .tiocmset = sdio_uart_tiocmset,
1071 .install = sdio_uart_install,
1072 .cleanup = sdio_uart_cleanup,
1037 .proc_fops = &sdio_uart_proc_fops, 1073 .proc_fops = &sdio_uart_proc_fops,
1038}; 1074};
1039 1075
@@ -1096,6 +1132,7 @@ static int sdio_uart_probe(struct sdio_func *func,
1096 port->func = func; 1132 port->func = func;
1097 sdio_set_drvdata(func, port); 1133 sdio_set_drvdata(func, port);
1098 tty_port_init(&port->port); 1134 tty_port_init(&port->port);
1135 port->port.ops = &sdio_uart_port_ops;
1099 1136
1100 ret = sdio_uart_add_port(port); 1137 ret = sdio_uart_add_port(port);
1101 if (ret) { 1138 if (ret) {