mdm6600: First pass at suspend/resume support.
authorNick Pelly <npelly@google.com>
Fri, 27 Aug 2010 22:08:56 +0000 (15:08 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:50 +0000 (16:33 -0700)
Add suspend/resume handler. Usb framework will no longer de-register tty on
suspend/resume now. Kill URB's with usbcore while in suspend.

Switch from dev_foo() to pr_foo() printk helpers. The dev_ ones are a pain to
find the right device struct, and occasionally caused null pointer panics.

Change-Id: I38769dc3befaef1a783ec5ab77169db2e963a9bc
Signed-off-by: Nick Pelly <npelly@google.com>
drivers/usb/serial/mdm6600.c

index 3a1f32db30c475d0f5104bfbc94faf8ecd52d299..124f40c47ad1e25860e25a662b7712a8df2f94b0 100644 (file)
@@ -116,13 +116,11 @@ static int mdm6600_attach(struct usb_serial *serial)
                        epread = ep;
        }
        if (!epwrite) {
-               dev_err(&serial->dev->dev, "%s No bulk out endpoint\n",
-                       __func__);
+               pr_err("%s No bulk out endpoint\n", __func__);
                return -EIO;
        }
        if (!epread) {
-               dev_err(&serial->dev->dev, "%s No bulk in endpoint\n",
-                       __func__);
+               pr_err("%s No bulk in endpoint\n", __func__);
                return -EIO;
        }
 
@@ -175,10 +173,8 @@ static int mdm6600_attach(struct usb_serial *serial)
        return 0;
 }
 
-static void mdm6600_disconnect(struct usb_serial *serial)
+static void mdm6600_kill_urbs(struct mdm6600_port *modem)
 {
-       struct mdm6600_port *modem = usb_get_serial_data(serial);
-
        dbg("%s: port %d", __func__, modem->port->number);
 
        /* cancel pending writes */
@@ -188,6 +184,16 @@ static void mdm6600_disconnect(struct usb_serial *serial)
        usb_kill_anchored_urbs(&modem->read.in_flight);
        usb_kill_urb(modem->port->interrupt_in_urb);
 
+}
+
+static void mdm6600_disconnect(struct usb_serial *serial)
+{
+       struct mdm6600_port *modem = usb_get_serial_data(serial);
+
+       dbg("%s: port %d", __func__, modem->port->number);
+
+       mdm6600_kill_urbs(modem);
+
        /* cancel read bottom half */
        cancel_work_sync(&modem->read.work);
 
@@ -218,25 +224,18 @@ static void mdm6600_release(struct usb_serial *serial)
        }
 }
 
