[PATCH]suspend/resume for cdc_acm
Oliver Neukum <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi, this patch implements suspend() and resume() methods for CDC ACM devices. Regards Oliver Signed-off-by: Oliver Neukum <[email protected]> ---- --- linux-2.6.23-rc9/drivers/usb/class/cdc-acm.h 2007-07-09 01:32:17.000000000 +0200 +++ acm/drivers/usb/class/cdc-acm.h 2007-10-08 11:20:39.000000000 +0200 @@ -120,6 +120,7 @@ struct acm { unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned int ctrl_caps; /* control capabilities from the class specific header */ + unsigned int susp_count; /* number of suspended interfaces */ }; #define CDC_DATA_INTERFACE_TYPE 0x0a --- linux-2.6.23-rc9/drivers/usb/class/cdc-acm.c 2007-10-10 10:28:50.000000000 +0200 +++ acm/drivers/usb/class/cdc-acm.c 2007-10-08 11:20:55.000000000 +0200 @@ -1096,6 +1096,25 @@ alloc_fail: return -ENOMEM; } +static void stop_data_traffic(struct acm *acm) +{ + int i; + + tasklet_disable(&acm->urb_task); + + usb_kill_urb(acm->ctrlurb); + usb_kill_urb(acm->writeurb); + for (i = 0; i < acm->rx_buflimit; i++) + usb_kill_urb(acm->ru[i].urb); + + INIT_LIST_HEAD(&acm->filled_read_bufs); + INIT_LIST_HEAD(&acm->spare_read_bufs); + + tasklet_enable(&acm->urb_task); + + flush_scheduled_work(); /* wait for acm_softint */ +} + static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); @@ -1123,19 +1142,7 @@ static void acm_disconnect(struct usb_in usb_set_intfdata(acm->control, NULL); usb_set_intfdata(acm->data, NULL); - tasklet_disable(&acm->urb_task); - - usb_kill_urb(acm->ctrlurb); - usb_kill_urb(acm->writeurb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->ru[i].urb); - - INIT_LIST_HEAD(&acm->filled_read_bufs); - INIT_LIST_HEAD(&acm->spare_read_bufs); - - tasklet_enable(&acm->urb_task); - - flush_scheduled_work(); /* wait for acm_softint */ + stop_data_traffic(acm); acm_write_buffers_free(acm); usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); @@ -1156,6 +1163,46 @@ static void acm_disconnect(struct usb_in tty_hangup(acm->tty); } +static int acm_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct acm *acm = usb_get_intfdata(intf); + + if (acm->susp_count++) + return 0; + /* + we treat opened interface differently, + we must giard against open + */ + mutex_lock(&open_mutex); + + if (acm->used) + stop_data_traffic(acm); + + mutex_unlock(&open_mutex); + return 0; +} + +static int acm_resume(struct usb_interface *intf) +{ + struct acm *acm = usb_get_intfdata(intf); + int rv = 0; + + if (--acm->susp_count) + return 0; + + mutex_lock(&open_mutex); + if (acm->used) { + rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); + if (rv < 0) + goto err_out; + + tasklet_schedule(&acm->urb_task); + } + +err_out: + mutex_unlock(&open_mutex); + return rv; +} /* * USB driver structure. */ @@ -1208,6 +1255,8 @@ static struct usb_driver acm_driver = { .name = "cdc_acm", .probe = acm_probe, .disconnect = acm_disconnect, + .suspend = acm_suspend, + .resume = acm_resume, .id_table = acm_ids, }; ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel