Commit 1365baf7249bb2d05e774e7681237b8e86f5007a

Authored by Oliver Neukum
Committed by Greg Kroah-Hartman
1 parent eedffd12e0

USB: autosuspend for cdc-acm

Here we go. This patch implements suspend/resume and autosuspend
for the CDC ACM driver.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 2 changed files with 79 additions and 15 deletions Side-by-side Diff

drivers/usb/class/cdc-acm.c
... ... @@ -496,10 +496,19 @@
496 496 otherwise it is scheduled, and with high data rates data can get lost. */
497 497 tty->low_latency = 1;
498 498  
  499 + if (usb_autopm_get_interface(acm->control)) {
  500 + mutex_unlock(&open_mutex);
  501 + return -EIO;
  502 + }
  503 +
  504 + mutex_lock(&acm->mutex);
  505 + mutex_unlock(&open_mutex);
499 506 if (acm->used++) {
  507 + usb_autopm_put_interface(acm->control);
500 508 goto done;
501 509 }
502 510  
  511 +
503 512 acm->ctrlurb->dev = acm->dev;
504 513 if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
505 514 dbg("usb_submit_urb(ctrl irq) failed");
506 515  
507 516  
... ... @@ -526,14 +535,15 @@
526 535  
527 536 done:
528 537 err_out:
529   - mutex_unlock(&open_mutex);
  538 + mutex_unlock(&acm->mutex);
530 539 return rv;
531 540  
532 541 full_bailout:
533 542 usb_kill_urb(acm->ctrlurb);
534 543 bail_out:
  544 + usb_autopm_put_interface(acm->control);
535 545 acm->used--;
536   - mutex_unlock(&open_mutex);
  546 + mutex_unlock(&acm->mutex);
537 547 return -EIO;
538 548 }
539 549  
... ... @@ -570,6 +580,7 @@
570 580 usb_kill_urb(acm->writeurb);
571 581 for (i = 0; i < nr; i++)
572 582 usb_kill_urb(acm->ru[i].urb);
  583 + usb_autopm_put_interface(acm->control);
573 584 } else
574 585 acm_tty_unregister(acm);
575 586 }
... ... @@ -980,6 +991,7 @@
980 991 spin_lock_init(&acm->throttle_lock);
981 992 spin_lock_init(&acm->write_lock);
982 993 spin_lock_init(&acm->read_lock);
  994 + mutex_init(&acm->mutex);
983 995 acm->write_ready = 1;
984 996 acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
985 997  
... ... @@ -1096,6 +1108,25 @@
1096 1108 return -ENOMEM;
1097 1109 }
1098 1110  
  1111 +static void stop_data_traffic(struct acm *acm)
  1112 +{
  1113 + int i;
  1114 +
  1115 + tasklet_disable(&acm->urb_task);
  1116 +
  1117 + usb_kill_urb(acm->ctrlurb);
  1118 + usb_kill_urb(acm->writeurb);
  1119 + for (i = 0; i < acm->rx_buflimit; i++)
  1120 + usb_kill_urb(acm->ru[i].urb);
  1121 +
  1122 + INIT_LIST_HEAD(&acm->filled_read_bufs);
  1123 + INIT_LIST_HEAD(&acm->spare_read_bufs);
  1124 +
  1125 + tasklet_enable(&acm->urb_task);
  1126 +
  1127 + cancel_work_sync(&acm->work);
  1128 +}
  1129 +
1099 1130 static void acm_disconnect(struct usb_interface *intf)
1100 1131 {
1101 1132 struct acm *acm = usb_get_intfdata(intf);
1102 1133  
... ... @@ -1123,20 +1154,8 @@
1123 1154 usb_set_intfdata(acm->control, NULL);
1124 1155 usb_set_intfdata(acm->data, NULL);
1125 1156  
1126   - tasklet_disable(&acm->urb_task);
  1157 + stop_data_traffic(acm);
1127 1158  
1128   - usb_kill_urb(acm->ctrlurb);
1129   - usb_kill_urb(acm->writeurb);
1130   - for (i = 0; i < acm->rx_buflimit; i++)
1131   - usb_kill_urb(acm->ru[i].urb);
1132   -
1133   - INIT_LIST_HEAD(&acm->filled_read_bufs);
1134   - INIT_LIST_HEAD(&acm->spare_read_bufs);
1135   -
1136   - tasklet_enable(&acm->urb_task);
1137   -
1138   - flush_scheduled_work(); /* wait for acm_softint */
1139   -
1140 1159 acm_write_buffers_free(acm);
1141 1160 usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
1142 1161 for (i = 0; i < acm->rx_buflimit; i++)
... ... @@ -1156,6 +1175,46 @@
1156 1175 tty_hangup(acm->tty);
1157 1176 }
1158 1177  
  1178 +static int acm_suspend(struct usb_interface *intf, pm_message_t message)
  1179 +{
  1180 + struct acm *acm = usb_get_intfdata(intf);
  1181 +
  1182 + if (acm->susp_count++)
  1183 + return 0;
  1184 + /*
  1185 + we treat opened interfaces differently,
  1186 + we must guard against open
  1187 + */
  1188 + mutex_lock(&acm->mutex);
  1189 +
  1190 + if (acm->used)
  1191 + stop_data_traffic(acm);
  1192 +
  1193 + mutex_unlock(&acm->mutex);
  1194 + return 0;
  1195 +}
  1196 +
  1197 +static int acm_resume(struct usb_interface *intf)
  1198 +{
  1199 + struct acm *acm = usb_get_intfdata(intf);
  1200 + int rv = 0;
  1201 +
  1202 + if (--acm->susp_count)
  1203 + return 0;
  1204 +
  1205 + mutex_lock(&acm->mutex);
  1206 + if (acm->used) {
  1207 + rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
  1208 + if (rv < 0)
  1209 + goto err_out;
  1210 +
  1211 + tasklet_schedule(&acm->urb_task);
  1212 + }
  1213 +
  1214 +err_out:
  1215 + mutex_unlock(&acm->mutex);
  1216 + return rv;
  1217 +}
1159 1218 /*
1160 1219 * USB driver structure.
1161 1220 */
1162 1221  
... ... @@ -1208,7 +1267,10 @@
1208 1267 .name = "cdc_acm",
1209 1268 .probe = acm_probe,
1210 1269 .disconnect = acm_disconnect,
  1270 + .suspend = acm_suspend,
  1271 + .resume = acm_resume,
1211 1272 .id_table = acm_ids,
  1273 + .supports_autosuspend = 1,
1212 1274 };
1213 1275  
1214 1276 /*
drivers/usb/class/cdc-acm.h
... ... @@ -107,6 +107,7 @@
107 107 int write_used; /* number of non-empty write buffers */
108 108 int write_ready; /* write urb is not running */
109 109 spinlock_t write_lock;
  110 + struct mutex mutex;
110 111 struct usb_cdc_line_coding line; /* bits, stop, parity */
111 112 struct work_struct work; /* work queue entry for line discipline waking up */
112 113 struct tasklet_struct urb_task; /* rx processing */
... ... @@ -120,6 +121,7 @@
120 121 unsigned char throttle; /* throttled by tty layer */
121 122 unsigned char clocal; /* termios CLOCAL */
122 123 unsigned int ctrl_caps; /* control capabilities from the class specific header */
  124 + unsigned int susp_count; /* number of suspended interfaces */
123 125 };
124 126  
125 127 #define CDC_DATA_INTERFACE_TYPE 0x0a