tty: sdio_uart: add modem functionality
Alan Cox [Mon, 30 Nov 2009 13:16:36 +0000 (13:16 +0000)]
Add the POSIX block for carrier

Linux TIOCMIWAIT functionality is still lacking from the driver.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

drivers/mmc/card/sdio_uart.c

index b999972..2a13db5 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/serial_reg.h>
@@ -86,6 +87,7 @@ struct sdio_uart_port {
        struct uart_icount      icount;
        unsigned int            uartclk;
        unsigned int            mctrl;
+       unsigned int            rx_mctrl;
        unsigned int            read_status_mask;
        unsigned int            ignore_status_mask;
        unsigned char           x_char;
@@ -220,6 +222,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
        unsigned char status;
        unsigned int ret;
 
+       /* FIXME: What stops this losing the delta bits and breaking
+          sdio_uart_check_modem_status ? */
        status = sdio_in(port, UART_MSR);
 
        ret = 0;
@@ -503,8 +507,20 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
                port->icount.rng++;
        if (status & UART_MSR_DDSR)
                port->icount.dsr++;
-       if (status & UART_MSR_DDCD)
+       if (status & UART_MSR_DDCD) {
                port->icount.dcd++;
+               /* DCD raise - wake for open */
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&port->port.open_wait);
+               else {
+                       /* DCD drop - hang up if tty attached */
+                       tty = tty_port_tty_get(&port->port);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
+               }
+       }
        if (status & UART_MSR_DCTS) {
                port->icount.cts++;
                tty = tty_port_tty_get(&port->port);
@@ -560,6 +576,20 @@ static void sdio_uart_irq(struct sdio_func *func)
        port->in_sdio_uart_irq = NULL;
 }
 
+static int uart_carrier_raised(struct tty_port *tport)
+{
+       struct sdio_uart_port *port =
+                       container_of(tport, struct sdio_uart_port, port);
+       unsigned int ret = sdio_uart_claim_func(port);
+       if (ret)        /* Missing hardware shoudn't block for carrier */
+               return 1;
+       ret = sdio_uart_get_mctrl(port);
+       sdio_uart_release_func(port);
+       if (ret & TIOCM_CAR)
+               return 1;
+       return 0;
+}
+
 /**
  *     uart_dtr_rts            -        port helper to set uart signals
  *     @tport: tty port to be updated
@@ -1044,6 +1074,7 @@ static const struct file_operations sdio_uart_proc_fops = {
 
 static const struct tty_port_operations sdio_uart_port_ops = {
        .dtr_rts = uart_dtr_rts,
+       .carrier_raised = uart_carrier_raised,
        .shutdown = sdio_uart_shutdown,
        .activate = sdio_uart_activate,
 };