diff options
author | Oliver Neukum <oneukum@suse.de> | 2007-06-13 11:13:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:34:38 -0400 |
commit | 7bbe990c989ee16f2c1be3e4ae28f8004bec788c (patch) | |
tree | c2ea2abc369f2cabeb46cb6c5d3125d3e58ca7e6 /drivers/usb/misc/usblcd.c | |
parent | 55b3fd41b0846929f68b5fb1058ad8077289f584 (diff) |
USB: autosuspend for usblcd
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 <oneukum@suse.de>
Cc: Georges Toth <g.toth@e-biz.lu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/misc/usblcd.c')
-rw-r--r-- | 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 6e093c2aac2c..504f7221b0d0 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c | |||
@@ -45,6 +45,7 @@ struct usb_lcd { | |||
45 | struct kref kref; | 45 | struct kref kref; |
46 | struct semaphore limit_sem; /* to stop writes at full throttle from | 46 | struct semaphore limit_sem; /* to stop writes at full throttle from |
47 | * using up all RAM */ | 47 | * using up all RAM */ |
48 | struct usb_anchor submitted; /* URBs to wait for before suspend */ | ||
48 | }; | 49 | }; |
49 | #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) | 50 | #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) |
50 | 51 | ||
@@ -67,7 +68,7 @@ static int lcd_open(struct inode *inode, struct file *file) | |||
67 | { | 68 | { |
68 | struct usb_lcd *dev; | 69 | struct usb_lcd *dev; |
69 | struct usb_interface *interface; | 70 | struct usb_interface *interface; |
70 | int subminor; | 71 | int subminor, r; |
71 | 72 | ||
72 | subminor = iminor(inode); | 73 | subminor = iminor(inode); |
73 | 74 | ||
@@ -85,6 +86,13 @@ static int lcd_open(struct inode *inode, struct file *file) | |||
85 | /* increment our usage count for the device */ | 86 | /* increment our usage count for the device */ |
86 | kref_get(&dev->kref); | 87 | kref_get(&dev->kref); |
87 | 88 | ||
89 | /* grab a power reference */ | ||
90 | r = usb_autopm_get_interface(interface); | ||
91 | if (r < 0) { | ||
92 | kref_put(&dev->kref, lcd_delete); | ||
93 | return r; | ||
94 | } | ||
95 | |||
88 | /* save our object in the file's private structure */ | 96 | /* save our object in the file's private structure */ |
89 | file->private_data = dev; | 97 | file->private_data = dev; |
90 | 98 | ||
@@ -100,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file) | |||
100 | return -ENODEV; | 108 | return -ENODEV; |
101 | 109 | ||
102 | /* decrement the count on our device */ | 110 | /* decrement the count on our device */ |
111 | usb_autopm_put_interface(dev->interface); | ||
103 | kref_put(&dev->kref, lcd_delete); | 112 | kref_put(&dev->kref, lcd_delete); |
104 | return 0; | 113 | return 0; |
105 | } | 114 | } |
@@ -225,12 +234,14 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz | |||
225 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), | 234 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), |
226 | buf, count, lcd_write_bulk_callback, dev); | 235 | buf, count, lcd_write_bulk_callback, dev); |
227 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 236 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
237 | |||
238 | usb_anchor_urb(urb, &dev->submitted); | ||
228 | 239 | ||
229 | /* send the data out the bulk port */ | 240 | /* send the data out the bulk port */ |
230 | retval = usb_submit_urb(urb, GFP_KERNEL); | 241 | retval = usb_submit_urb(urb, GFP_KERNEL); |
231 | if (retval) { | 242 | if (retval) { |
232 | err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval); | 243 | err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval); |
233 | goto error; | 244 | goto error_unanchor; |
234 | } | 245 | } |
235 | 246 | ||
236 | /* release our reference to this urb, the USB core will eventually free it entirely */ | 247 | /* 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 | |||
238 | 249 | ||
239 | exit: | 250 | exit: |
240 | return count; | 251 | return count; |
241 | 252 | error_unanchor: | |
253 | usb_unanchor_urb(urb); | ||
242 | error: | 254 | error: |
243 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); | 255 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); |
244 | usb_free_urb(urb); | 256 | usb_free_urb(urb); |
@@ -283,6 +295,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id | |||
283 | } | 295 | } |
284 | kref_init(&dev->kref); | 296 | kref_init(&dev->kref); |
285 | sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); | 297 | sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); |
298 | init_usb_anchor(&dev->submitted); | ||
286 | 299 | ||
287 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); | 300 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); |
288 | dev->interface = interface; | 301 | dev->interface = interface; |
@@ -350,6 +363,30 @@ error: | |||
350 | return retval; | 363 | return retval; |
351 | } | 364 | } |
352 | 365 | ||
366 | static void lcd_draw_down(struct usb_lcd *dev) | ||
367 | { | ||
368 | int time; | ||
369 | |||
370 | time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); | ||
371 | if (!time) | ||
372 | usb_kill_anchored_urbs(&dev->submitted); | ||
373 | } | ||
374 | |||
375 | static int lcd_suspend(struct usb_interface *intf, pm_message_t message) | ||
376 | { | ||
377 | struct usb_lcd *dev = usb_get_intfdata(intf); | ||
378 | |||
379 | if (!dev) | ||
380 | return 0; | ||
381 | lcd_draw_down(dev); | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int lcd_resume (struct usb_interface *intf) | ||
386 | { | ||
387 | return 0; | ||
388 | } | ||
389 | |||
353 | static void lcd_disconnect(struct usb_interface *interface) | 390 | static void lcd_disconnect(struct usb_interface *interface) |
354 | { | 391 | { |
355 | struct usb_lcd *dev; | 392 | struct usb_lcd *dev; |
@@ -371,7 +408,10 @@ static struct usb_driver lcd_driver = { | |||
371 | .name = "usblcd", | 408 | .name = "usblcd", |
372 | .probe = lcd_probe, | 409 | .probe = lcd_probe, |
373 | .disconnect = lcd_disconnect, | 410 | .disconnect = lcd_disconnect, |
411 | .suspend = lcd_suspend, | ||
412 | .resume = lcd_resume, | ||
374 | .id_table = id_table, | 413 | .id_table = id_table, |
414 | .supports_autosuspend = 1, | ||
375 | }; | 415 | }; |
376 | 416 | ||
377 | static int __init usb_lcd_init(void) | 417 | static int __init usb_lcd_init(void) |