[PATCH 115/149] USB: autosuspend for usblcd

Greg Kroah-Hartman <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
From: Oliver Neukum <[email protected]>

this patch implements autosuspend for the usblcd driver. It uses
the new usb_anchor infrastructure. Many thanks to Georges for testing.

Signed-off-by: Oliver Neukum <[email protected]>
Cc: Georges Toth <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 drivers/usb/misc/usblcd.c |   46 ++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 6e093c2..504f722 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -45,6 +45,7 @@ struct usb_lcd {
 	struct kref		kref;
 	struct semaphore	limit_sem;		/* to stop writes at full throttle from
 							 * using up all RAM */
+	struct usb_anchor	submitted;		/* URBs to wait for before suspend */
 };
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 
@@ -67,7 +68,7 @@ static int lcd_open(struct inode *inode, struct file *file)
 {
 	struct usb_lcd *dev;
 	struct usb_interface *interface;
-	int subminor;
+	int subminor, r;
 
 	subminor = iminor(inode);
 
@@ -85,6 +86,13 @@ static int lcd_open(struct inode *inode, struct file *file)
 	/* increment our usage count for the device */
 	kref_get(&dev->kref);
 
+	/* grab a power reference */
+	r = usb_autopm_get_interface(interface);
+	if (r < 0) {
+		kref_put(&dev->kref, lcd_delete);
+		return r;
+	}
+
 	/* save our object in the file's private structure */
 	file->private_data = dev;
 
@@ -100,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file)
 		return -ENODEV;
 
 	/* decrement the count on our device */
+	usb_autopm_put_interface(dev->interface);
 	kref_put(&dev->kref, lcd_delete);
 	return 0;
 }
@@ -225,12 +234,14 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
 			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
 			  buf, count, lcd_write_bulk_callback, dev);
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	usb_anchor_urb(urb, &dev->submitted);
 	
 	/* send the data out the bulk port */
 	retval = usb_submit_urb(urb, GFP_KERNEL);
 	if (retval) {
 		err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
-		goto error;
+		goto error_unanchor;
 	}
 	
 	/* release our reference to this urb, the USB core will eventually free it entirely */
@@ -238,7 +249,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
 
 exit:
 	return count;
-
+error_unanchor:
+	usb_unanchor_urb(urb);
 error:
 	usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
 	usb_free_urb(urb);
@@ -283,6 +295,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
 	}
 	kref_init(&dev->kref);
 	sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
+	init_usb_anchor(&dev->submitted);
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
 	dev->interface = interface;
@@ -350,6 +363,30 @@ error:
 	return retval;
 }
 
+static void lcd_draw_down(struct usb_lcd *dev)
+{
+	int time;
+
+	time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
+	if (!time)
+		usb_kill_anchored_urbs(&dev->submitted);
+}
+
+static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usb_lcd *dev = usb_get_intfdata(intf);
+
+	if (!dev)
+		return 0;
+	lcd_draw_down(dev);
+	return 0;
+}
+
+static int lcd_resume (struct usb_interface *intf)
+{
+	return 0;
+}
+
 static void lcd_disconnect(struct usb_interface *interface)
 {
 	struct usb_lcd *dev;
@@ -371,7 +408,10 @@ static struct usb_driver lcd_driver = {
 	.name =		"usblcd",
 	.probe =	lcd_probe,
 	.disconnect =	lcd_disconnect,
+	.suspend =	lcd_suspend,
+	.resume =	lcd_resume,
 	.id_table =	id_table,
+	.supports_autosuspend = 1,
 };
 
 static int __init usb_lcd_init(void)
-- 
1.5.2.2


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[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.