Tuesday, 23 June 2009

USB persist, Webcams and Suspend/Resume

The other day I was looking at a problem with a laptop running Ubuntu Hardy that had an integrated USB webcam that failed to work over a suspend/resume cycle. A webcam viewer application such as Cheese or UCView was being run during the suspend/resume and had locked up after the resume. A workaround was to enable USB persist on this device as described in Documentation/usb/persist.txt in the kernel source.

From my understanding, if a USB host controller loses power (e.g. during a system syspend) then it is treated as if it has been unplugged. For devices like integrated webcams we know it cannot be unplugged, so we can enable USB persist.

USB host controllers can get reset after suspend to RAM on some systems, and you will see kernel messages such as "root hub lost power or was reset" (use dmesg to see this). In such cases, USB persist can save the day.

UBS persist keeps the USB device's core data structures persistent when power session disruption occurs. Essentially on resume the kernel checks if persist is set on the device, if so, it does a USB port reset, re-enumates and checks if the device is the same as the one before (e.g. checking descriptors and information such as produce and vendor IDs) it then re-uses the original device data structures.

USB persist for a device can be enables by echo'ing 1 to the devices persist file as root:

echo 1 >/sys/bus/usb/devices/.../power/persist

Below is a shell script to set USB persist for a device with a given IDVENDOR and IDPRODUCT USB ID.

for I in /sys/bus/usb/devices/*/*
if [ -e $I/idVendor -a -e $I/idProduct ]; then
idvendor=`cat $I/idVendor`
idproduct=`cat $I/idProduct`
if [ x$idvendor = x$IDVENDOR -a x$idproduct = x$IDPRODUCT ]; then
if [ -e $I/../power/persist ]; then
echo 1 > $I/power/persist
if [ -e $I/../power/persist ] ; then
echo 1 > $I/../power/persist

Note that doing USB persist on pluggable USB devices is NOT recommended as it can cause kernel panics!

1 comment:

  1. It seems that this behavior is now standard. For me it works very bad, as my logitech webcam is unusable after suspend..
    So i have to do the inverse of yours! But anyway, thanks for the script. :)