On Thu, 12 Oct 2006, Oliver Neukum wrote:

> Hi,
> 
> I can't boot 2.6.19-rc1, so here's an incomplete version of autosuspend
> for hid to invite comments on the basic approach.
> 
>       Regards
>               Oliver
> 
> --- linux-2.6.19-rc1/drivers/usb/input/hid.h  2006-10-05 04:57:05.000000000 
> +0200
> +++ gregtree/drivers/usb/input/hid.h  2006-10-09 15:20:21.000000000 +0200
> @@ -384,6 +384,9 @@
>  #define HID_IN_RUNNING               3
>  #define HID_RESET_PENDING    4
>  #define HID_SUSPENDED                5
> +#define HID_IN_IDLE          6
> +
> +#define HID_IDLE_TIME                200*HZ

This will need to be configurable separately for each device.

>  int hid_open(struct hid_device *hid)
>  {
> -     ++hid->open;
> +     clear_bit(HID_IN_IDLE, &hid->iofl);
> +     if (!hid->open++)
> +             usb_autopm_get_interface(hid->intf);
>       if (hid_start_in(hid))
>               hid_io_error(hid);
>       return 0;
> @@ -1375,8 +1383,10 @@
>  
>  void hid_close(struct hid_device *hid)
>  {
> -     if (!--hid->open)
> +     if (!--hid->open) {
>               usb_kill_urb(hid->urbin);
> +             set_bit(HID_IN_IDLE, &hid->iofl);
> +     }
>  }

There needs to be a call to usb_autopm_put_interface() here, to balance 
the call in hid_open().

> +void hid_add_idle_timer(struct hid_device *hid)
> +{
> +     hid->idle_timer.expires = jiffies + HID_IDLE_TIME;
> +     add_timer(&hid->idle_timer);
> +}
> +
> +static void hid_mod_idle_timer(struct hid_device *hid)
> +{
> +     unsigned long flags;
> +
> +     spin_lock_irqsave(&hid->inlock, flags);
> +     if (usb_get_intfdata(hid->intf))
> +             mod_timer(&hid->idle_timer, jiffies + HID_IDLE_TIME);
> +     spin_unlock_irqrestore(&hid->inlock, flags);
> +}

It's not obvious why you need two separate functions (you can always call
mod_timer in place of add_timer), or why you need the spinlock.  

usb_get_intfdata() here isn't safe; if the value can be 0 then it can also
be anything else, since a different driver may be bound to the interface.  
It would be better to have an "unbound" flag in the hid_device structure.
On the other hand, why do you need to check this at all?  This routine 
won't get called after the driver is unbound.

> +static void __hid_report_idle(void *d)
> +{
> +     struct usb_interface *intf = d;
> +
> +     usb_autopm_put_interface(intf);
> +}

This call needs to be balanced somewhere.  Otherwise intf->pm_usage_cnt
will be decremented at every timeout and never incremented.  See below.

> +static void hid_report_idle(struct hid_device *hid)
> +{
> +     struct usb_interface *intf = hid->intf;
> +     unsigned long flags;
> +
> +     spin_lock_irqsave(&hid->inlock, flags);
> +     if (!test_bit(HID_SUSPENDED, &hid->iofl))
> +             if (usb_get_intfdata(intf))
> +                     schedule_work(&hid->idle_work);
> +     spin_unlock_irqrestore(&hid->inlock, flags);
> +}

Again, usb_get_intfdata() isn't safe or appropriate.

> +static void hid_check_idle(unsigned long arg)
> +{
> +     struct hid_device *hid = (struct hid_device *)arg;
> +     int state;
> +
> +     state = test_and_set_bit(HID_IN_IDLE, &hid->iofl);
> +
> +     if (!state) {
> +             hid_mod_idle_timer(hid);
> +     } else {
> +             hid_report_idle(hid);
> +     }
> +}

Somewhere you will need to restart the idle timer after an autoresume.  
Probably in the resume method.  That may also be where you want to set 
intf->pm_usage_cnt to 1 if the device is open.

Alan Stern


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to