Increase USB polling rate across all devices in linux?

I just came across this tweak that permits one to increase the polling rate of a usb mouse to 1KHz. Is it possible to achieve the same increase to other USB devices (or all USB devices)? I'm a researcher in cognitive science and I conduct experiments using keyboards and gamepads (usually a wired xbox 360 gamepad) for human input where an increased polling rate would mean better measurement accuracy of response times.


I don't know of any general mechanism. I believe that one has to tweak the sources of the kernel or the respective driver.

A ray of hope is given by this answer to the thread I-PAC / Keyboard Encoder polling rate :

On Linux, it is possible to set the USB mouse polling rate, and almost all mice can work with 500Hz polling. There's no official support for increased polling speed of other HID devices (and I assume the I-PAC is a standard HID device), but with a simple modification to drivers/usb/input/hid-core.c you can increase the polling rate for those too. I poll my USB keyboard at 250Hz and it works perfectly, but I haven't tested other keyboards, and it's likely that it won't work with all devices.


If you're willing to compile your own kernel, modifying drivers/hid/usbhid/hid-core.c is an option.
I had a similar issue as I want to change the polling rate of my keyboard and drawing tablet so I have modified my hid-core.c for some time now.

It appears that newer kernels (4.12 and up) already have usbhid.jspoll parameter but still no parameter for keyboards.

With older than 4.12 kernels I modified my hid-core.c as follows, making mousepoll affect all devices it handles:

--- a/linux-4.11-original/drivers/hid/usbhid/hid-core.c
+++ b/linux-4.11/drivers/hid/usbhid/hid-core.c
@@ -1081,9 +1081,14 @@ static int usbhid_start(struct hid_device *hid)
                               hid->name, endpoint->bInterval, interval);
                }

-               /* Change the polling interval of mice. */
-               if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
+               /* Change the polling interval of mice.
+               EDIT 2016-09-03: poll everything with mousepoll
+                */
+               if (/*hid->collection->usage == HID_GD_MOUSE &&*/ hid_mousepoll_interval > 0) {
+                       printk(KERN_INFO "%s: Changed interval to mousepoll: %d -> %d\n",
+                              hid->name, interval, hid_mousepoll_interval);
                        interval = hid_mousepoll_interval;
+               }

And for versions 4.12 and up I modified it differently as I didn't want to break the working usbhid.jspoll:

--- a/linux-4.12.4-original/drivers/hid/usbhid/hid-core.c
+++ b/linux-4.12.4/drivers/hid/usbhid/hid-core.c
@@ -56,6 +56,10 @@ static unsigned int hid_jspoll_interval;
 module_param_named(jspoll, hid_jspoll_interval, uint, 0644);
 MODULE_PARM_DESC(jspoll, "Polling interval of joysticks");

+static unsigned int hid_elsepoll_interval;
+module_param_named(elsepoll, hid_elsepoll_interval, uint, 0644);
+MODULE_PARM_DESC(elsepoll, "Polling interval of non-mouse non-joysticks");
+
@@ -1083,15 +1087,31 @@ static int usbhid_start(struct hid_device *hid)
                }

                /* Change the polling interval of mice and joysticks. */
+               /* EDIT 2017-08-03:
+                       added elsepoll
+                       always print to KERN_INFO when one of mousepoll, jspoll, elsepoll takes effect.
+               */
                switch (hid->collection->usage) {
                case HID_GD_MOUSE:
-                       if (hid_mousepoll_interval > 0)
+                       if (hid_mousepoll_interval > 0) {
+                               printk(KERN_INFO "%s: Changed interval to mousepoll: %d -> %d\n",
+                                      hid->name, interval, hid_mousepoll_interval);
                                interval = hid_mousepoll_interval;
+                       }
                        break;
                case HID_GD_JOYSTICK:
-                       if (hid_jspoll_interval > 0)
+                       if (hid_jspoll_interval > 0) {
+                               printk(KERN_INFO "%s: Changed interval to jspoll: %d -> %d\n",
+                                      hid->name, interval, hid_jspoll_interval);
                                interval = hid_jspoll_interval;
+                       }
                        break;
+               default:
+                       if (hid_elsepoll_interval > 0) {
+                               printk(KERN_INFO "%s: Changed interval to elsepoll: %d -> %d\n",
+                                      hid->name, interval, hid_elsepoll_interval);
+                               interval = hid_elsepoll_interval;
+                       }

Now to get 1000Hz (1ms interval) poll on gamepads and keyboards:

  • if builtin or unsure: add usbhid.mousepoll=1 or usbhid.jspoll=1 usbhid.elsepoll=1 to kernel command line and reboot.

  • if module: write options usbhid mousepoll=1 or options usbhid jspoll=1 elsepoll=1 to /etc/modprobe.d/usbhid.conf

If you just rmmod usbhid;modprobe usbhid after modifying the file above, you need to unplug and replug a USB device to actually change its polling interval even though the kernel messages seem to suggest otherwise.

After rebooting or reloading usbhid, to verify it working, unplug and re-plug the USB devices and run dmesg |grep poll
Expect something like this on the last few lines:

[476243.420106] daskeyboard: Changed interval to elsepoll: 10 -> 1
[476243.497161] daskeyboard: Changed interval to elsepoll: 10 -> 1
[476251.633110] USB Gamepad : Changed interval to jspoll: 17 -> 1
[476260.726864] Wacom Co.,Ltd. Intuos PS: Changed interval to elsepoll: 2 -> 1
[476260.730403] Wacom Co.,Ltd. Intuos PS: Changed interval to elsepoll: 2 -> 1

The devices here are 04d9:2013, 0810:0003 and 056a:030e