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