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