|
@@ -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
|
|
@@ -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,
|
|
|
};
|
|
@@ -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;
|
|
@@ -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)
|
|
@@ -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))
|
|
@@ -1105,14 +1110,12 @@ bail_out_error:
|
|
|
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];
|
|
@@ -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) {
|
|
@@ -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);
|