aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/option.c
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2009-01-27 11:21:40 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-03-24 19:20:29 -0400
commit4901b2c34ecb6fc45909228ad269c8126efe4401 (patch)
treedd7fe1bd0bb4b86859eaba4bcb27b5302e51d134 /drivers/usb/serial/option.c
parentb633d28e2c5fbe1c8d163892644f57df04aa1421 (diff)
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: Oliver Neukum <oneukum@suse.de> Signed-Off-By: Matthias Urlichs <smurf@smurf.noris.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/option.c')
-rw-r--r--drivers/usb/serial/option.c86
1 files changed, 80 insertions, 6 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 61ebddc48497..d560c0b54e6e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -62,6 +62,8 @@ static int option_tiocmget(struct tty_struct *tty, struct file *file);
62static int option_tiocmset(struct tty_struct *tty, struct file *file, 62static int option_tiocmset(struct tty_struct *tty, struct file *file,
63 unsigned int set, unsigned int clear); 63 unsigned int set, unsigned int clear);
64static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port); 64static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port);
65static int option_suspend(struct usb_serial *serial, pm_message_t message);
66static int option_resume(struct usb_serial *serial);
65 67
66/* Vendor and product IDs */ 68/* Vendor and product IDs */
67#define OPTION_VENDOR_ID 0x0AF0 69#define OPTION_VENDOR_ID 0x0AF0
@@ -523,6 +525,8 @@ static struct usb_driver option_driver = {
523 .name = "option", 525 .name = "option",
524 .probe = usb_serial_probe, 526 .probe = usb_serial_probe,
525 .disconnect = usb_serial_disconnect, 527 .disconnect = usb_serial_disconnect,
528 .suspend = usb_serial_suspend,
529 .resume = usb_serial_resume,
526 .id_table = option_ids, 530 .id_table = option_ids,
527 .no_dynamic_id = 1, 531 .no_dynamic_id = 1,
528}; 532};
@@ -551,6 +555,8 @@ static struct usb_serial_driver option_1port_device = {
551 .attach = option_startup, 555 .attach = option_startup,
552 .shutdown = option_shutdown, 556 .shutdown = option_shutdown,
553 .read_int_callback = option_instat_callback, 557 .read_int_callback = option_instat_callback,
558 .suspend = option_suspend,
559 .resume = option_resume,
554}; 560};
555 561
556static int debug; 562static int debug;
@@ -821,10 +827,10 @@ static void option_instat_callback(struct urb *urb)
821 req_pkt->bRequestType, req_pkt->bRequest); 827 req_pkt->bRequestType, req_pkt->bRequest);
822 } 828 }
823 } else 829 } else
824 dbg("%s: error %d", __func__, status); 830 err("%s: error %d", __func__, status);
825 831
826 /* Resubmit urb so we continue receiving IRQ data */ 832 /* Resubmit urb so we continue receiving IRQ data */
827 if (status != -ESHUTDOWN) { 833 if (status != -ESHUTDOWN && status != -ENOENT) {
828 urb->dev = serial->dev; 834 urb->dev = serial->dev;
829 err = usb_submit_urb(urb, GFP_ATOMIC); 835 err = usb_submit_urb(urb, GFP_ATOMIC);
830 if (err) 836 if (err)
@@ -843,7 +849,6 @@ static int option_write_room(struct tty_struct *tty)
843 849
844 portdata = usb_get_serial_port_data(port); 850 portdata = usb_get_serial_port_data(port);
845 851
846
847 for (i = 0; i < N_OUT_URB; i++) { 852 for (i = 0; i < N_OUT_URB; i++) {
848 this_urb = portdata->out_urbs[i]; 853 this_urb = portdata->out_urbs[i];
849 if (this_urb && !test_bit(i, &portdata->out_busy)) 854 if (this_urb && !test_bit(i, &portdata->out_busy))
@@ -1105,14 +1110,12 @@ bail_out_error:
1105 return 1; 1110 return 1;
1106} 1111}
1107 1112
1108static void option_shutdown(struct usb_serial *serial) 1113static void stop_read_write_urbs(struct usb_serial *serial)
1109{ 1114{
1110 int i, j; 1115 int i, j;
1111 struct usb_serial_port *port; 1116 struct usb_serial_port *port;
1112 struct option_port_private *portdata; 1117 struct option_port_private *portdata;
1113 1118
1114 dbg("%s", __func__);
1115
1116 /* Stop reading/writing urbs */ 1119 /* Stop reading/writing urbs */
1117 for (i = 0; i < serial->num_ports; ++i) { 1120 for (i = 0; i < serial->num_ports; ++i) {
1118 port = serial->port[i]; 1121 port = serial->port[i];
@@ -1122,6 +1125,17 @@ static void option_shutdown(struct usb_serial *serial)
1122 for (j = 0; j < N_OUT_URB; j++) 1125 for (j = 0; j < N_OUT_URB; j++)
1123 usb_kill_urb(portdata->out_urbs[j]); 1126 usb_kill_urb(portdata->out_urbs[j]);
1124 } 1127 }
1128}
1129
1130static void option_shutdown(struct usb_serial *serial)
1131{
1132 int i, j;
1133 struct usb_serial_port *port;
1134 struct option_port_private *portdata;
1135
1136 dbg("%s", __func__);
1137
1138 stop_read_write_urbs(serial);
1125 1139
1126 /* Now free them */ 1140 /* Now free them */
1127 for (i = 0; i < serial->num_ports; ++i) { 1141 for (i = 0; i < serial->num_ports; ++i) {
@@ -1152,6 +1166,66 @@ static void option_shutdown(struct usb_serial *serial)
1152 } 1166 }
1153} 1167}
1154 1168
1169static int option_suspend(struct usb_serial *serial, pm_message_t message)
1170{
1171 dbg("%s entered", __func__);
1172 stop_read_write_urbs(serial);
1173
1174 return 0;
1175}
1176
1177static int option_resume(struct usb_serial *serial)
1178{
1179 int err, i, j;
1180 struct usb_serial_port *port;
1181 struct urb *urb;
1182 struct option_port_private *portdata;
1183
1184 dbg("%s entered", __func__);
1185 /* get the interrupt URBs resubmitted unconditionally */
1186 for (i = 0; i < serial->num_ports; i++) {
1187 port = serial->port[i];
1188 if (!port->interrupt_in_urb) {
1189 dbg("%s: No interrupt URB for port %d\n", __func__, i);
1190 continue;
1191 }
1192 port->interrupt_in_urb->dev = serial->dev;
1193 err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
1194 dbg("Submitted interrupt URB for port %d (result %d)", i, err);
1195 if (err < 0) {
1196 err("%s: Error %d for interrupt URB of port%d",
1197 __func__, err, i);
1198 return err;
1199 }
1200 }
1201
1202 for (i = 0; i < serial->num_ports; i++) {
1203 /* walk all ports */
1204 port = serial->port[i];
1205 portdata = usb_get_serial_port_data(port);
1206 mutex_lock(&port->mutex);
1207
1208 /* skip closed ports */
1209 if (!port->port.count) {
1210 mutex_unlock(&port->mutex);
1211 continue;
1212 }
1213
1214 for (j = 0; j < N_IN_URB; j++) {
1215 urb = portdata->in_urbs[j];
1216 err = usb_submit_urb(urb, GFP_NOIO);
1217 if (err < 0) {
1218 mutex_unlock(&port->mutex);
1219 err("%s: Error %d for bulk URB %d",
1220 __func__, err, i);
1221 return err;
1222 }
1223 }
1224 mutex_unlock(&port->mutex);
1225 }
1226 return 0;
1227}
1228
1155MODULE_AUTHOR(DRIVER_AUTHOR); 1229MODULE_AUTHOR(DRIVER_AUTHOR);
1156MODULE_DESCRIPTION(DRIVER_DESC); 1230MODULE_DESCRIPTION(DRIVER_DESC);
1157MODULE_VERSION(DRIVER_VERSION); 1231MODULE_VERSION(DRIVER_VERSION);