Search code examples
linuxembeddedusbattiny

What sets the /sys/bus/usb/devices/xyz/power/control file?


Long story short

I'd like to know if there's a way to control the value in the /sys/bus/usb/devices/5-1.1/power/control file from a USB device descriptor. Host always sets it to auto and I'd like it to be implicitly set to on.

Full story

I added a microcontroller to a laptop USB cooler because I wanted the device to sleep when the host is suspended. The microcontroller is a DigiSpark ATTiny85 and I'm using the V-USB library to mimic a USB device.

To detect that the host is suspended, I'm constantly checking if the host sent a Start-of-Frame packet (which it does every 3ms or so, unless suspended) and if no new packets are received, the device goes to sleep. Receiving a SoF packet results in an interrupt which wakes the microcontroller and hence, the cooler.

So far, everything works perfectly.

However, I have a small issue with this file: /sys/bus/usb/devices/5-1.1/power/control which gets set to "auto" and, since there's really no communication between the cooler and host (apart from SoF packets that the host sends to device), the host autosuspends the device soon after it gets connected. :/

Once I set the file value to on, the host doesn't try to autosuspend the device anymore based on whether there's communication or not (the desired sleep on suspend behavior still works without a problem). But, of course, this needs to be done everytime the device is unplugged and plugged back in.

Now... maybe I could also send some dummy data from the cooler to host, to mimic communication, but, unless the host reads it, some buffer will definitely fill which is why this does not look like a solution.

I was wondering if there's some way to maybe tweak the USB device descriptor to tell the host that while this is a busPowered device, it should not try to autosuspend it.

Any ideas are highly appreciated.


Solution

  • Answering this in case some lost soul runs into a similar thing.

    So, I wanted to play around with WSL so I installed Windows 11. The device behaved in the same way, as in once connected it started but it got auto-suspended after a short time.

    Initially I was using the default USB class from the DigisparkCDC library, but then decided to have a look at DigisparkKeyboard just for comparison.

    While the former was connecting as a CDC device, the latter gets connected as a HID device. Changing the USB class was not enough though, as HID devices also pass some report.

    After a lot of trial and error I got to a really minimal HID REPORT descriptor:

    const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
      0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
      0x09, 0x80,                    // USAGE (System Controller)
      0xa1, 0x01,                    // COLLECTION (Application)
      0x05, 0x80,                    //   USAGE_PAGE (System Controller)
      0x09, 0x01,                    //   USAGE (Generic Desktop)
      0x75, 0x01,                    //   REPORT_SIZE (1)
      0x95, 0x08,                    //   REPORT_COUNT (8)
      0x81, 0x00,                    //   INPUT
      0xc0                           // END_COLLECTION
    };
    

    This just needs to be pasted into ArduinoIDE as a global variable and the usbconfig.h file must be adjusted so that USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH matches the length of the HID descriptor (and is also uncommented).

    And that's it! It now all works as intended (on Windows), without getting autosuspended! This also seems to work fine on a different laptop with a Linux Mint 21 installation (for some reason it used to work on this one even before - why is beyond me - but there were some logs saying that reading the device descriptor failed).

    EDIT: Seems like using Undefined for Usage and UsagePage causes intermittent issues with the device resuming when the host goes out of suspend. Replaced them with Generic Desktop and System Controller and it seems to work fine. Feel free to experiment if you run into issues!