Oliver,

Thank you for this patch, we will get to testing it and respond with
results.

-Kevin

-----Original Message-----
From: Oliver Neukum [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, January 30, 2008 1:32 AM
To: Linux Development Group; linux-usb@vger.kernel.org
Subject: testers sought: USB autosuspend for sierra

Hi,

this should implement USB autosuspend and hence some power savings
if enabled for devices using the sierra driver. Please test.

        Regards
                Oliver

----

--- linux-2.6.24-sierra/drivers/usb/serial/sierra.c.alt 2008-01-29
19:34:49.000000000 +0100
+++ linux-2.6.24-sierra/drivers/usb/serial/sierra.c     2008-01-30
10:23:24.000000000 +0100
@@ -42,6 +42,7 @@
 static int debug;
 static int nmea;
 static int truinstall = 1;
+static DEFINE_MUTEX(open_suspend_lock);
 
 enum devicetype {
        DEVICE_3_PORT =         0,
@@ -49,6 +50,25 @@ enum devicetype {
        DEVICE_INSTALLER =      2,
 };
 
+
+struct sierra_port_private {
+       spinlock_t lock;        /* lock the structure */
+       int outstanding_urbs;   /* number of out urbs in flight */
+       struct usb_anchor transmit_urbs;
+
+       /* Input endpoints and buffer for this port */
+       struct urb *in_urbs[N_IN_URB];
+       char in_buffer[N_IN_URB][IN_BUFLEN];
+
+       /* Settings for the port */
+       int rts_state;  /* Handshaking pins (outputs) */
+       int dtr_state;
+       int cts_state;  /* Handshaking pins (inputs) */
+       int dsr_state;
+       int dcd_state;
+       int ri_state;
+};
+
 static int sierra_set_power_state(struct usb_device *udev, __u16
swiState)
 {
        int result;
@@ -146,6 +166,68 @@ static int sierra_probe(struct usb_seria
        return result;
 }
 
+static int sierra_suspend(struct usb_interface *intf, pm_message_t
message)
+{
+       struct usb_serial *serial = usb_get_intfdata(intf);
+       struct usb_serial_port *port;
+       struct sierra_port_private *portdata;
+       struct urb *u;
+       int i, j;
+
+       mutex_lock(&open_suspend_lock);
+
+       for (i = 0; i < serial->num_port_pointers; i++) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
+               usb_kill_urb(port->interrupt_in_urb);
+               for (j = 0; j < N_IN_URB; j++) {
+                       u = portdata->in_urbs[j];
+                       usb_kill_urb(u);
+               }
+               usb_kill_anchored_urbs(&portdata->transmit_urbs);
+       }
+
+       mutex_unlock(&open_suspend_lock);
+       return 0;
+}
+
+static int sierra_resume (struct usb_interface *intf)
+{
+       struct usb_serial *serial = usb_get_intfdata(intf);
+       struct usb_serial_port *port;
+       struct sierra_port_private *portdata;
+       struct urb *u;
+       int i, j, err = 0;
+
+       mutex_lock(&open_suspend_lock);
+       for (i = 0; i < serial->num_port_pointers; i++) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
+               if (port->open_count) {
+                       for (j = 0; j < N_IN_URB; j++) {
+                               u = portdata->in_urbs[j];
+                               err = usb_submit_urb(u, GFP_NOIO);
+                               if (err < 0) {
+error_kill:
+                                       for (j = N_IN_URB - 1; j >= 0;
j--) {
+                                               u =
portdata->in_urbs[j];
+                                               usb_kill_urb(u);
+                                       }
+                                       goto error_bail_out;
+                               }
+                       }
+                       if (port->interrupt_in_urb) {
+                               err =
usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+                               if (err < 0)
+                                       goto error_kill;
+                       }
+               }
+       }
+error_bail_out:
+       mutex_unlock(&open_suspend_lock);
+       return err;
+}
+
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
@@ -189,25 +271,11 @@ static struct usb_driver sierra_driver =
        .name       = "sierra",
        .probe      = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
+       .suspend        = sierra_suspend,
+       .resume         = sierra_resume,
        .id_table   = id_table,
        .no_dynamic_id =        1,
-};
-
-struct sierra_port_private {
-       spinlock_t lock;        /* lock the structure */
-       int outstanding_urbs;   /* number of out urbs in flight */
-
-       /* Input endpoints and buffer for this port */
-       struct urb *in_urbs[N_IN_URB];
-       char in_buffer[N_IN_URB][IN_BUFLEN];
-
-       /* Settings for the port */
-       int rts_state;  /* Handshaking pins (outputs) */
-       int dtr_state;
-       int cts_state;  /* Handshaking pins (inputs) */
-       int dsr_state;
-       int dcd_state;
-       int ri_state;
+       .supports_autosuspend = 1,
 };
 
 static int sierra_send_setup(struct usb_serial_port *port)
@@ -381,11 +449,13 @@ static int sierra_write(struct usb_seria
                          buffer, count, sierra_outdat_callback, port);
 
        /* send it down the pipe */
+       usb_anchor_urb(urb, &portdata->transmit_urbs);
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
                dev_err(&port->dev, "%s - usb_submit_urb(write bulk)
failed "
                        "with status = %d\n", __FUNCTION__, status);
                count = status;
+               usb_unanchor_urb(urb);
                goto error;
        }
 
@@ -546,6 +616,11 @@ static int sierra_open(struct usb_serial
        portdata->rts_state = 1;
        portdata->dtr_state = 1;
 
+       result = usb_autopm_get_interface(serial->interface);
+       if (result < 0)
+               return -EIO;
+
+       mutex_lock(&open_suspend_lock);
        /* Reset low level data toggle and start reading from endpoints
*/
        for (i = 0; i < N_IN_URB; i++) {
                urb = portdata->in_urbs[i];
@@ -581,6 +656,7 @@ static int sierra_open(struct usb_serial
                        dev_err(&port->dev, "submit irq_in urb failed
%d\n",
                                result);
        }
+       mutex_unlock(&open_suspend_lock);
        return 0;
 }
 
@@ -605,6 +681,7 @@ static void sierra_close(struct usb_seri
        }
 
        usb_kill_urb(port->interrupt_in_urb);
+       usb_autopm_put_interface(serial->interface);
 
        port->tty = NULL;
 }
@@ -636,6 +713,7 @@ static int sierra_startup(struct usb_ser
                        return -ENOMEM;
                }
                spin_lock_init(&portdata->lock);
+               init_usb_anchor(&portdata->transmit_urbs);
 
                usb_set_serial_port_data(port, portdata);
 

-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to