Re: suspend/resume for usb serial devices

James Graves <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
Here's those two patch files.  Boy, don't I feel silly.

James

-------------------------------------------------------------------------
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/

_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
sierra_suspend_resume_v107.patch (text/x-patch, 4 KB)
--- sierra.c	2007-05-02 13:11:47.000000000 -0500
+++ sierra_107.c	2007-04-30 19:17:43.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,
@@ -456,15 +459,45 @@
 	return (0);
 }
 
-static inline void stop_urb(struct urb *urb)
+/* Stop reading/writing urbs */
+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]);
+}
+
+static void unlink_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;
+
+		unlink_urbs(portdata);
+	}
+}
+
+static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
 {
-	if (urb && urb->status == -EINPROGRESS)
-		usb_kill_urb(urb);
+	dbg("%s", __FUNCTION__);
+	if (serial)
+		unlink_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 +509,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]);
+		unlink_urbs(portdata);
 	}
 	port->tty = NULL;
 }
@@ -523,7 +551,7 @@
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
 
-	/* Do indat endpoints first */
+		/* Do indat endpoints first */
 		for (j = 0; j < N_IN_URB; ++j) {
 			portdata->in_urbs[j] = sierra_setup_urb (serial,
                   	port->bulk_in_endpointAddress, USB_DIR_IN, port,
@@ -539,6 +567,14 @@
 	}
 }
 
+static int sierra_resume(struct usb_serial *serial)
+{
+	dbg("%s", __FUNCTION__);
+	if (serial)
+		sierra_setup_urbs(serial);
+	return 0;
+}
+
 static int sierra_startup(struct usb_serial *serial)
 {
 	int i, err;
@@ -580,20 +616,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]);
-	}
+	unlink_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 +644,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 +677,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 +708,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. */
generic_usb_susp_20070426.patch (text/x-patch, 4.1 KB)
--- linux-2.6.21-rc7/include/linux/usb/serial.h	2007-04-25 17:02:20.000000000 +0200
+++ linux-2.6.21-rc7-auto/include/linux/usb/serial.h	2007-04-26 14:48:17.000000000 +0200
@@ -221,6 +221,9 @@ struct usb_serial_driver {
 	int (*port_probe) (struct usb_serial_port *port);
 	int (*port_remove) (struct usb_serial_port *port);
 
+	int (*suspend) (struct usb_serial *serial, pm_message_t message);
+	int (*resume) (struct usb_serial *serial);
+
 	/* serial function calls */
 	int  (*open)		(struct usb_serial_port *port, struct file * filp);
 	void (*close)		(struct usb_serial_port *port, struct file * filp);
@@ -249,6 +252,9 @@ extern void usb_serial_port_softint(stru
 extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
 extern void usb_serial_disconnect(struct usb_interface *iface);
 
+extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
+extern int usb_serial_resume(struct usb_interface *intf);
+
 extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
 extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
 
@@ -269,6 +275,7 @@ extern void usb_serial_put(struct usb_se
 extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
 extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
 extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
+extern int usb_serial_generic_resume (struct usb_serial *serial);
 extern int usb_serial_generic_write_room (struct usb_serial_port *port);
 extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
 extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
--- linux-2.6.21-rc7/drivers/usb/serial/generic.c	2007-04-25 17:02:10.000000000 +0200
+++ linux-2.6.21-rc7-auto/drivers/usb/serial/generic.c	2007-04-26 14:09:27.000000000 +0200
@@ -169,6 +169,23 @@ static void generic_cleanup (struct usb_
 	}
 }
 
+int usb_serial_generic_resume(struct usb_serial *serial)
+{
+	struct usb_serial_port *port;
+	int i, c = 0, r;
+
+	for (i = 0; i < serial->num_ports; i++) {
+		port = serial->port[i];
+		if (port->open_count && port->read_urb) {
+			r = usb_submit_urb(port->read_urb, GFP_NOIO);
+			if (r < 0)
+				c++;
+		}
+	}
+
+	return c ? -EIO : 0;
+}
+
 void usb_serial_generic_close (struct usb_serial_port *port, struct file * filp)
 {
 	dbg("%s - port %d", __FUNCTION__, port->number);
--- linux-2.6.21-rc7/drivers/usb/serial/usb-serial.c	2007-04-25 17:02:11.000000000 +0200
+++ linux-2.6.21-rc7-auto/drivers/usb/serial/usb-serial.c	2007-04-26 15:28:23.000000000 +0200
@@ -47,6 +47,8 @@ static struct usb_driver usb_serial_driv
 	.name =		"usbserial",
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
+	.suspend =	usb_serial_suspend,
+	.resume =	usb_serial_resume,
 	.no_dynamic_id = 	1,
 };
 
@@ -1070,6 +1072,37 @@ void usb_serial_disconnect(struct usb_in
 	dev_info(dev, "device disconnected\n");
 }
 
+int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usb_serial *serial = usb_get_intfdata(intf);
+	struct usb_serial_port *port;
+	int i, r = 0;
+
+	if (serial) {
+		for (i = 0; i < serial->num_ports; ++i) {
+			port = serial->port[i];
+			if (port)
+				kill_traffic(port);
+		}
+	}
+
+	if (serial->type->suspend)
+		serial->type->suspend(serial, message);
+
+	return r;
+}
+
+EXPORT_SYMBOL(usb_serial_suspend);
+
+int usb_serial_resume(struct usb_interface *intf)
+{
+	struct usb_serial *serial = usb_get_intfdata(intf);
+
+	return serial->type->resume(serial);
+}
+
+EXPORT_SYMBOL(usb_serial_resume);
+
 static const struct tty_operations serial_ops = {
 	.open =			serial_open,
 	.close =		serial_close,
@@ -1195,6 +1228,7 @@ static void fixup_generic(struct usb_ser
 	set_to_generic_if_null(device, read_bulk_callback);
 	set_to_generic_if_null(device, write_bulk_callback);
 	set_to_generic_if_null(device, shutdown);
+	set_to_generic_if_null(device, resume);
 }
 
 int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.