Oliver Neukum wrote:
this is wrong for 2 reasons:
[... sierra_resume() and sierra_setup_urbs() ...]
1. You allocate new urbs. But you don't free the old urbs in suspend.
2. You don't restart the read queue. resume() must share code with open()
in that regard
OK, I have pulled out the code from sierra_open() that does the
usb_clear_halt() and usb_submit_urb() into a new function called
sierra_enable_urbs(). That then is called by sierra_open() and
sierra_resume(). Is this what you meant?
+static inline void unlink_urbs(struct sierra_port_private *portdata)
+{
+ int i;
+ for (i = 0; i < N_IN_URB; i++)
+ usb_unlink_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_unlink_urb(portdata->out_urbs[i]);
+}
Use usb_kill_urb() please.
OK. I also changed the name for those associated functions too.
Attached is the revised patch for the linux 2.6.21 version of sierra.c.
Let me know what you think. We're still testing it here.
Thanks Oliver!
James
--- sierra.c 2007-05-01 18:07:39.000000000 -0500
+++ sierra_107.c 2007-05-07 18:53:31.000000000 -0500
@@ -15,7 +15,7 @@
*/
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.0.7"
#define DRIVER_AUTHOR "Kevin Lloyd <[EMAIL PROTECTED]>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -69,6 +69,9 @@
{ }
};
+static int sierra_resume(struct usb_serial *serial);
+static int sierra_suspend(struct usb_serial *serial, pm_message_t message);
+
static struct usb_driver sierra_driver = {
.name = "sierra",
.probe = usb_serial_probe,
@@ -391,22 +394,11 @@
return data_len;
}
-static int sierra_open(struct usb_serial_port *port, struct file *filp)
-{
- struct sierra_port_private *portdata;
- struct usb_serial *serial = port->serial;
- int i, err;
- struct urb *urb;
- int result;
- __u16 set_mode_dzero = 0x0000;
- portdata = usb_get_serial_port_data(port);
-
- dbg("%s", __FUNCTION__);
-
- /* Set some sane defaults */
- portdata->rts_state = 1;
- portdata->dtr_state = 1;
+static void sierra_enable_urbs(struct usb_serial *serial, struct sierra_port_private *portdata)
+{
+ int i, err;
+ struct urb *urb;
/* Reset low level data toggle and start reading from endpoints */
for (i = 0; i < N_IN_URB; i++) {
@@ -442,6 +434,24 @@
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), 0); */
}
+}
+
+static int sierra_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct sierra_port_private *portdata;
+ struct usb_serial *serial = port->serial;
+ int result;
+ __u16 set_mode_dzero = 0x0000;
+
+ portdata = usb_get_serial_port_data(port);
+
+ dbg("%s", __FUNCTION__);
+
+ /* Set some sane defaults */
+ portdata->rts_state = 1;
+ portdata->dtr_state = 1;
+
+ sierra_enable_urbs(serial, portdata);
port->tty->low_latency = 1;
@@ -456,15 +466,45 @@
return (0);
}
-static inline void stop_urb(struct urb *urb)
-{
- if (urb && urb->status == -EINPROGRESS)
- usb_kill_urb(urb);
+/* Stop reading/writing urbs */
+static inline void kill_urbs(struct sierra_port_private *portdata)
+{
+ int i;
+ for (i = 0; i < N_IN_URB; i++)
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
+}
+
+static void kill_all_ports_urbs(struct usb_serial *serial)
+{
+ int i;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ /* Stop reading/writing urbs */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (!port)
+ continue;
+ portdata = usb_get_serial_port_data(port);
+ if (!portdata)
+ continue;
+
+ kill_urbs(portdata);
+ }
+}
+
+static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
+{
+ dbg("%s", __FUNCTION__);
+ if (serial)
+ kill_all_ports_urbs(serial);
+ return 0;
}
static void sierra_close(struct usb_serial_port *port, struct file *filp)
{
- int i;
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
@@ -476,12 +516,7 @@
if (serial->dev) {
sierra_send_setup(port);
-
- /* Stop reading/writing urbs */
- for (i = 0; i < N_IN_URB; i++)
- stop_urb(portdata->in_urbs[i]);
- for (i = 0; i < N_OUT_URB; i++)
- stop_urb(portdata->out_urbs[i]);
+ kill_urbs(portdata);
}
port->tty = NULL;
}
@@ -510,6 +545,28 @@
return urb;
}
+
+static int sierra_resume(struct usb_serial *serial)
+{
+ int i;
+
+ dbg("%s", __FUNCTION__);
+ if (serial) {
+ for (i = 0; i < serial->num_ports; i++) {
+ struct usb_serial_port *port;
+ port = serial->port[i];
+ if (port) {
+ struct sierra_port_private *portdata;
+ portdata = usb_get_serial_port_data(port);
+ if (portdata) {
+ sierra_enable_urbs(serial, portdata);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
/* Setup urbs */
static void sierra_setup_urbs(struct usb_serial *serial)
{
@@ -580,20 +637,16 @@
dbg("%s", __FUNCTION__);
- /* Stop reading/writing urbs */
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- portdata = usb_get_serial_port_data(port);
- for (j = 0; j < N_IN_URB; j++)
- stop_urb(portdata->in_urbs[j]);
- for (j = 0; j < N_OUT_URB; j++)
- stop_urb(portdata->out_urbs[j]);
- }
+ kill_all_ports_urbs(serial);
/* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
+ if (!port)
+ continue;
portdata = usb_get_serial_port_data(port);
+ if (!portdata)
+ continue;
for (j = 0; j < N_IN_URB; j++) {
if (portdata->in_urbs[j]) {
@@ -612,6 +665,8 @@
/* Now free per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
+ if (!port)
+ continue;
kfree(usb_get_serial_port_data(port));
}
}
@@ -643,6 +698,8 @@
.attach = sierra_startup,
.shutdown = sierra_shutdown,
.read_int_callback = sierra_instat_callback,
+ .suspend = sierra_suspend,
+ .resume = sierra_resume,
};
static struct usb_serial_driver sierra_3port_device = {
@@ -672,6 +729,8 @@
.attach = sierra_startup,
.shutdown = sierra_shutdown,
.read_int_callback = sierra_instat_callback,
+ .suspend = sierra_suspend,
+ .resume = sierra_resume,
};
/* Functions used by new usb-serial code. */
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel