[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.