USB: suspend support for usb serial

this implements generic support for suspend/resume for usb serial.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 4f8282a..b90ef3f 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -69,6 +69,7 @@
 	.shutdown =		usb_serial_generic_shutdown,
 	.throttle =		usb_serial_generic_throttle,
 	.unthrottle =		usb_serial_generic_unthrottle,
+	.resume =		usb_serial_generic_resume,
 };
 
 static int generic_probe(struct usb_interface *interface,
@@ -169,6 +170,23 @@
 	}
 }
 
+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);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 87f3788..e3e3728 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -46,6 +46,8 @@
 	.name =		"usbserial",
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
+	.suspend =	usb_serial_suspend,
+	.resume =	usb_serial_resume,
 	.no_dynamic_id = 	1,
 };
 
@@ -1069,6 +1071,35 @@
 	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,
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 32acbae..e8b8928 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -221,6 +221,9 @@
 	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 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 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);