aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc/usblcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/misc/usblcd.c')
-rw-r--r--drivers/usb/misc/usblcd.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 12bad8a205a7..504f7221b0d0 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -45,13 +45,13 @@ 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
51#define USB_LCD_CONCURRENT_WRITES 5 52#define USB_LCD_CONCURRENT_WRITES 5
52 53
53static struct usb_driver lcd_driver; 54static struct usb_driver lcd_driver;
54static DEFINE_MUTEX(usb_lcd_open_mutex);
55 55
56 56
57static void lcd_delete(struct kref *kref) 57static void lcd_delete(struct kref *kref)
@@ -68,35 +68,35 @@ static int lcd_open(struct inode *inode, struct file *file)
68{ 68{
69 struct usb_lcd *dev; 69 struct usb_lcd *dev;
70 struct usb_interface *interface; 70 struct usb_interface *interface;
71 int subminor; 71 int subminor, r;
72 int retval = 0;
73 72
74 subminor = iminor(inode); 73 subminor = iminor(inode);
75 74
76 mutex_lock(&usb_lcd_open_mutex);
77 interface = usb_find_interface(&lcd_driver, subminor); 75 interface = usb_find_interface(&lcd_driver, subminor);
78 if (!interface) { 76 if (!interface) {
79 err ("USBLCD: %s - error, can't find device for minor %d", 77 err ("USBLCD: %s - error, can't find device for minor %d",
80 __FUNCTION__, subminor); 78 __FUNCTION__, subminor);
81 retval = -ENODEV; 79 return -ENODEV;
82 goto exit;
83 } 80 }
84 81
85 dev = usb_get_intfdata(interface); 82 dev = usb_get_intfdata(interface);
86 if (!dev) { 83 if (!dev)
87 retval = -ENODEV; 84 return -ENODEV;
88 goto exit;
89 }
90 85
91 /* increment our usage count for the device */ 86 /* increment our usage count for the device */
92 kref_get(&dev->kref); 87 kref_get(&dev->kref);
93 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
94 /* save our object in the file's private structure */ 96 /* save our object in the file's private structure */
95 file->private_data = dev; 97 file->private_data = dev;
96 98
97exit: 99 return 0;
98 mutex_unlock(&usb_lcd_open_mutex);
99 return retval;
100} 100}
101 101
102static int lcd_release(struct inode *inode, struct file *file) 102static int lcd_release(struct inode *inode, struct file *file)
@@ -108,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file)
108 return -ENODEV; 108 return -ENODEV;
109 109
110 /* decrement the count on our device */ 110 /* decrement the count on our device */
111 usb_autopm_put_interface(dev->interface);
111 kref_put(&dev->kref, lcd_delete); 112 kref_put(&dev->kref, lcd_delete);
112 return 0; 113 return 0;
113} 114}
@@ -233,12 +234,14 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
233 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 234 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
234 buf, count, lcd_write_bulk_callback, dev); 235 buf, count, lcd_write_bulk_callback, dev);
235 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);
236 239
237 /* send the data out the bulk port */ 240 /* send the data out the bulk port */
238 retval = usb_submit_urb(urb, GFP_KERNEL); 241 retval = usb_submit_urb(urb, GFP_KERNEL);
239 if (retval) { 242 if (retval) {
240 err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval); 243 err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
241 goto error; 244 goto error_unanchor;
242 } 245 }
243 246
244 /* 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 */
@@ -246,7 +249,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
246 249
247exit: 250exit:
248 return count; 251 return count;
249 252error_unanchor:
253 usb_unanchor_urb(urb);
250error: 254error:
251 usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); 255 usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
252 usb_free_urb(urb); 256 usb_free_urb(urb);
@@ -291,6 +295,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
291 } 295 }
292 kref_init(&dev->kref); 296 kref_init(&dev->kref);
293 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);
294 299
295 dev->udev = usb_get_dev(interface_to_usbdev(interface)); 300 dev->udev = usb_get_dev(interface_to_usbdev(interface));
296 dev->interface = interface; 301 dev->interface = interface;
@@ -358,22 +363,41 @@ error:
358 return retval; 363 return retval;
359} 364}
360 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
361static void lcd_disconnect(struct usb_interface *interface) 390static void lcd_disconnect(struct usb_interface *interface)
362{ 391{
363 struct usb_lcd *dev; 392 struct usb_lcd *dev;
364 int minor = interface->minor; 393 int minor = interface->minor;
365 394
366 /* prevent skel_open() from racing skel_disconnect() */
367 mutex_lock(&usb_lcd_open_mutex);
368
369 dev = usb_get_intfdata(interface); 395 dev = usb_get_intfdata(interface);
370 usb_set_intfdata(interface, NULL); 396 usb_set_intfdata(interface, NULL);
371 397
372 /* give back our minor */ 398 /* give back our minor */
373 usb_deregister_dev(interface, &lcd_class); 399 usb_deregister_dev(interface, &lcd_class);
374 400
375 mutex_unlock(&usb_lcd_open_mutex);
376
377 /* decrement our usage count */ 401 /* decrement our usage count */
378 kref_put(&dev->kref, lcd_delete); 402 kref_put(&dev->kref, lcd_delete);
379 403
@@ -384,7 +408,10 @@ static struct usb_driver lcd_driver = {
384 .name = "usblcd", 408 .name = "usblcd",
385 .probe = lcd_probe, 409 .probe = lcd_probe,
386 .disconnect = lcd_disconnect, 410 .disconnect = lcd_disconnect,
411 .suspend = lcd_suspend,
412 .resume = lcd_resume,
387 .id_table = id_table, 413 .id_table = id_table,
414 .supports_autosuspend = 1,
388}; 415};
389 416
390static int __init usb_lcd_init(void) 417static int __init usb_lcd_init(void)