Skip to content

Commit

Permalink
USB: suspend/resume support for option driver
Browse files Browse the repository at this point in the history
This patch implements suspend and resume methods for the
option driver. With my hardware I can even suspend the system
and keep up a connection for a short time.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-Off-By: Matthias Urlichs <smurf@smurf.noris.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Oliver Neukum authored and Greg Kroah-Hartman committed Mar 24, 2009
1 parent b633d28 commit 4901b2c
Showing 1 changed file with 80 additions and 6 deletions.
86 changes: 80 additions & 6 deletions drivers/usb/serial/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ static int option_tiocmget(struct tty_struct *tty, struct file *file);
static int option_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port);
static int option_suspend(struct usb_serial *serial, pm_message_t message);
static int option_resume(struct usb_serial *serial);

/* Vendor and product IDs */
#define OPTION_VENDOR_ID 0x0AF0
Expand Down Expand Up @@ -523,6 +525,8 @@ static struct usb_driver option_driver = {
.name = "option",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
.id_table = option_ids,
.no_dynamic_id = 1,
};
Expand Down Expand Up @@ -551,6 +555,8 @@ static struct usb_serial_driver option_1port_device = {
.attach = option_startup,
.shutdown = option_shutdown,
.read_int_callback = option_instat_callback,
.suspend = option_suspend,
.resume = option_resume,
};

static int debug;
Expand Down Expand Up @@ -821,10 +827,10 @@ static void option_instat_callback(struct urb *urb)
req_pkt->bRequestType, req_pkt->bRequest);
}
} else
dbg("%s: error %d", __func__, status);
err("%s: error %d", __func__, status);

/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN) {
if (status != -ESHUTDOWN && status != -ENOENT) {
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
Expand All @@ -843,7 +849,6 @@ static int option_write_room(struct tty_struct *tty)

portdata = usb_get_serial_port_data(port);


for (i = 0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
if (this_urb && !test_bit(i, &portdata->out_busy))
Expand Down Expand Up @@ -1105,14 +1110,12 @@ static int option_startup(struct usb_serial *serial)
return 1;
}

static void option_shutdown(struct usb_serial *serial)
static void stop_read_write_urbs(struct usb_serial *serial)
{
int i, j;
struct usb_serial_port *port;
struct option_port_private *portdata;

dbg("%s", __func__);

/* Stop reading/writing urbs */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
Expand All @@ -1122,6 +1125,17 @@ static void option_shutdown(struct usb_serial *serial)
for (j = 0; j < N_OUT_URB; j++)
usb_kill_urb(portdata->out_urbs[j]);
}
}

static void option_shutdown(struct usb_serial *serial)
{
int i, j;
struct usb_serial_port *port;
struct option_port_private *portdata;

dbg("%s", __func__);

stop_read_write_urbs(serial);

/* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
Expand Down Expand Up @@ -1152,6 +1166,66 @@ static void option_shutdown(struct usb_serial *serial)
}
}

static int option_suspend(struct usb_serial *serial, pm_message_t message)
{
dbg("%s entered", __func__);
stop_read_write_urbs(serial);

return 0;
}

static int option_resume(struct usb_serial *serial)
{
int err, i, j;
struct usb_serial_port *port;
struct urb *urb;
struct option_port_private *portdata;

dbg("%s entered", __func__);
/* get the interrupt URBs resubmitted unconditionally */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (!port->interrupt_in_urb) {
dbg("%s: No interrupt URB for port %d\n", __func__, i);
continue;
}
port->interrupt_in_urb->dev = serial->dev;
err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
dbg("Submitted interrupt URB for port %d (result %d)", i, err);
if (err < 0) {
err("%s: Error %d for interrupt URB of port%d",
__func__, err, i);
return err;
}
}

for (i = 0; i < serial->num_ports; i++) {
/* walk all ports */
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
mutex_lock(&port->mutex);

/* skip closed ports */
if (!port->port.count) {
mutex_unlock(&port->mutex);
continue;
}

for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
err = usb_submit_urb(urb, GFP_NOIO);
if (err < 0) {
mutex_unlock(&port->mutex);
err("%s: Error %d for bulk URB %d",
__func__, err, i);
return err;
}
}
mutex_unlock(&port->mutex);
}
return 0;
}

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
Expand Down

0 comments on commit 4901b2c

Please sign in to comment.