Hi,

this should implement autosuspend. Could you please test it?
It's against 1.0.6.

        Regards
                Oliver

----

commit 5929871d540c96a05df7c7d3cbaeff4524ffe8e2
Author: Oliver Neukum <[EMAIL PROTECTED]>
Date:   Fri Feb 1 15:48:09 2008 +0100

    autosuspend for the si470x driver

diff --git a/drivers/media/radio/radio-si470x.c 
b/drivers/media/radio/radio-si470x.c
index bb29e44..251e081 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -416,6 +416,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 */
@@ -763,9 +764,15 @@ 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);
+       mutex_unlock(&radio->lock);
+
+       return retval;
 }
 
 
@@ -887,11 +894,13 @@ static ssize_t si470x_fops_read(struct file *file, char 
__user *buf,
        unsigned int block_count = 0;
 
        /* switch on rds reception */
+       mutex_lock(&radio->lock);
        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
                si470x_rds_on(radio);
                schedule_delayed_work(&radio->work,
                        msecs_to_jiffies(rds_poll_time));
        }
+       mutex_unlock(&radio->lock);
 
        /* block if no new data available */
        while (radio->wr_index == radio->rd_index) {
@@ -941,11 +950,13 @@ static unsigned int si470x_fops_poll(struct file *file,
        struct si470x_device *radio = video_get_drvdata(video_devdata(file));
 
        /* switch on rds reception */
+       mutex_lock(&radio->lock);
        if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
                si470x_rds_on(radio);
                schedule_delayed_work(&radio->work,
                        msecs_to_jiffies(rds_poll_time));
        }
+       mutex_unlock(&radio->lock);
 
        poll_wait(file, &radio->read_queue, pts);
 
@@ -962,10 +973,21 @@ 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 err;
        radio->users++;
-       if (radio->users == 1)
-               return si470x_start(radio);
+
+       err = usb_autopm_get_interface(radio->intf);
+       if (err < 0) {
+               radio->users--;
+               return -EIO;
+       }
+       
+       if (radio->users == 1) {
+               err = si470x_start(radio);
+               if (err < 0)
+                       usb_autopm_put_interface(radio->intf);
+               return err;
+       }
 
        return 0;
 }
@@ -977,6 +999,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 err;
 
        if (!radio)
                return -ENODEV;
@@ -989,7 +1012,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);
+               err = si470x_stop(radio);
+               usb_autopm_put_interface(radio->intf);
+               return err;
        }
 
        return 0;
@@ -1378,6 +1403,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);
 
@@ -1454,6 +1480,28 @@ static void si470x_usb_driver_disconnect(struct 
usb_interface *intf)
        kfree(radio);
 }
 
+static int si470x_usb_driver_suspend (struct usb_interface *intf, pm_message_t 
message)
+{
+       struct si470x_device *radio = usb_get_intfdata(intf);
+
+       mutex_lock(&radio->lock);
+       cancel_delayed_work_sync(&radio->work);
+       mutex_unlock(&radio->lock);
+
+       return 0;
+}
+
+static int si470x_usb_driver_resume (struct usb_interface *intf)
+{
+       struct si470x_device *radio = usb_get_intfdata(intf);
+
+       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 - usb driver interface
@@ -1462,7 +1510,10 @@ static struct usb_driver si470x_usb_driver = {
        .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,
 };
 
 
-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to