提交 4901b2c3 编写于 作者: O Oliver Neukum 提交者: Greg Kroah-Hartman

USB: suspend/resume support for option driver

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: NOliver Neukum <oneukum@suse.de>
Signed-Off-By: NMatthias Urlichs <smurf@smurf.noris.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 b633d28e
...@@ -62,6 +62,8 @@ static int option_tiocmget(struct tty_struct *tty, struct file *file); ...@@ -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, static int option_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); 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 */ /* Vendor and product IDs */
#define OPTION_VENDOR_ID 0x0AF0 #define OPTION_VENDOR_ID 0x0AF0
...@@ -523,6 +525,8 @@ static struct usb_driver option_driver = { ...@@ -523,6 +525,8 @@ static struct usb_driver option_driver = {
.name = "option", .name = "option",
.probe = usb_serial_probe, .probe = usb_serial_probe,
.disconnect = usb_serial_disconnect, .disconnect = usb_serial_disconnect,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
.id_table = option_ids, .id_table = option_ids,
.no_dynamic_id = 1, .no_dynamic_id = 1,
}; };
...@@ -551,6 +555,8 @@ static struct usb_serial_driver option_1port_device = { ...@@ -551,6 +555,8 @@ static struct usb_serial_driver option_1port_device = {
.attach = option_startup, .attach = option_startup,
.shutdown = option_shutdown, .shutdown = option_shutdown,
.read_int_callback = option_instat_callback, .read_int_callback = option_instat_callback,
.suspend = option_suspend,
.resume = option_resume,
}; };
static int debug; static int debug;
...@@ -821,10 +827,10 @@ static void option_instat_callback(struct urb *urb) ...@@ -821,10 +827,10 @@ static void option_instat_callback(struct urb *urb)
req_pkt->bRequestType, req_pkt->bRequest); req_pkt->bRequestType, req_pkt->bRequest);
} }
} else } else
dbg("%s: error %d", __func__, status); err("%s: error %d", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */ /* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN) { if (status != -ESHUTDOWN && status != -ENOENT) {
urb->dev = serial->dev; urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) if (err)
...@@ -843,7 +849,6 @@ static int option_write_room(struct tty_struct *tty) ...@@ -843,7 +849,6 @@ static int option_write_room(struct tty_struct *tty)
portdata = usb_get_serial_port_data(port); portdata = usb_get_serial_port_data(port);
for (i = 0; i < N_OUT_URB; i++) { for (i = 0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i]; this_urb = portdata->out_urbs[i];
if (this_urb && !test_bit(i, &portdata->out_busy)) if (this_urb && !test_bit(i, &portdata->out_busy))
...@@ -1105,14 +1110,12 @@ static int option_startup(struct usb_serial *serial) ...@@ -1105,14 +1110,12 @@ static int option_startup(struct usb_serial *serial)
return 1; return 1;
} }
static void option_shutdown(struct usb_serial *serial) static void stop_read_write_urbs(struct usb_serial *serial)
{ {
int i, j; int i, j;
struct usb_serial_port *port; struct usb_serial_port *port;
struct option_port_private *portdata; struct option_port_private *portdata;
dbg("%s", __func__);
/* Stop reading/writing urbs */ /* Stop reading/writing urbs */
for (i = 0; i < serial->num_ports; ++i) { for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i]; port = serial->port[i];
...@@ -1122,6 +1125,17 @@ static void option_shutdown(struct usb_serial *serial) ...@@ -1122,6 +1125,17 @@ static void option_shutdown(struct usb_serial *serial)
for (j = 0; j < N_OUT_URB; j++) for (j = 0; j < N_OUT_URB; j++)
usb_kill_urb(portdata->out_urbs[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 */ /* Now free them */
for (i = 0; i < serial->num_ports; ++i) { for (i = 0; i < serial->num_ports; ++i) {
...@@ -1152,6 +1166,66 @@ static void option_shutdown(struct usb_serial *serial) ...@@ -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_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION); MODULE_VERSION(DRIVER_VERSION);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册