diff options
author | Oliver Neukum <oliver@neukum.org> | 2009-07-01 10:00:32 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:25 -0400 |
commit | 383cedc3bb435de7a27d31a92d622413daa5cb20 (patch) | |
tree | 1e2a24ac637c3287f9dac5ee0d44cded3c84dce3 /drivers | |
parent | ab26d20f3ef1105d889f702cd01fba8c6fb32f73 (diff) |
USB: serial: full autosuspend support for the option driver
this adds autosupport usable even in an always online mode.
- enables remote wakeup on open
- autoresume for sending
- timeout based autosuspend if nothing is sent or recieved
- autosuspend without remote wakeup support on open/close
Signed-off-by: Oliver Neukum <oliver@neukum.org>
Tested-off-by: Zhao Ming <zhao.ming9@zte.com.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/serial/option.c | 134 |
1 files changed, 116 insertions, 18 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 67862d71f068..f66e39883218 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -596,6 +596,7 @@ static struct usb_driver option_driver = { | |||
596 | #ifdef CONFIG_PM | 596 | #ifdef CONFIG_PM |
597 | .suspend = usb_serial_suspend, | 597 | .suspend = usb_serial_suspend, |
598 | .resume = usb_serial_resume, | 598 | .resume = usb_serial_resume, |
599 | .supports_autosuspend = 1, | ||
599 | #endif | 600 | #endif |
600 | .id_table = option_ids, | 601 | .id_table = option_ids, |
601 | .no_dynamic_id = 1, | 602 | .no_dynamic_id = 1, |
@@ -643,6 +644,12 @@ static int debug; | |||
643 | #define IN_BUFLEN 4096 | 644 | #define IN_BUFLEN 4096 |
644 | #define OUT_BUFLEN 4096 | 645 | #define OUT_BUFLEN 4096 |
645 | 646 | ||
647 | struct option_intf_private { | ||
648 | spinlock_t susp_lock; | ||
649 | unsigned int suspended:1; | ||
650 | int in_flight; | ||
651 | }; | ||
652 | |||
646 | struct option_port_private { | 653 | struct option_port_private { |
647 | /* Input endpoints and buffer for this port */ | 654 | /* Input endpoints and buffer for this port */ |
648 | struct urb *in_urbs[N_IN_URB]; | 655 | struct urb *in_urbs[N_IN_URB]; |
@@ -651,6 +658,8 @@ struct option_port_private { | |||
651 | struct urb *out_urbs[N_OUT_URB]; | 658 | struct urb *out_urbs[N_OUT_URB]; |
652 | u8 *out_buffer[N_OUT_URB]; | 659 | u8 *out_buffer[N_OUT_URB]; |
653 | unsigned long out_busy; /* Bit vector of URBs in use */ | 660 | unsigned long out_busy; /* Bit vector of URBs in use */ |
661 | int opened; | ||
662 | struct usb_anchor delayed; | ||
654 | 663 | ||
655 | /* Settings for the port */ | 664 | /* Settings for the port */ |
656 | int rts_state; /* Handshaking pins (outputs) */ | 665 | int rts_state; /* Handshaking pins (outputs) */ |
@@ -697,12 +706,17 @@ module_exit(option_exit); | |||
697 | static int option_probe(struct usb_serial *serial, | 706 | static int option_probe(struct usb_serial *serial, |
698 | const struct usb_device_id *id) | 707 | const struct usb_device_id *id) |
699 | { | 708 | { |
709 | struct option_intf_private *data; | ||
700 | /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ | 710 | /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ |
701 | if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && | 711 | if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && |
702 | serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && | 712 | serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && |
703 | serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) | 713 | serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) |
704 | return -ENODEV; | 714 | return -ENODEV; |
705 | 715 | ||
716 | data = serial->private = kzalloc(sizeof(struct option_intf_private), GFP_KERNEL); | ||
717 | if (!data) | ||
718 | return -ENOMEM; | ||
719 | spin_lock_init(&data->susp_lock); | ||
706 | return 0; | 720 | return 0; |
707 | } | 721 | } |
708 | 722 | ||
@@ -759,12 +773,15 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
759 | const unsigned char *buf, int count) | 773 | const unsigned char *buf, int count) |
760 | { | 774 | { |
761 | struct option_port_private *portdata; | 775 | struct option_port_private *portdata; |
776 | struct option_intf_private *intfdata; | ||
762 | int i; | 777 | int i; |
763 | int left, todo; | 778 | int left, todo; |
764 | struct urb *this_urb = NULL; /* spurious */ | 779 | struct urb *this_urb = NULL; /* spurious */ |
765 | int err; | 780 | int err; |
781 | unsigned long flags; | ||
766 | 782 | ||
767 | portdata = usb_get_serial_port_data(port); | 783 | portdata = usb_get_serial_port_data(port); |
784 | intfdata = port->serial->private; | ||
768 | 785 | ||
769 | dbg("%s: write (%d chars)", __func__, count); | 786 | dbg("%s: write (%d chars)", __func__, count); |
770 | 787 | ||
@@ -786,17 +803,33 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
786 | dbg("%s: endpoint %d buf %d", __func__, | 803 | dbg("%s: endpoint %d buf %d", __func__, |
787 | usb_pipeendpoint(this_urb->pipe), i); | 804 | usb_pipeendpoint(this_urb->pipe), i); |
788 | 805 | ||
806 | err = usb_autopm_get_interface_async(port->serial->interface); | ||
807 | if (err < 0) | ||
808 | break; | ||
809 | |||
789 | /* send the data */ | 810 | /* send the data */ |
790 | memcpy(this_urb->transfer_buffer, buf, todo); | 811 | memcpy(this_urb->transfer_buffer, buf, todo); |
791 | this_urb->transfer_buffer_length = todo; | 812 | this_urb->transfer_buffer_length = todo; |
792 | 813 | ||
793 | err = usb_submit_urb(this_urb, GFP_ATOMIC); | 814 | spin_lock_irqsave(&intfdata->susp_lock, flags); |
794 | if (err) { | 815 | if (intfdata->suspended) { |
795 | dbg("usb_submit_urb %p (write bulk) failed " | 816 | usb_anchor_urb(this_urb, &portdata->delayed); |
796 | "(%d)", this_urb, err); | 817 | spin_unlock_irqrestore(&intfdata->susp_lock, flags); |
797 | clear_bit(i, &portdata->out_busy); | 818 | } else { |
798 | continue; | 819 | intfdata->in_flight++; |
820 | spin_unlock_irqrestore(&intfdata->susp_lock, flags); | ||
821 | err = usb_submit_urb(this_urb, GFP_ATOMIC); | ||
822 | if (err) { | ||
823 | dbg("usb_submit_urb %p (write bulk) failed " | ||
824 | "(%d)", this_urb, err); | ||
825 | clear_bit(i, &portdata->out_busy); | ||
826 | spin_lock_irqsave(&intfdata->susp_lock, flags); | ||
827 | intfdata->in_flight--; | ||
828 | spin_unlock_irqrestore(&intfdata->susp_lock, flags); | ||
829 | continue; | ||
830 | } | ||
799 | } | 831 | } |
832 | |||
800 | portdata->tx_start_time[i] = jiffies; | 833 | portdata->tx_start_time[i] = jiffies; |
801 | buf += todo; | 834 | buf += todo; |
802 | left -= todo; | 835 | left -= todo; |
@@ -840,7 +873,10 @@ static void option_indat_callback(struct urb *urb) | |||
840 | if (err) | 873 | if (err) |
841 | printk(KERN_ERR "%s: resubmit read urb failed. " | 874 | printk(KERN_ERR "%s: resubmit read urb failed. " |
842 | "(%d)", __func__, err); | 875 | "(%d)", __func__, err); |
876 | else | ||
877 | usb_mark_last_busy(port->serial->dev); | ||
843 | } | 878 | } |
879 | |||
844 | } | 880 | } |
845 | return; | 881 | return; |
846 | } | 882 | } |
@@ -849,15 +885,21 @@ static void option_outdat_callback(struct urb *urb) | |||
849 | { | 885 | { |
850 | struct usb_serial_port *port; | 886 | struct usb_serial_port *port; |
851 | struct option_port_private *portdata; | 887 | struct option_port_private *portdata; |
888 | struct option_intf_private *intfdata; | ||
852 | int i; | 889 | int i; |
853 | 890 | ||
854 | dbg("%s", __func__); | 891 | dbg("%s", __func__); |
855 | 892 | ||
856 | port = urb->context; | 893 | port = urb->context; |
894 | intfdata = port->serial->private; | ||
857 | 895 | ||
858 | usb_serial_port_softint(port); | 896 | usb_serial_port_softint(port); |
859 | 897 | usb_autopm_put_interface_async(port->serial->interface); | |
860 | portdata = usb_get_serial_port_data(port); | 898 | portdata = usb_get_serial_port_data(port); |
899 | spin_lock(&intfdata->susp_lock); | ||
900 | intfdata->in_flight--; | ||
901 | spin_unlock(&intfdata->susp_lock); | ||
902 | |||
861 | for (i = 0; i < N_OUT_URB; ++i) { | 903 | for (i = 0; i < N_OUT_URB; ++i) { |
862 | if (portdata->out_urbs[i] == urb) { | 904 | if (portdata->out_urbs[i] == urb) { |
863 | smp_mb__before_clear_bit(); | 905 | smp_mb__before_clear_bit(); |
@@ -967,10 +1009,13 @@ static int option_chars_in_buffer(struct tty_struct *tty) | |||
967 | static int option_open(struct tty_struct *tty, struct usb_serial_port *port) | 1009 | static int option_open(struct tty_struct *tty, struct usb_serial_port *port) |
968 | { | 1010 | { |
969 | struct option_port_private *portdata; | 1011 | struct option_port_private *portdata; |
1012 | struct option_intf_private *intfdata; | ||
1013 | struct usb_serial *serial = port->serial; | ||
970 | int i, err; | 1014 | int i, err; |
971 | struct urb *urb; | 1015 | struct urb *urb; |
972 | 1016 | ||
973 | portdata = usb_get_serial_port_data(port); | 1017 | portdata = usb_get_serial_port_data(port); |
1018 | intfdata = serial->private; | ||
974 | 1019 | ||
975 | dbg("%s", __func__); | 1020 | dbg("%s", __func__); |
976 | 1021 | ||
@@ -989,6 +1034,12 @@ static int option_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
989 | 1034 | ||
990 | option_send_setup(port); | 1035 | option_send_setup(port); |
991 | 1036 | ||
1037 | serial->interface->needs_remote_wakeup = 1; | ||
1038 | spin_lock_irq(&intfdata->susp_lock); | ||
1039 | portdata->opened = 1; | ||
1040 | spin_unlock_irq(&intfdata->susp_lock); | ||
1041 | usb_autopm_put_interface(serial->interface); | ||
1042 | |||
992 | return 0; | 1043 | return 0; |
993 | } | 1044 | } |
994 | 1045 | ||
@@ -1013,16 +1064,23 @@ static void option_close(struct usb_serial_port *port) | |||
1013 | int i; | 1064 | int i; |
1014 | struct usb_serial *serial = port->serial; | 1065 | struct usb_serial *serial = port->serial; |
1015 | struct option_port_private *portdata; | 1066 | struct option_port_private *portdata; |
1067 | struct option_intf_private *intfdata = port->serial->private; | ||
1016 | 1068 | ||
1017 | dbg("%s", __func__); | 1069 | dbg("%s", __func__); |
1018 | portdata = usb_get_serial_port_data(port); | 1070 | portdata = usb_get_serial_port_data(port); |
1019 | 1071 | ||
1020 | if (serial->dev) { | 1072 | if (serial->dev) { |
1021 | /* Stop reading/writing urbs */ | 1073 | /* Stop reading/writing urbs */ |
1074 | spin_lock_irq(&intfdata->susp_lock); | ||
1075 | portdata->opened = 0; | ||
1076 | spin_unlock_irq(&intfdata->susp_lock); | ||
1077 | |||
1022 | for (i = 0; i < N_IN_URB; i++) | 1078 | for (i = 0; i < N_IN_URB; i++) |
1023 | usb_kill_urb(portdata->in_urbs[i]); | 1079 | usb_kill_urb(portdata->in_urbs[i]); |
1024 | for (i = 0; i < N_OUT_URB; i++) | 1080 | for (i = 0; i < N_OUT_URB; i++) |
1025 | usb_kill_urb(portdata->out_urbs[i]); | 1081 | usb_kill_urb(portdata->out_urbs[i]); |
1082 | usb_autopm_get_interface(serial->interface); | ||
1083 | serial->interface->needs_remote_wakeup = 0; | ||
1026 | } | 1084 | } |
1027 | } | 1085 | } |
1028 | 1086 | ||
@@ -1127,6 +1185,7 @@ static int option_startup(struct usb_serial *serial) | |||
1127 | __func__, i); | 1185 | __func__, i); |
1128 | return 1; | 1186 | return 1; |
1129 | } | 1187 | } |
1188 | init_usb_anchor(&portdata->delayed); | ||
1130 | 1189 | ||
1131 | for (j = 0; j < N_IN_URB; j++) { | 1190 | for (j = 0; j < N_IN_URB; j++) { |
1132 | buffer = (u8 *)__get_free_page(GFP_KERNEL); | 1191 | buffer = (u8 *)__get_free_page(GFP_KERNEL); |
@@ -1229,18 +1288,52 @@ static void option_release(struct usb_serial *serial) | |||
1229 | #ifdef CONFIG_PM | 1288 | #ifdef CONFIG_PM |
1230 | static int option_suspend(struct usb_serial *serial, pm_message_t message) | 1289 | static int option_suspend(struct usb_serial *serial, pm_message_t message) |
1231 | { | 1290 | { |
1291 | struct option_intf_private *intfdata = serial->private; | ||
1292 | int b; | ||
1293 | |||
1232 | dbg("%s entered", __func__); | 1294 | dbg("%s entered", __func__); |
1295 | |||
1296 | if (serial->dev->auto_pm) { | ||
1297 | spin_lock_irq(&intfdata->susp_lock); | ||
1298 | b = intfdata->in_flight; | ||
1299 | spin_unlock_irq(&intfdata->susp_lock); | ||
1300 | |||
1301 | if (b) | ||
1302 | return -EBUSY; | ||
1303 | } | ||
1304 | |||
1305 | spin_lock_irq(&intfdata->susp_lock); | ||
1306 | intfdata->suspended = 1; | ||
1307 | spin_unlock_irq(&intfdata->susp_lock); | ||
1233 | stop_read_write_urbs(serial); | 1308 | stop_read_write_urbs(serial); |
1234 | 1309 | ||
1235 | return 0; | 1310 | return 0; |
1236 | } | 1311 | } |
1237 | 1312 | ||
1313 | static void play_delayed(struct usb_serial_port *port) | ||
1314 | { | ||
1315 | struct option_intf_private *data; | ||
1316 | struct option_port_private *portdata; | ||
1317 | struct urb *urb; | ||
1318 | int err; | ||
1319 | |||
1320 | portdata = usb_get_serial_port_data(port); | ||
1321 | data = port->serial->private; | ||
1322 | while ((urb = usb_get_from_anchor(&portdata->delayed))) { | ||
1323 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
1324 | if (!err) | ||
1325 | data->in_flight++; | ||
1326 | } | ||
1327 | } | ||
1328 | |||
1238 | static int option_resume(struct usb_serial *serial) | 1329 | static int option_resume(struct usb_serial *serial) |
1239 | { | 1330 | { |
1240 | int err, i, j; | 1331 | int i, j; |
1241 | struct usb_serial_port *port; | 1332 | struct usb_serial_port *port; |
1242 | struct urb *urb; | 1333 | struct option_intf_private *intfdata = serial->private; |
1243 | struct option_port_private *portdata; | 1334 | struct option_port_private *portdata; |
1335 | struct urb *urb; | ||
1336 | int err = 0; | ||
1244 | 1337 | ||
1245 | dbg("%s entered", __func__); | 1338 | dbg("%s entered", __func__); |
1246 | /* get the interrupt URBs resubmitted unconditionally */ | 1339 | /* get the interrupt URBs resubmitted unconditionally */ |
@@ -1255,7 +1348,7 @@ static int option_resume(struct usb_serial *serial) | |||
1255 | if (err < 0) { | 1348 | if (err < 0) { |
1256 | err("%s: Error %d for interrupt URB of port%d", | 1349 | err("%s: Error %d for interrupt URB of port%d", |
1257 | __func__, err, i); | 1350 | __func__, err, i); |
1258 | return err; | 1351 | goto err_out; |
1259 | } | 1352 | } |
1260 | } | 1353 | } |
1261 | 1354 | ||
@@ -1263,27 +1356,32 @@ static int option_resume(struct usb_serial *serial) | |||
1263 | /* walk all ports */ | 1356 | /* walk all ports */ |
1264 | port = serial->port[i]; | 1357 | port = serial->port[i]; |
1265 | portdata = usb_get_serial_port_data(port); | 1358 | portdata = usb_get_serial_port_data(port); |
1266 | mutex_lock(&port->mutex); | ||
1267 | 1359 | ||
1268 | /* skip closed ports */ | 1360 | /* skip closed ports */ |
1269 | if (!port->port.count) { | 1361 | spin_lock_irq(&intfdata->susp_lock); |
1270 | mutex_unlock(&port->mutex); | 1362 | if (!portdata->opened) { |
1363 | spin_unlock_irq(&intfdata->susp_lock); | ||
1271 | continue; | 1364 | continue; |
1272 | } | 1365 | } |
1273 | 1366 | ||
1274 | for (j = 0; j < N_IN_URB; j++) { | 1367 | for (j = 0; j < N_IN_URB; j++) { |
1275 | urb = portdata->in_urbs[j]; | 1368 | urb = portdata->in_urbs[j]; |
1276 | err = usb_submit_urb(urb, GFP_NOIO); | 1369 | err = usb_submit_urb(urb, GFP_ATOMIC); |
1277 | if (err < 0) { | 1370 | if (err < 0) { |
1278 | mutex_unlock(&port->mutex); | ||
1279 | err("%s: Error %d for bulk URB %d", | 1371 | err("%s: Error %d for bulk URB %d", |
1280 | __func__, err, i); | 1372 | __func__, err, i); |
1281 | return err; | 1373 | spin_unlock_irq(&intfdata->susp_lock); |
1374 | goto err_out; | ||
1282 | } | 1375 | } |
1283 | } | 1376 | } |
1284 | mutex_unlock(&port->mutex); | 1377 | play_delayed(port); |
1378 | spin_unlock_irq(&intfdata->susp_lock); | ||
1285 | } | 1379 | } |
1286 | return 0; | 1380 | spin_lock_irq(&intfdata->susp_lock); |
1381 | intfdata->suspended = 0; | ||
1382 | spin_unlock_irq(&intfdata->susp_lock); | ||
1383 | err_out: | ||
1384 | return err; | ||
1287 | } | 1385 | } |
1288 | #endif | 1386 | #endif |
1289 | 1387 | ||