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
 
 struct hid_input {
        struct list_head list;
@@ -408,9 +411,11 @@
 
        unsigned long iofl;                                             /* I/O 
flags (CTRL_RUNNING, OUT_RUNNING) */
        struct timer_list io_retry;                                     /* 
Retry timer */
+       struct timer_list idle_timer;                                   /* 
timer to determine idleness */
        unsigned long stop_retry;                                       /* Time 
to give up, in jiffies */
        unsigned int retry_delay;                                       /* 
Delay length in ms */
        struct work_struct reset_work;                                  /* Task 
context for resets */
+       struct work_struct idle_work;                                   /* Task 
context for reporting idleness */
 
        unsigned int bufsize;                                           /* URB 
buffer size */
 
--- linux-2.6.19-rc1/drivers/usb/input/hid-core.c       2006-10-05 
04:57:05.000000000 +0200
+++ gregtree/drivers/usb/input/hid-core.c       2006-10-09 15:23:09.000000000 
+0200
@@ -1009,6 +1009,8 @@
        struct hid_device       *hid = urb->context;
        int                     status;
 
+       /*data recieved, errors ignored as they are handled, device not idle */
+       clear_bit(HID_IN_IDLE, &hid->iofl);
        switch (urb->status) {
                case 0:                 /* success */
                        hid->retry_delay = 0;
@@ -1365,9 +1367,15 @@
        return result;
 }
 
+static void hid_check_idle(unsigned long arg);
+void hid_add_idle_timer(struct hid_device *hid);
+static void __hid_report_idle(void *d);
+
 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);
+       }
 }
 
 #define USB_VENDOR_ID_PANJIT           0x134c
@@ -1971,12 +1981,16 @@
        init_waitqueue_head(&hid->wait);
 
        INIT_WORK(&hid->reset_work, hid_reset, hid);
+       INIT_WORK(&hid->idle_work, __hid_report_idle, intf);
        setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+       setup_timer(&hid->idle_timer, hid_check_idle, (unsigned long) hid);
 
        spin_lock_init(&hid->inlock);
        spin_lock_init(&hid->outlock);
        spin_lock_init(&hid->ctrllock);
 
+       set_bit(HID_IN_IDLE, &hid->iofl);
+
        hid->version = le16_to_cpu(hdesc->bcdHID);
        hid->country = hdesc->bCountryCode;
        hid->dev = dev;
@@ -2050,6 +2064,7 @@
        usb_kill_urb(hid->urbctrl);
 
        del_timer_sync(&hid->io_retry);
+       del_timer_sync(&hid->idle_timer);
        flush_scheduled_work();
 
        if (hid->claimed & HID_CLAIMED_INPUT)
@@ -2116,12 +2131,64 @@
 
        usb_make_path(interface_to_usbdev(intf), path, 63);
 
+       if ((hid->claimed & HID_CLAIMED_INPUT) && !(hid->claimed & 
HID_CLAIMED_HIDDEV))
+               hid_add_idle_timer(hid);
+
        printk(": USB HID v%x.%02x %s [%s] on %s\n",
                hid->version >> 8, hid->version & 0xff, c, hid->name, path);
 
        return 0;
 }
 
+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);
+}
+
+static void __hid_report_idle(void *d)
+{
+       struct usb_interface *intf = d;
+
+       usb_autopm_put_interface(intf);
+}
+
+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);
+}
+
+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);
+       }
+}
+
 static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct hid_device *hid = usb_get_intfdata (intf);

-------------------------------------------------------------------------
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