From 57566ad2d83f58c02e191aa7f4d7cddad3f92618 Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Sat, 9 Feb 2008 16:08:24 -0300 Subject: [PATCH] V4L/DVB (7189): autosuspend support Together with Oliver Neukum from Novell, USB autosuspend support was added. Signed-off-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si470x.c | 83 +++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index c72a9e7ad8..649f14d2c0 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -81,6 +81,10 @@ * - racy interruptible_sleep_on(), * replaced with wait_event_interruptible() * - handle signals in read() + * 2008-02-08 Tobias Lorenz + * Oliver Neukum + * Version 1.0.7 + * - usb autosuspend support * * ToDo: * - add seeking support @@ -415,6 +419,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); struct si470x_device { /* reference to USB and video device */ struct usb_device *usbdev; + struct usb_interface *intf; struct video_device *videodev; /* driver management */ @@ -762,9 +767,17 @@ static int si470x_stop(struct si470x_device *radio) */ static int si470x_rds_on(struct si470x_device *radio) { + int retval; + /* sysconfig 1 */ + mutex_lock(&radio->lock); radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; - return si470x_set_register(radio, SYSCONFIG1); + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; + mutex_unlock(&radio->lock); + + return retval; } @@ -961,10 +974,22 @@ static unsigned int si470x_fops_poll(struct file *file, static int si470x_fops_open(struct inode *inode, struct file *file) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; radio->users++; - if (radio->users == 1) - return si470x_start(radio); + + retval = usb_autopm_get_interface(radio->intf); + if (retval < 0) { + radio->users--; + return -EIO; + } + + if (radio->users == 1) { + retval = si470x_start(radio); + if (retval < 0) + usb_autopm_put_interface(radio->intf); + return retval; + } return 0; } @@ -976,6 +1001,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file) static int si470x_fops_release(struct inode *inode, struct file *file) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; if (!radio) return -ENODEV; @@ -988,7 +1014,9 @@ static int si470x_fops_release(struct inode *inode, struct file *file) /* cancel read processes */ wake_up_interruptible(&radio->read_queue); - return si470x_stop(radio); + retval = si470x_stop(radio); + usb_autopm_put_interface(radio->intf); + return retval; } return 0; @@ -1377,6 +1405,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, sizeof(si470x_viddev_template)); radio->users = 0; radio->usbdev = interface_to_usbdev(intf); + radio->intf = intf; mutex_init(&radio->lock); video_set_drvdata(radio->videodev, radio); @@ -1439,6 +1468,41 @@ err_initial: } +/* + * si470x_usb_driver_suspend - suspend the device + */ +static int si470x_usb_driver_suspend(struct usb_interface *intf, + pm_message_t message) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + printk(KERN_INFO DRIVER_NAME ": suspending now...\n"); + + cancel_delayed_work_sync(&radio->work); + + return 0; +} + + +/* + * si470x_usb_driver_resume - resume the device + */ +static int si470x_usb_driver_resume(struct usb_interface *intf) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + printk(KERN_INFO DRIVER_NAME ": resuming now...\n"); + + mutex_lock(&radio->lock); + if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) + schedule_delayed_work(&radio->work, + msecs_to_jiffies(rds_poll_time)); + mutex_unlock(&radio->lock); + + return 0; +} + + /* * si470x_usb_driver_disconnect - disconnect the device */ @@ -1458,10 +1522,13 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) * si470x_usb_driver - usb driver interface */ static struct usb_driver si470x_usb_driver = { - .name = DRIVER_NAME, - .probe = si470x_usb_driver_probe, - .disconnect = si470x_usb_driver_disconnect, - .id_table = si470x_usb_driver_id_table, + .name = DRIVER_NAME, + .probe = si470x_usb_driver_probe, + .disconnect = si470x_usb_driver_disconnect, + .suspend = si470x_usb_driver_suspend, + .resume = si470x_usb_driver_resume, + .id_table = si470x_usb_driver_id_table, + .supports_autosuspend = 1, }; -- 2.39.5