Suspending your usb mouse with udev

For my first post here, I decided to do something simple: suspending a usb mouse. Of course it should be fairly easy to apply this to other devices as well, but in my case it was a mouse, and that is kind of the most obvious case.

Suspending a usb device obviously has the effect of reducing the devices power consumption, thus increasing the battery life of your laptop and giving you the warm fuzzy feeling of fighting climate change without getting up from your desk.

Note: The sysfs interface described in this post has changed in more recent kernel versions. What I describe here works with the kernel shipping with Ubuntu Lucid (2.6.32). I will probably update this once Ubuntu ships a kernel with the new interface.

Suspending

Now basically, suspending a usb device is pretty simple. First, you have to find your device in the sysfs tree, that is, in /sys/bus/usb/devices . There is no straightforward way of finding a given device here, so the easiest way is to print all the device names. Each of the folders in devices (actually, the folders pointed to by the symlinks) that actually represents a real device contains a file named “product” which contains the name of the device.

So let’s just print the names and contents of these files:

$ for f in /sys/bus/usb/devices/*/product
> do
>   printf "%s\t" "$f"
>   cat $f
> done
...
/sys/bus/usb/devices/2-1.3/product      Microsoft 5-Button Mouse with IntelliEye(TM)
...

So, in my case, my mouse is currently (!)  in 2-1.3. Now that we’ve found this out, suspending is as simple as:

$ sudo -s "echo suspend > /sys/bus/usb/devices/2-1.3/power/level"

This suspends the device immediately, which is fun but not all that useful. Setting the device to auto-suspend after, say, five minutes of inactivity, works like this:

$ sudo -s "echo 300 > /sys/bus/usb/devices/2-1.3/power/autosuspend"
$ sudo -s "echo auto > /sys/bus/usb/devices/2-1.3/power/level"

Again, this sysfs interface has changed in recent versions. While this may still work with newer kernels, theres a “more correct” way of doing it. More on that later.

Now while this works nicely, the system doesn’t remember the setting across reboots. Of course we could hack what we did above into a shell script and put that into our .bashrc or similar, but that wouldn’t be nearly as elegant as it can be. This is were udev comes into play.

udev

udev is a neat system service that is notified by the kernel whenever a device is connected or disconnected. Through so-called “udev rules” we can tell udev to perform a given action when a certain device appears.

To make use of this, we need to be able to identify our device when it comes up, so back to the sysfs directory.

/sys/bus/usb/devices/2-1.3$ cat idVendor idProduct
045e
0039

The contents of the idVendor and idProduct files identify our device. Matching exactly this device is actually more strict than necessary, but unless you have lots of different mice, this will work just fine.

With that knowledge, we can write our udev rule. From what I’ve gathered, the recommended location for your own rules file is /etc/udev/rules.d/10-local.rules . Of course the name and the number are not mandatory, but the suffix is.

A single udev rule is basically a list of matching predicates and assignment actions. When a device fulfills all the matching predicates, udev performs the assignments. In our case, we match for the subsystem and the vendor and device ids we just found:

# File: /etc/udev/rules.d/10-local.rules

# External mouse ("Microsoft 5-Button Mouse with IntelliEye(TM)")
SUBSYSTEM=="usb", \
  ATTR{idVendor}=="045e", \
  ATTR{idProduct}=="0039", \
  ATTR{power/level}="auto", \
  ATTR{power/autosuspend}="300"

Note: The line continuation above is owed to the display here on the page. udev does not support line continuation. Put all the parts in one line.

As you can see, the matching parts of the rule differ from the assignments only by the additional ‘=’ character. The ATTR{} expressions allow us to directly access the contents of the sysfs directory of the device.

With this setup, the auto suspend settings are applied automatically every time the device is connected to the system.

References/ further reading

Advertisements
This entry was posted in Linux. Bookmark the permalink.

One Response to Suspending your usb mouse with udev

  1. Mark S says:

    Thanks for hint about how to autosuspend devices. I’ve wanted to do that for quite a while, but have never fully understood how autosuspend seemed to be enabled for some devices and not others.

    One thing I’ve also done is create symbolic names for my input devices under /dev/input. It seems that it isn’t possible to do this using the usb subsystem, instead you have to use the “input” subsystem. Here’s the rules that I’ve ended up with for my Logitech trackman, to both autosuspend it after 5 minutes and to create a symbolic link under /dev/input. This is with kernel 2.6.39, there is a new millisecond resolution file that is intended to be used from now on according to the kernel documentation USB power-management file. One thing of interest is that the name attribute under the input subsystem seems to be a concatenation of the usb manufacturer and product names.

    85-input-local.rules
    ~~~~~~~~~~~~~~~

    SUBSYSTEM==”input”, ATTRS{name}==”Logitech Trackball”, SYMLINK+=”input/trackman”

    SUBSYSTEM==”usb”, ATTRS{manufacturer}==”Logitech”, ATTRS{product}==”Trackball”, ATTR{power/wakeup}=”enabled”, ATTR{power/control}=”auto”, ATTR{power/autosuspend_delay_ms}=”300000″

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s