aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-06-13 11:13:31 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:38 -0400
commit7bbe990c989ee16f2c1be3e4ae28f8004bec788c (patch)
treec2ea2abc369f2cabeb46cb6c5d3125d3e58ca7e6 /drivers/usb
parent55b3fd41b0846929f68b5fb1058ad8077289f584 (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')
-rw-r--r--drivers/usb/misc/usblcd.c46
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
239exit: 250exit:
240 return count; 251 return count;
241 252error_unanchor:
253 usb_unanchor_urb(urb);
242error: 254error:
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
366static 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
375static 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
385static int lcd_resume (struct usb_interface *intf)
386{
387 return 0;
388}
389
353static void lcd_disconnect(struct usb_interface *interface) 390static 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
377static int __init usb_lcd_init(void) 417static int __init usb_lcd_init(void)