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