mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-05-03 13:53:48 +00:00
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>
This commit is contained in:
parent
55b3fd41b0
commit
7bbe990c98
1 changed files with 43 additions and 3 deletions
|
@ -45,6 +45,7 @@ struct usb_lcd {
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
struct semaphore limit_sem; /* to stop writes at full throttle from
|
struct semaphore limit_sem; /* to stop writes at full throttle from
|
||||||
* using up all RAM */
|
* 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)
|
#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_lcd *dev;
|
||||||
struct usb_interface *interface;
|
struct usb_interface *interface;
|
||||||
int subminor;
|
int subminor, r;
|
||||||
|
|
||||||
subminor = iminor(inode);
|
subminor = iminor(inode);
|
||||||
|
|
||||||
|
@ -85,6 +86,13 @@ static int lcd_open(struct inode *inode, struct file *file)
|
||||||
/* increment our usage count for the device */
|
/* increment our usage count for the device */
|
||||||
kref_get(&dev->kref);
|
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 */
|
/* save our object in the file's private structure */
|
||||||
file->private_data = dev;
|
file->private_data = dev;
|
||||||
|
|
||||||
|
@ -100,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* decrement the count on our device */
|
/* decrement the count on our device */
|
||||||
|
usb_autopm_put_interface(dev->interface);
|
||||||
kref_put(&dev->kref, lcd_delete);
|
kref_put(&dev->kref, lcd_delete);
|
||||||
return 0;
|
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),
|
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
|
||||||
buf, count, lcd_write_bulk_callback, dev);
|
buf, count, lcd_write_bulk_callback, dev);
|
||||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||||
|
|
||||||
|
usb_anchor_urb(urb, &dev->submitted);
|
||||||
|
|
||||||
/* send the data out the bulk port */
|
/* send the data out the bulk port */
|
||||||
retval = usb_submit_urb(urb, GFP_KERNEL);
|
retval = usb_submit_urb(urb, GFP_KERNEL);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, 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 */
|
/* 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:
|
exit:
|
||||||
return count;
|
return count;
|
||||||
|
error_unanchor:
|
||||||
|
usb_unanchor_urb(urb);
|
||||||
error:
|
error:
|
||||||
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
|
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
|
||||||
usb_free_urb(urb);
|
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);
|
kref_init(&dev->kref);
|
||||||
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
|
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
|
||||||
|
init_usb_anchor(&dev->submitted);
|
||||||
|
|
||||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||||
dev->interface = interface;
|
dev->interface = interface;
|
||||||
|
@ -350,6 +363,30 @@ error:
|
||||||
return retval;
|
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)
|
static void lcd_disconnect(struct usb_interface *interface)
|
||||||
{
|
{
|
||||||
struct usb_lcd *dev;
|
struct usb_lcd *dev;
|
||||||
|
@ -371,7 +408,10 @@ static struct usb_driver lcd_driver = {
|
||||||
.name = "usblcd",
|
.name = "usblcd",
|
||||||
.probe = lcd_probe,
|
.probe = lcd_probe,
|
||||||
.disconnect = lcd_disconnect,
|
.disconnect = lcd_disconnect,
|
||||||
|
.suspend = lcd_suspend,
|
||||||
|
.resume = lcd_resume,
|
||||||
.id_table = id_table,
|
.id_table = id_table,
|
||||||
|
.supports_autosuspend = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init usb_lcd_init(void)
|
static int __init usb_lcd_init(void)
|
||||||
|
|
Loading…
Add table
Reference in a new issue