-/* called when tty is opened */
-static int mdm6600_open(struct tty_struct *tty, struct usb_serial_port *port)
+static int mdm6600_submit_urbs(struct mdm6600_port *modem)
 {
        int i;
-       int rc = 0;
-       struct mdm6600_port *modem = usb_get_serial_data(port->serial);
-
-       dbg("%s: port %d", __func__, port->number);
-
-       WARN_ON_ONCE(modem->port != port);
+       int rc;
 
-       modem->tiocm_status = 0;
+       dbg("%s: port %d", __func__, modem->port->number);
 
-       if (port->number == MODEM_INTERFACE_NUM) {
-               WARN_ON_ONCE(!port->interrupt_in_urb);
-               rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+       if (modem->port->number == MODEM_INTERFACE_NUM) {
+               WARN_ON_ONCE(!modem->port->interrupt_in_urb);
+               rc = usb_submit_urb(modem->port->interrupt_in_urb, GFP_KERNEL);
                if (rc) {
-                       dev_err(&port->dev,
-                           "%s: failed to submit interrupt urb, error %d\n",
+                       pr_err("%s: failed to submit interrupt urb, error %d\n",
                            __func__, rc);
                        return rc;
                }
@@ -244,28 +243,37 @@ static int mdm6600_open(struct tty_struct *tty, struct usb_serial_port *port)
        for (i = 0; i < POOL_SZ; i++) {
                rc = usb_submit_urb(modem->read.urb[i], GFP_KERNEL);
                if (rc) {
-                       dev_err(&port->dev,
-                           "%s: failed to submit bulk read urb, error %d\n",
+                       pr_err("%s: failed to submit bulk read urb, error %d\n",
                            __func__, rc);
                        return rc;
                }
+               usb_anchor_urb(modem->read.urb[i], &modem->read.in_flight);
        }
 
-       return rc;
+       return 0;
 }
 
-static void mdm6600_close(struct usb_serial_port *port)
+/* called when tty is opened */
+static int mdm6600_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct mdm6600_port *modem = usb_get_serial_data(port->serial);
 
        dbg("%s: port %d", __func__, port->number);
 
-       /* cancel pending writes */
-       usb_kill_anchored_urbs(&modem->write.in_flight);
+       WARN_ON_ONCE(modem->port != port);
 
-       /* stop reading from mdm6600 */
-       usb_kill_anchored_urbs(&modem->read.in_flight);
-       usb_kill_urb(port->interrupt_in_urb);
+       modem->tiocm_status = 0;
+
+       return mdm6600_submit_urbs(modem);
+}
+
+static void mdm6600_close(struct usb_serial_port *port)
+{
+       struct mdm6600_port *modem = usb_get_serial_data(port->serial);
+
+       dbg("%s: port %d", __func__, port->number);
+
+       mdm6600_kill_urbs(modem);
 
        /* cancel read bottom half */
        cancel_work_sync(&modem->read.work);
@@ -331,12 +339,10 @@ static void mdm6600_write_bulk_cb(struct urb *u)
 
        status = u->status;
        if (status)
-               dev_warn(&modem->serial->dev->dev, "%s non-zero status %d\n",
-                       __func__, u->status);
+               pr_warn("%s non-zero status %d\n", __func__, u->status);
 
        if (mdm6600_mark_write_urb_unused(&modem->write, u))
-               dev_warn(&modem->serial->dev->dev, "%s unknown urb %p\n",
-                       __func__, u);
+               pr_warn("%s unknown urb %p\n", __func__, u);
 
        if (!status)
                usb_serial_port_softint(modem->port);
@@ -358,7 +364,7 @@ static int mdm6600_write(struct tty_struct *tty, struct usb_serial_port *port,
 
        u = mdm6600_get_unused_write_urb(&modem->write);
        if (!u) {
-               dev_info(&port->dev, "%s: all buffers busy!\n", __func__);
+               pr_info("%s: all buffers busy!\n", __func__);
                return 0;
        }
 
@@ -370,8 +376,7 @@ static int mdm6600_write(struct tty_struct *tty, struct usb_serial_port *port,
 
        rc = usb_submit_urb(u, GFP_ATOMIC);
        if (rc < 0) {
-               dev_err(&port->dev, "%s: submit bulk urb failed %d\n",
-                       __func__, rc);
+               pr_err("%s: submit bulk urb failed %d\n", __func__, rc);
                return rc;
        }
 
@@ -400,9 +405,8 @@ static int mdm6600_dtr_control(struct usb_serial_port *port, int ctrl)
 
        rc = usb_autopm_get_interface(iface);
        if (rc < 0) {
-               dev_err(&dev->dev, "%s %s autopm failed %d",
-                       dev_driver_string(&iface->dev), dev_name(&iface->dev),
-                       rc);
+               pr_err("%s %s autopm failed %d", dev_driver_string(&iface->dev),
+                       dev_name(&iface->dev), rc);
                return rc;
        }
 
@@ -464,9 +468,9 @@ static void mdm6600_read_int_callback(struct urb *u)
        case -ENOENT:
        case -ESHUTDOWN:
                dbg("%s: urb terminated, status %d", __func__, u->status);
-               goto exit;
+               return;
        default:
-               dbg("%s: urb status non-zero %d", __func__, u->status);
+               pr_warn("%s non-zero status %d\n", __func__, u->status);
                goto exit;
        }
 
@@ -483,8 +487,7 @@ static void mdm6600_read_int_callback(struct urb *u)
        switch (request) {
        case BP_MODEM_STATUS:
                if (u->actual_length < 9) {
-                       dev_err(&port->dev,
-                               "%s: modem status urb too small %d\n",
+                       pr_err("%s: modem status urb too small %d\n",
                                __func__, u->actual_length);
                        break;
                }
@@ -507,8 +510,7 @@ static void mdm6600_read_int_callback(struct urb *u)
 exit:
        rc = usb_submit_urb(u, GFP_ATOMIC);
        if (rc)
-               dev_err(&u->dev->dev,
-                       "%s: Error %d re-submitting interrupt urb\n",
+               pr_err("%s: Error %d re-submitting interrupt urb\n",
                        __func__, rc);
 }
 
@@ -555,15 +557,13 @@ static void mdm6600_read_bulk_work(struct work_struct *work)
                        u->actual_length, u->transfer_buffer);
                tty = tty_port_tty_get(&modem->port->port);
                if (!tty) {
-                       dev_warn(&modem->port->dev, "%s: could not find tty\n",
-                               __func__);
+                       pr_warn("%s: could not find tty\n", __func__);
                        goto next;
                }
                c = mdm6600_pass_to_tty(tty, u->transfer_buffer,
                        u->actual_length);
                if (c != u->actual_length)
-                       dev_warn(&modem->port->dev,
-                               "%s: dropped %u of %u bytes\n",
+                       pr_warn("%s: dropped %u of %u bytes\n",
                                __func__, u->actual_length - c,
                                u->actual_length);
                tty_kref_put(tty);
@@ -571,41 +571,74 @@ static void mdm6600_read_bulk_work(struct work_struct *work)
 next:
                rc = usb_submit_urb(u, GFP_KERNEL);
                if (rc)
-                       dev_err(&u->dev->dev,
-                               "%s: Error %d re-submitting read urb\n",
+                       pr_err("%s: Error %d re-submitting read urb\n",
                                __func__, rc);
+               else
+                       usb_anchor_urb(u, &modem->read.in_flight);
        }
 }
 
 static void mdm6600_read_bulk_cb(struct urb *u)
 {
+       int rc;
        struct mdm6600_port *modem = u->context;
 
        dbg("%s: urb %p", __func__, u);
 
-       if (u->status) {
-               int rc;
-               dev_warn(&modem->serial->dev->dev, "%s non-zero status %d\n",
-                       __func__, u->status);
+       switch (u->status) {
+       case 0:
+               break;  /* success */
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               dbg("%s: urb terminated, status %d", __func__, u->status);
+               return;
+       default:
+               pr_warn("%s non-zero status %d\n", __func__, u->status);
                /* straight back into use */
                rc = usb_submit_urb(u, GFP_ATOMIC);
                if (rc)
-                       dev_err(&u->dev->dev,
-                               "%s: Error %d re-submitting read urb\n",
+                       pr_err("%s: Error %d re-submitting read urb\n",
                                __func__, rc);
                return;
        }
 
+       /* process urb in bottom half */
        usb_anchor_urb(u, &modem->read.pending);
        schedule_work(&modem->read.work);
 }
 
+static int mdm6600_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct usb_serial *serial = usb_get_intfdata(intf);
+       struct mdm6600_port *modem = usb_get_serial_data(serial);
+
+       dbg("%s: event=%d", __func__, message.event);
+
+       mdm6600_kill_urbs(modem);
+
+       return 0;
+}
+
+static int mdm6600_resume(struct usb_interface *intf)
+{
+       struct usb_serial *serial = usb_get_intfdata(intf);
+       struct mdm6600_port *modem = usb_get_serial_data(serial);
+
+       dbg("%s", __func__);
+
+       return mdm6600_submit_urbs(modem);
+}
+
 static struct usb_driver mdm6600_usb_driver = {
        .name =         "mdm6600",
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     mdm6600_id_table,
        .no_dynamic_id =        1,
+       .supports_autosuspend = 1,
+       .suspend =      mdm6600_suspend,
+       .resume =       mdm6600_resume,
 };
 
 static struct usb_serial_driver mdm6600_usb_serial_driver = {