From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 17:03:23
The Valve Index has a problem that when the DP link is torn down
(such as a power state transition) the device stops responding to EDID
requests the next time it goes up. Either manually resetting the device
or hotplugging it brings it back to normal behavior.
Introduce a driver that during a power state transition will reset the
device. This helps most cases, but if the system crashes the device
can still be in a bad state. So also export a sysfs file that userspace
could potentially use to trigger a reset on demand while in this circumstance.
Curtis Vogt (1):
USB: quirks: Ignore remote wakeup from the Valve Index breakout box
hub
Mario Limonciello (2):
HID: Add shutdown callback for device drivers
HID: valve-index: Reboot headset on system power transitions
.../ABI/testing/sysfs-driver-hid-valve-index | 12 ++
drivers/hid/Kconfig | 11 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 13 ++
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-valve-index.c | 142 ++++++++++++++++++
drivers/usb/core/quirks.c | 4 +
include/linux/hid.h | 2 +
8 files changed, 186 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-valve-index
create mode 100644 drivers/hid/hid-valve-index.c
--
2.43.0
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 17:03:25
From: Curtis Vogt <redacted>
The hub in the Valve Index breakout box (28de:2613, bcdDevice 1.82) asserts
remote wakeup a few seconds after the host enters S3, so a system with the
headset attached does not stay suspended. Observed on 7.3-rc2 with an
amdgpu host: every suspend attempt returned after 4-8 seconds with wakeup
events recorded on the hub and its xHCI controller, with no HID driver
bound to the headset. Disabling wakeup on the hub through sysfs lets the
same system stay asleep until woken from the front panel. The headset
most likely reacts to the DisplayPort link being taken down as the host
suspends.
Nothing behind this hub is a device that should be able to wake the host
(the headset, its radio and microphone, and a further hub), so ignore its
remote wakeup capability, as is already done for the ASUS T100 base
station's hub.
Signed-off-by: Curtis Vogt <redacted>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
drivers/usb/core/quirks.c | 4 ++++
1 file changed, 4 insertions(+)
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 17:03:26
HID device drivers can receive suspend and resume notifications through
callbacks forwarded by their transport driver. There is no corresponding
way to perform device-specific work during an orderly system shutdown.
Add a shutdown callback to struct hid_driver and dispatch it from the HID
bus shutdown operation. This allows a HID device driver to communicate
with hardware before its transport is shut down.
Assisted-by: LLM
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
drivers/hid/hid-core.c | 13 +++++++++++++
include/linux/hid.h | 2 ++
2 files changed, 15 insertions(+)
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 17:03:28
The Valve Index HMD stops serving its EDID after the host disables the
DisplayPort PHY. The headset remains powered by its breakout box across
suspend and shutdown, so the bad state survives and the next connector
detection reports "No EDID read". The HMD then appears as a synthesized
640x480 display until it is power-cycled.
The 64-byte HID output report 0x16 with command 0x01 reboots the headset
and restores its EDID service. Add a device-specific driver which sends
this report for system sleep transitions and orderly shutdown while leaving
runtime autosuspend alone.
Resume a runtime-suspended interface for a shutdown request and restrict
the command to the composite interface which declares report 0x16.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4333
Link: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/939
Assisted-by: LLM
Co-developed-by: Curtis Vogt <redacted>
Signed-off-by: Curtis Vogt <redacted>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
.../ABI/testing/sysfs-driver-hid-valve-index | 12 ++
drivers/hid/Kconfig | 11 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-valve-index.c | 142 ++++++++++++++++++
5 files changed, 167 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-valve-index
create mode 100644 drivers/hid/hid-valve-index.c
@@ -0,0 +1,12 @@+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot+Date: October 2026+Contact: linux-input@vger.kernel.org+Description:+ Writing a boolean true value reboots the Valve Index headset to+ recover its EDID service. Writing a boolean false value has no+ effect. This file is write-only.++ The Valve Index is a composite HID device. The reboot command is+ only supported by the interface that provides the headset's 64-byte+ output report. Writing true to this file on another interface fails+ with -ENODEV.
@@ -0,0 +1,142 @@+// SPDX-License-Identifier: GPL-2.0-or-later+/*+*HIDdriverfortheValveIndexheadset+*/++#include<linux/hid.h>+#include<linux/module.h>++#include"hid-ids.h"++#define VALVE_INDEX_REBOOT_REPORT_ID 0x16+#define VALVE_INDEX_REBOOT_CMD 0x01+#define VALVE_INDEX_REPORT_SIZE 64++staticboolvalve_index_has_reboot_report(structhid_device*hdev)+{+structhid_report*report;++/*+*Therebootcommandisavendorprotocolcarriedintheunnumbered+*64-byteoutputreportoftheheadset'sthirdinterface;thefirst+*databyteisthecommandid.Report0x16isonlydeclaredasa+*featurereportandisnotwhatthecommandissentas.+*/+report=hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[0];++returnreport&&hid_report_len(report)==VALVE_INDEX_REPORT_SIZE;+}++staticvoidvalve_index_reboot(structhid_device*hdev,boolwake)+{+u8*report;+intret;++if(!valve_index_has_reboot_report(hdev))+return;++/* USB transfer buffers must be DMA-able, so not on the stack. */+report=kzalloc(VALVE_INDEX_REPORT_SIZE,GFP_KERNEL);+if(!report)+return;+report[0]=VALVE_INDEX_REBOOT_REPORT_ID;+report[1]=VALVE_INDEX_REBOOT_CMD;++if(wake){+ret=hid_hw_power(hdev,PM_HINT_FULLON);+if(ret<0){+hid_warn(hdev,"failed to resume headset for reboot: %d\n",+ret);+gotoout;+}+}++/* Use the same interrupt-out then SET_REPORT fallback as hidraw. */+ret=hid_hw_output_report(hdev,report,VALVE_INDEX_REPORT_SIZE);+if(ret==-ENOSYS)+ret=hid_hw_raw_request(hdev,report[0],report,+VALVE_INDEX_REPORT_SIZE,+HID_OUTPUT_REPORT,HID_REQ_SET_REPORT);+if(ret<0)+hid_warn(hdev,"failed to reboot headset: %d\n",ret);+elseif(ret!=VALVE_INDEX_REPORT_SIZE)+hid_warn(hdev,"short headset reboot report: %d\n",ret);++if(wake)+hid_hw_power(hdev,PM_HINT_NORMAL);+out:+kfree(report);+}++/*+*Thesuspendandshutdownhooksonlycoverorderlypowertransitions.After+*acrash,ahardresetorapowercuttheheadsetisleftinthestatewhere+*itsEDIDnolongerreads,andnothingrecoversituntilthenextorderly+*transition.Exposetherebootcommandasawrite-only"reboot"attribute+*ontheHIDdevicesouserspacecanrecoverit,forinstancefromaudev+*rulethatfiresonlywhentheconnectorreportsnoEDID.Writingtoan+*interfacethatdoesnotcarrytherebootreportreturns-ENODEV.+*/+staticssize_treboot_store(structdevice*dev,structdevice_attribute*attr,+constchar*buf,size_tcount)+{+structhid_device*hdev=to_hid_device(dev);+boolval;++if(kstrtobool(buf,&val))+return-EINVAL;+if(!val)+returncount;+if(!valve_index_has_reboot_report(hdev))+return-ENODEV;++valve_index_reboot(hdev,true);++returncount;+}+staticDEVICE_ATTR_WO(reboot);++staticstructattribute*valve_index_attrs[]={+&dev_attr_reboot.attr,+NULL+};+ATTRIBUTE_GROUPS(valve_index);++/*+*Theheadset'sEDIDserviceislostwhenthehostdisablestheDisplayPort+*PHYduringsystemsuspend,soitneedstherebootonthewayoutof+*suspend.Doingitonthewayindoesnotwork:theheadsetdroppingoff+*USBisaremote-wakeupeventfromitshubandabortsthesuspend.+*/+staticintvalve_index_resume(structhid_device*hdev)+{+valve_index_reboot(hdev,false);++return0;+}++staticvoidvalve_index_shutdown(structhid_device*hdev)+{+valve_index_reboot(hdev,true);+}++staticconststructhid_device_idvalve_index_devices[]={+{HID_USB_DEVICE(USB_VENDOR_ID_VALVE,+USB_DEVICE_ID_VALVE_INDEX_HEADSET)},+{}+};+MODULE_DEVICE_TABLE(hid,valve_index_devices);++staticstructhid_drivervalve_index_driver={+.name="valve-index",+.id_table=valve_index_devices,+.resume=valve_index_resume,+.reset_resume=valve_index_resume,+.shutdown=valve_index_shutdown,+.driver.dev_groups=valve_index_groups,+};+module_hid_driver(valve_index_driver);++MODULE_AUTHOR("Mario Limonciello <mario.limonciello@amd.com>");+MODULE_DESCRIPTION("HID driver for Valve Index headset");+MODULE_LICENSE("GPL");
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect buffer formatting and report ID targeting in `hid_hw_raw_request` fallback for an unnumbered HID report.
--
commit 4526fbce2701e5a40089fba6ae186ded76bc0864
Author: Mario Limonciello [off-list ref]
Subject: HID: valve-index: Reboot headset on system power transitions
This commit introduces a new HID driver for the Valve Index headset to
reboot it on system power transitions. It sends a specific 64-byte report
to recover the EDID service after a DisplayPort link shutdown.
Link: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/939
+static void valve_index_reboot(struct hid_device *hdev, bool wake)
+{
+ u8 *report;
+ int ret;
+
+ if (!valve_index_has_reboot_report(hdev))
+ return;
+
+ /* USB transfer buffers must be DMA-able, so not on the stack. */
+ report = kzalloc(VALVE_INDEX_REPORT_SIZE, GFP_KERNEL);
+ if (!report)
+ return;
+ report[0] = VALVE_INDEX_REBOOT_REPORT_ID;
[Severity: Medium]
Is the report buffer sized correctly for an unnumbered report fallback?
The HID core and usbhid transport expect unnumbered report buffers to be
prefixed with a dummy 0x00 byte (so payload size + 1) for control transfers.
Allocating exactly 64 bytes and placing the payload command at index 0 might
break control transfer formatting in usbhid_set_raw_report if the fallback
path below is taken.
[ ... ]
+ /* Use the same interrupt-out then SET_REPORT fallback as hidraw. */
+ ret = hid_hw_output_report(hdev, report, VALVE_INDEX_REPORT_SIZE);
+ if (ret == -ENOSYS)
+ ret = hid_hw_raw_request(hdev, report[0], report,
+ VALVE_INDEX_REPORT_SIZE,
+ HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
[Severity: Medium]
Does this properly target the unnumbered report during the fallback?
By passing report[0] (which contains 0x16) as the reportnum argument, the
fallback control transfer will target Output Report ID 0x16 instead of the
required unnumbered report (ID 0). If hid_hw_output_report returns -ENOSYS
and this fallback is taken, the headset might reject the transfer, causing
the reboot command to fail.
+ if (ret < 0)
+ hid_warn(hdev, "failed to reboot headset: %d\n", ret);
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 17:21:29
On 9/10/26 12:17, sashiko-bot@kernel.org wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect buffer formatting and report ID targeting in `hid_hw_raw_request` fallback for an unnumbered HID report.
--
commit 4526fbce2701e5a40089fba6ae186ded76bc0864
Author: Mario Limonciello [off-list ref]
Subject: HID: valve-index: Reboot headset on system power transitions
This commit introduces a new HID driver for the Valve Index headset to
reboot it on system power transitions. It sends a specific 64-byte report
to recover the EDID service after a DisplayPort link shutdown.
Link: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/939
+static void valve_index_reboot(struct hid_device *hdev, bool wake)
+{
+ u8 *report;
+ int ret;
+
+ if (!valve_index_has_reboot_report(hdev))
+ return;
+
+ /* USB transfer buffers must be DMA-able, so not on the stack. */
+ report = kzalloc(VALVE_INDEX_REPORT_SIZE, GFP_KERNEL);
+ if (!report)
+ return;
+ report[0] = VALVE_INDEX_REBOOT_REPORT_ID;
[Severity: Medium]
Is the report buffer sized correctly for an unnumbered report fallback?
The HID core and usbhid transport expect unnumbered report buffers to be
prefixed with a dummy 0x00 byte (so payload size + 1) for control transfers.
Allocating exactly 64 bytes and placing the payload command at index 0 might
break control transfer formatting in usbhid_set_raw_report if the fallback
path below is taken.
[ ... ]
quoted
+ /* Use the same interrupt-out then SET_REPORT fallback as hidraw. */
+ ret = hid_hw_output_report(hdev, report, VALVE_INDEX_REPORT_SIZE);
+ if (ret == -ENOSYS)
+ ret = hid_hw_raw_request(hdev, report[0], report,
+ VALVE_INDEX_REPORT_SIZE,
+ HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
[Severity: Medium]
Does this properly target the unnumbered report during the fallback?
By passing report[0] (which contains 0x16) as the reportnum argument, the
fallback control transfer will target Output Report ID 0x16 instead of the
required unnumbered report (ID 0). If hid_hw_output_report returns -ENOSYS
and this fallback is taken, the headset might reject the transfer, causing
the reboot command to fail.
quoted
+ if (ret < 0)
+ hid_warn(hdev, "failed to reboot headset: %d\n", ret);
[ ... ]
Curtis - can you check how the headset handles those cases?
From: Michal Pecio <hidden> Date: 2026-09-10 20:04:29
On Thu, 10 Sep 2026 12:02:53 -0500, Mario Limonciello wrote:
The Valve Index HMD stops serving its EDID after the host disables the
DisplayPort PHY. The headset remains powered by its breakout box across
suspend and shutdown, so the bad state survives and the next connector
detection reports "No EDID read". The HMD then appears as a synthesized
640x480 display until it is power-cycled.
The 64-byte HID output report 0x16 with command 0x01 reboots the headset
and restores its EDID service. Add a device-specific driver which sends
this report for system sleep transitions and orderly shutdown while leaving
runtime autosuspend alone.
Resume a runtime-suspended interface for a shutdown request and restrict
the command to the composite interface which declares report 0x16.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4333
Hmm, people say it's a regression, so it looks like at least one
alternative solution should, in theory, exist...
Obligatory question: does it work any better with Windows? :)
@@ -0,0 +1,12 @@+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot+Date: October 2026+Contact: linux-input@vger.kernel.org+Description:+ Writing a boolean true value reboots the Valve Index headset to+ recover its EDID service. Writing a boolean false value has no+ effect. This file is write-only.++ The Valve Index is a composite HID device. The reboot command is+ only supported by the interface that provides the headset's 64-byte+ output report. Writing true to this file on another interface fails+ with -ENODEV.
@@ -0,0 +1,142 @@+// SPDX-License-Identifier: GPL-2.0-or-later+/*+*HIDdriverfortheValveIndexheadset+*/++#include<linux/hid.h>+#include<linux/module.h>++#include"hid-ids.h"++#define VALVE_INDEX_REBOOT_REPORT_ID 0x16+#define VALVE_INDEX_REBOOT_CMD 0x01+#define VALVE_INDEX_REPORT_SIZE 64++staticboolvalve_index_has_reboot_report(structhid_device*hdev)+{+structhid_report*report;++/*+*Therebootcommandisavendorprotocolcarriedintheunnumbered+*64-byteoutputreportoftheheadset'sthirdinterface;thefirst+*databyteisthecommandid.Report0x16isonlydeclaredasa+*featurereportandisnotwhatthecommandissentas.+*/+report=hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[0];++returnreport&&hid_report_len(report)==VALVE_INDEX_REPORT_SIZE;+}++staticvoidvalve_index_reboot(structhid_device*hdev,boolwake)+{+u8*report;+intret;++if(!valve_index_has_reboot_report(hdev))+return;++/* USB transfer buffers must be DMA-able, so not on the stack. */+report=kzalloc(VALVE_INDEX_REPORT_SIZE,GFP_KERNEL);+if(!report)+return;+report[0]=VALVE_INDEX_REBOOT_REPORT_ID;+report[1]=VALVE_INDEX_REBOOT_CMD;++if(wake){+ret=hid_hw_power(hdev,PM_HINT_FULLON);+if(ret<0){+hid_warn(hdev,"failed to resume headset for reboot: %d\n",+ret);+gotoout;+}+}++/* Use the same interrupt-out then SET_REPORT fallback as hidraw. */+ret=hid_hw_output_report(hdev,report,VALVE_INDEX_REPORT_SIZE);+if(ret==-ENOSYS)+ret=hid_hw_raw_request(hdev,report[0],report,+VALVE_INDEX_REPORT_SIZE,+HID_OUTPUT_REPORT,HID_REQ_SET_REPORT);+if(ret<0)+hid_warn(hdev,"failed to reboot headset: %d\n",ret);+elseif(ret!=VALVE_INDEX_REPORT_SIZE)+hid_warn(hdev,"short headset reboot report: %d\n",ret);++if(wake)+hid_hw_power(hdev,PM_HINT_NORMAL);+out:+kfree(report);+}++/*+*Thesuspendandshutdownhooksonlycoverorderlypowertransitions.After+*acrash,ahardresetorapowercuttheheadsetisleftinthestatewhere+*itsEDIDnolongerreads,andnothingrecoversituntilthenextorderly+*transition.Exposetherebootcommandasawrite-only"reboot"attribute+*ontheHIDdevicesouserspacecanrecoverit,forinstancefromaudev+*rulethatfiresonlywhentheconnectorreportsnoEDID.Writingtoan+*interfacethatdoesnotcarrytherebootreportreturns-ENODEV.+*/+staticssize_treboot_store(structdevice*dev,structdevice_attribute*attr,+constchar*buf,size_tcount)+{+structhid_device*hdev=to_hid_device(dev);+boolval;++if(kstrtobool(buf,&val))+return-EINVAL;+if(!val)+returncount;+if(!valve_index_has_reboot_report(hdev))+return-ENODEV;++valve_index_reboot(hdev,true);++returncount;+}+staticDEVICE_ATTR_WO(reboot);++staticstructattribute*valve_index_attrs[]={+&dev_attr_reboot.attr,+NULL+};+ATTRIBUTE_GROUPS(valve_index);++/*+*Theheadset'sEDIDserviceislostwhenthehostdisablestheDisplayPort+*PHYduringsystemsuspend,soitneedstherebootonthewayoutof+*suspend.Doingitonthewayindoesnotwork:theheadsetdroppingoff+*USBisaremote-wakeupeventfromitshubandabortsthesuspend.+*/
The internal hub which will be quirked by the next patch, or its parent?
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 20:43:28
On 9/10/26 15:04, Michal Pecio wrote:
On Thu, 10 Sep 2026 12:02:53 -0500, Mario Limonciello wrote:
quoted
The Valve Index HMD stops serving its EDID after the host disables the
DisplayPort PHY. The headset remains powered by its breakout box across
suspend and shutdown, so the bad state survives and the next connector
detection reports "No EDID read". The HMD then appears as a synthesized
640x480 display until it is power-cycled.
The 64-byte HID output report 0x16 with command 0x01 reboots the headset
and restores its EDID service. Add a device-specific driver which sends
this report for system sleep transitions and orderly shutdown while leaving
runtime autosuspend alone.
Resume a runtime-suspended interface for a shutdown request and restrict
the command to the composite interface which declares report 0x16.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4333
Hmm, people say it's a regression, so it looks like at least one
alternative solution should, in theory, exist...
Right. This bug sat for a very long time hoping someone with the
hardware would bisect and we could explain what changed.
My initial suspicion is timing. But scouring the web you can see it
happens on NVIDIA hardware too.
https://forums.developer.nvidia.com/t/valve-index-initialized-in-unusable-state-on-boot/324710
So 'unlikely' that a DRM change caused it. Maybe tied to the F/W
version on the Index and it got updated from initial report to failure?
I have no idea. I don't have this hardware so I'm just trying to help
these people how I can :)
Obligatory question: does it work any better with Windows? :)
@@ -0,0 +1,12 @@+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot+Date: October 2026+Contact: linux-input@vger.kernel.org+Description:+ Writing a boolean true value reboots the Valve Index headset to+ recover its EDID service. Writing a boolean false value has no+ effect. This file is write-only.++ The Valve Index is a composite HID device. The reboot command is+ only supported by the interface that provides the headset's 64-byte+ output report. Writing true to this file on another interface fails+ with -ENODEV.
@@ -0,0 +1,142 @@+// SPDX-License-Identifier: GPL-2.0-or-later+/*+*HIDdriverfortheValveIndexheadset+*/++#include<linux/hid.h>+#include<linux/module.h>++#include"hid-ids.h"++#define VALVE_INDEX_REBOOT_REPORT_ID 0x16+#define VALVE_INDEX_REBOOT_CMD 0x01+#define VALVE_INDEX_REPORT_SIZE 64++staticboolvalve_index_has_reboot_report(structhid_device*hdev)+{+structhid_report*report;++/*+*Therebootcommandisavendorprotocolcarriedintheunnumbered+*64-byteoutputreportoftheheadset'sthirdinterface;thefirst+*databyteisthecommandid.Report0x16isonlydeclaredasa+*featurereportandisnotwhatthecommandissentas.+*/+report=hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[0];++returnreport&&hid_report_len(report)==VALVE_INDEX_REPORT_SIZE;+}++staticvoidvalve_index_reboot(structhid_device*hdev,boolwake)+{+u8*report;+intret;++if(!valve_index_has_reboot_report(hdev))+return;++/* USB transfer buffers must be DMA-able, so not on the stack. */+report=kzalloc(VALVE_INDEX_REPORT_SIZE,GFP_KERNEL);+if(!report)+return;+report[0]=VALVE_INDEX_REBOOT_REPORT_ID;+report[1]=VALVE_INDEX_REBOOT_CMD;++if(wake){+ret=hid_hw_power(hdev,PM_HINT_FULLON);+if(ret<0){+hid_warn(hdev,"failed to resume headset for reboot: %d\n",+ret);+gotoout;+}+}++/* Use the same interrupt-out then SET_REPORT fallback as hidraw. */+ret=hid_hw_output_report(hdev,report,VALVE_INDEX_REPORT_SIZE);+if(ret==-ENOSYS)+ret=hid_hw_raw_request(hdev,report[0],report,+VALVE_INDEX_REPORT_SIZE,+HID_OUTPUT_REPORT,HID_REQ_SET_REPORT);+if(ret<0)+hid_warn(hdev,"failed to reboot headset: %d\n",ret);+elseif(ret!=VALVE_INDEX_REPORT_SIZE)+hid_warn(hdev,"short headset reboot report: %d\n",ret);++if(wake)+hid_hw_power(hdev,PM_HINT_NORMAL);+out:+kfree(report);+}++/*+*Thesuspendandshutdownhooksonlycoverorderlypowertransitions.After+*acrash,ahardresetorapowercuttheheadsetisleftinthestatewhere+*itsEDIDnolongerreads,andnothingrecoversituntilthenextorderly+*transition.Exposetherebootcommandasawrite-only"reboot"attribute+*ontheHIDdevicesouserspacecanrecoverit,forinstancefromaudev+*rulethatfiresonlywhentheconnectorreportsnoEDID.Writingtoan+*interfacethatdoesnotcarrytherebootreportreturns-ENODEV.+*/+staticssize_treboot_store(structdevice*dev,structdevice_attribute*attr,+constchar*buf,size_tcount)+{+structhid_device*hdev=to_hid_device(dev);+boolval;++if(kstrtobool(buf,&val))+return-EINVAL;+if(!val)+returncount;+if(!valve_index_has_reboot_report(hdev))+return-ENODEV;++valve_index_reboot(hdev,true);++returncount;+}+staticDEVICE_ATTR_WO(reboot);++staticstructattribute*valve_index_attrs[]={+&dev_attr_reboot.attr,+NULL+};+ATTRIBUTE_GROUPS(valve_index);++/*+*Theheadset'sEDIDserviceislostwhenthehostdisablestheDisplayPort+*PHYduringsystemsuspend,soitneedstherebootonthewayoutof+*suspend.Doingitonthewayindoesnotwork:theheadsetdroppingoff+*USBisaremote-wakeupeventfromitshubandabortsthesuspend.+*/
The internal hub which will be quirked by the next patch, or its parent?
It has to be the internal hub if quirking it works, no?
I guess it's easy to check this by looking up wakeup count from all the
applicable devices in sysfs while toggling the sysfs file introduced by
this patch?
From: Michal Pecio <hidden> Date: 2026-09-10 20:53:04
On Thu, 10 Sep 2026 15:43:18 -0500, Mario Limonciello wrote:
quoted
quoted
+/*
+ * The headset's EDID service is lost when the host disables the DisplayPort
+ * PHY during system suspend, so it needs the reboot on the way out of
+ * suspend. Doing it on the way in does not work: the headset dropping off
+ * USB is a remote-wakeup event from its hub and aborts the suspend.
+ */
The internal hub which will be quirked by the next patch, or its parent?
It has to be the internal hub if quirking it works, no?
I believe there are two separate problems here:
1. resetting the device at suspend causes instant wakeup
2. a few seconds later the system wakes up anyway
1. is solved by resetting on resume rather than suspend
2. is solved by the quirk
Questions:
Any chance that 2 also solves 1?
Would resetting on suspend be preferable, as the comment suggests?
Maybe it would, if the reset can race with DP seeing empty EDID?
Regards,
Michal
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-10 20:58:34
On 9/10/26 15:52, Michal Pecio wrote:
On Thu, 10 Sep 2026 15:43:18 -0500, Mario Limonciello wrote:
quoted
quoted
quoted
+/*
+ * The headset's EDID service is lost when the host disables the DisplayPort
+ * PHY during system suspend, so it needs the reboot on the way out of
+ * suspend. Doing it on the way in does not work: the headset dropping off
+ * USB is a remote-wakeup event from its hub and aborts the suspend.
+ */
The internal hub which will be quirked by the next patch, or its parent?
It has to be the internal hub if quirking it works, no?
I believe there are two separate problems here:
1. resetting the device at suspend causes instant wakeup
2. a few seconds later the system wakes up anyway
1. is solved by resetting on resume rather than suspend
2. is solved by the quirk
Questions:
Any chance that 2 also solves 1?
Would resetting on suspend be preferable, as the comment suggests?
Maybe it would, if the reset can race with DP seeing empty EDID?
I do think that resetting on suspend makes a lot more sense for that
exact reason. That's why my original PoC did it that way.
That's a very good idea to see if the quirk + moving it back to suspend
works.
On Thu, Sep 10, 2026 at 03:43:18PM -0500, Mario Limonciello wrote:
On 9/10/26 15:04, Michal Pecio wrote:
quoted
On Thu, 10 Sep 2026 12:02:53 -0500, Mario Limonciello wrote:
quoted
The Valve Index HMD stops serving its EDID after the host disables the
DisplayPort PHY. The headset remains powered by its breakout box across
suspend and shutdown, so the bad state survives and the next connector
detection reports "No EDID read". The HMD then appears as a synthesized
640x480 display until it is power-cycled.
The 64-byte HID output report 0x16 with command 0x01 reboots the headset
and restores its EDID service. Add a device-specific driver which sends
this report for system sleep transitions and orderly shutdown while leaving
runtime autosuspend alone.
Resume a runtime-suspended interface for a shutdown request and restrict
the command to the composite interface which declares report 0x16.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4333
Hmm, people say it's a regression, so it looks like at least one
alternative solution should, in theory, exist...
Right. This bug sat for a very long time hoping someone with the hardware
would bisect and we could explain what changed.
My initial suspicion is timing. But scouring the web you can see it happens
on NVIDIA hardware too.
https://forums.developer.nvidia.com/t/valve-index-initialized-in-unusable-state-on-boot/324710
So 'unlikely' that a DRM change caused it. Maybe tied to the F/W version on
the Index and it got updated from initial report to failure?
I have no idea. I don't have this hardware so I'm just trying to help these
people how I can :)
quoted
Obligatory question: does it work any better with Windows? :)
Curtis?
When I was using Windows I believe I observed a similiar behavior of the
system booting into a black screen and hanging. I remember this
occurring as far back as 2020 when I was using a 5700XT (RDNA1).
I'm willing to test on Windows again but I'll need to setup a Windows
system since I don't currently have one available.
@@ -0,0 +1,12 @@+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot+Date: October 2026+Contact: linux-input@vger.kernel.org+Description:+ Writing a boolean true value reboots the Valve Index headset to+ recover its EDID service. Writing a boolean false value has no+ effect. This file is write-only.++ The Valve Index is a composite HID device. The reboot command is+ only supported by the interface that provides the headset's 64-byte+ output report. Writing true to this file on another interface fails+ with -ENODEV.
@@ -0,0 +1,142 @@+// SPDX-License-Identifier: GPL-2.0-or-later+/*+*HIDdriverfortheValveIndexheadset+*/++#include<linux/hid.h>+#include<linux/module.h>++#include"hid-ids.h"++#define VALVE_INDEX_REBOOT_REPORT_ID 0x16+#define VALVE_INDEX_REBOOT_CMD 0x01+#define VALVE_INDEX_REPORT_SIZE 64++staticboolvalve_index_has_reboot_report(structhid_device*hdev)+{+structhid_report*report;++/*+*Therebootcommandisavendorprotocolcarriedintheunnumbered+*64-byteoutputreportoftheheadset'sthirdinterface;thefirst+*databyteisthecommandid.Report0x16isonlydeclaredasa+*featurereportandisnotwhatthecommandissentas.+*/+report=hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[0];++returnreport&&hid_report_len(report)==VALVE_INDEX_REPORT_SIZE;+}++staticvoidvalve_index_reboot(structhid_device*hdev,boolwake)+{+u8*report;+intret;++if(!valve_index_has_reboot_report(hdev))+return;++/* USB transfer buffers must be DMA-able, so not on the stack. */+report=kzalloc(VALVE_INDEX_REPORT_SIZE,GFP_KERNEL);+if(!report)+return;+report[0]=VALVE_INDEX_REBOOT_REPORT_ID;+report[1]=VALVE_INDEX_REBOOT_CMD;++if(wake){+ret=hid_hw_power(hdev,PM_HINT_FULLON);+if(ret<0){+hid_warn(hdev,"failed to resume headset for reboot: %d\n",+ret);+gotoout;+}+}++/* Use the same interrupt-out then SET_REPORT fallback as hidraw. */+ret=hid_hw_output_report(hdev,report,VALVE_INDEX_REPORT_SIZE);+if(ret==-ENOSYS)+ret=hid_hw_raw_request(hdev,report[0],report,+VALVE_INDEX_REPORT_SIZE,+HID_OUTPUT_REPORT,HID_REQ_SET_REPORT);+if(ret<0)+hid_warn(hdev,"failed to reboot headset: %d\n",ret);+elseif(ret!=VALVE_INDEX_REPORT_SIZE)+hid_warn(hdev,"short headset reboot report: %d\n",ret);++if(wake)+hid_hw_power(hdev,PM_HINT_NORMAL);+out:+kfree(report);+}++/*+*Thesuspendandshutdownhooksonlycoverorderlypowertransitions.After+*acrash,ahardresetorapowercuttheheadsetisleftinthestatewhere+*itsEDIDnolongerreads,andnothingrecoversituntilthenextorderly+*transition.Exposetherebootcommandasawrite-only"reboot"attribute+*ontheHIDdevicesouserspacecanrecoverit,forinstancefromaudev+*rulethatfiresonlywhentheconnectorreportsnoEDID.Writingtoan+*interfacethatdoesnotcarrytherebootreportreturns-ENODEV.+*/+staticssize_treboot_store(structdevice*dev,structdevice_attribute*attr,+constchar*buf,size_tcount)+{+structhid_device*hdev=to_hid_device(dev);+boolval;++if(kstrtobool(buf,&val))+return-EINVAL;+if(!val)+returncount;+if(!valve_index_has_reboot_report(hdev))+return-ENODEV;++valve_index_reboot(hdev,true);++returncount;+}+staticDEVICE_ATTR_WO(reboot);++staticstructattribute*valve_index_attrs[]={+&dev_attr_reboot.attr,+NULL+};+ATTRIBUTE_GROUPS(valve_index);++/*+*Theheadset'sEDIDserviceislostwhenthehostdisablestheDisplayPort+*PHYduringsystemsuspend,soitneedstherebootonthewayoutof+*suspend.Doingitonthewayindoesnotwork:theheadsetdroppingoff+*USBisaremote-wakeupeventfromitshubandabortsthesuspend.+*/
The internal hub which will be quirked by the next patch, or its parent?
It has to be the internal hub if quirking it works, no?
I guess it's easy to check this by looking up wakeup count from all the
applicable devices in sysfs while toggling the sysfs file introduced by this
patch?
On Thu, Sep 10, 2026 at 12:21:15PM -0500, Mario Limonciello wrote:
On 9/10/26 12:17, sashiko-bot@kernel.org wrote:
quoted
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect buffer formatting and report ID targeting in `hid_hw_raw_request` fallback for an unnumbered HID report.
--
commit 4526fbce2701e5a40089fba6ae186ded76bc0864
Author: Mario Limonciello [off-list ref]
Subject: HID: valve-index: Reboot headset on system power transitions
This commit introduces a new HID driver for the Valve Index headset to
reboot it on system power transitions. It sends a specific 64-byte report
to recover the EDID service after a DisplayPort link shutdown.
Link: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/939
+static void valve_index_reboot(struct hid_device *hdev, bool wake)
+{
+ u8 *report;
+ int ret;
+
+ if (!valve_index_has_reboot_report(hdev))
+ return;
+
+ /* USB transfer buffers must be DMA-able, so not on the stack. */
+ report = kzalloc(VALVE_INDEX_REPORT_SIZE, GFP_KERNEL);
+ if (!report)
+ return;
+ report[0] = VALVE_INDEX_REBOOT_REPORT_ID;
[Severity: Medium]
Is the report buffer sized correctly for an unnumbered report fallback?
The HID core and usbhid transport expect unnumbered report buffers to be
prefixed with a dummy 0x00 byte (so payload size + 1) for control transfers.
Allocating exactly 64 bytes and placing the payload command at index 0 might
break control transfer formatting in usbhid_set_raw_report if the fallback
path below is taken.
[ ... ]
quoted
+ /* Use the same interrupt-out then SET_REPORT fallback as hidraw. */
+ ret = hid_hw_output_report(hdev, report, VALVE_INDEX_REPORT_SIZE);
+ if (ret == -ENOSYS)
+ ret = hid_hw_raw_request(hdev, report[0], report,
+ VALVE_INDEX_REPORT_SIZE,
+ HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
[Severity: Medium]
Does this properly target the unnumbered report during the fallback?
By passing report[0] (which contains 0x16) as the reportnum argument, the
fallback control transfer will target Output Report ID 0x16 instead of the
required unnumbered report (ID 0). If hid_hw_output_report returns -ENOSYS
and this fallback is taken, the headset might reject the transfer, causing
the reboot command to fail.
quoted
+ if (ret < 0)
+ hid_warn(hdev, "failed to reboot headset: %d\n", ret);
[ ... ]
Curtis - can you check how the headset handles those cases?
On Thu, Sep 10, 2026 at 12:02:53PM -0500, Mario Limonciello wrote:
quoted hunk
The Valve Index HMD stops serving its EDID after the host disables the
DisplayPort PHY. The headset remains powered by its breakout box across
suspend and shutdown, so the bad state survives and the next connector
detection reports "No EDID read". The HMD then appears as a synthesized
640x480 display until it is power-cycled.
The 64-byte HID output report 0x16 with command 0x01 reboots the headset
and restores its EDID service. Add a device-specific driver which sends
this report for system sleep transitions and orderly shutdown while leaving
runtime autosuspend alone.
Resume a runtime-suspended interface for a shutdown request and restrict
the command to the composite interface which declares report 0x16.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4333
Link: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/939
Assisted-by: LLM
Co-developed-by: Curtis Vogt <redacted>
Signed-off-by: Curtis Vogt <redacted>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
.../ABI/testing/sysfs-driver-hid-valve-index | 12 ++
drivers/hid/Kconfig | 11 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-valve-index.c | 142 ++++++++++++++++++
5 files changed, 167 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-valve-index
create mode 100644 drivers/hid/hid-valve-index.c
@@ -0,0 +1,12 @@+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot+Date: October 2026+Contact: linux-input@vger.kernel.org+Description:+ Writing a boolean true value reboots the Valve Index headset to+ recover its EDID service. Writing a boolean false value has no+ effect. This file is write-only.
Shouldn't this just be a debugfs file? Making it a sysfs file seems
"risky" as it's not a normal operation.
+ The Valve Index is a composite HID device. The reboot command is
+ only supported by the interface that provides the headset's 64-byte
+ output report. Writing true to this file on another interface fails
+ with -ENODEV.
Why would it be present on "another interface'? That feels wrong.
thanks,
greg k-h
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-11 06:01:52
On 9/11/26 00:54, Greg Kroah-Hartman wrote:
On Thu, Sep 10, 2026 at 12:02:53PM -0500, Mario Limonciello wrote:
quoted
The Valve Index HMD stops serving its EDID after the host disables the
DisplayPort PHY. The headset remains powered by its breakout box across
suspend and shutdown, so the bad state survives and the next connector
detection reports "No EDID read". The HMD then appears as a synthesized
640x480 display until it is power-cycled.
The 64-byte HID output report 0x16 with command 0x01 reboots the headset
and restores its EDID service. Add a device-specific driver which sends
this report for system sleep transitions and orderly shutdown while leaving
runtime autosuspend alone.
Resume a runtime-suspended interface for a shutdown request and restrict
the command to the composite interface which declares report 0x16.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/4333
Link: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/939
Assisted-by: LLM
Co-developed-by: Curtis Vogt <redacted>
Signed-off-by: Curtis Vogt <redacted>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
.../ABI/testing/sysfs-driver-hid-valve-index | 12 ++
drivers/hid/Kconfig | 11 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-valve-index.c | 142 ++++++++++++++++++
5 files changed, 167 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-valve-index
create mode 100644 drivers/hid/hid-valve-index.c
@@ -0,0 +1,12 @@+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot+Date: October 2026+Contact: linux-input@vger.kernel.org+Description:+ Writing a boolean true value reboots the Valve Index headset to+ recover its EDID service. Writing a boolean false value has no+ effect. This file is write-only.
Shouldn't this just be a debugfs file? Making it a sysfs file seems
"risky" as it's not a normal operation.
Yeah I guess that makes sense.
quoted
+ The Valve Index is a composite HID device. The reboot command is
+ only supported by the interface that provides the headset's 64-byte
+ output report. Writing true to this file on another interface fails
+ with -ENODEV.
Why would it be present on "another interface'? That feels wrong.
thanks,
greg k-h
From: Michal Pecio <hidden> Date: 2026-09-11 09:09:06
On Thu, 10 Sep 2026 23:54:22 -0500, Curtis Vogt wrote:
When I was using Windows I believe I observed a similiar behavior of
the system booting into a black screen and hanging. I remember this
occurring as far back as 2020 when I was using a 5700XT (RDNA1).
I'm willing to test on Windows again but I'll need to setup a Windows
system since I don't currently have one available.
It's not extremely important, I frankly asked this question because
I didn't expect problems on Windows. I assumed it would be either:
1. Obviously, Windows resets this device every time when XYZ, therefore
Linux can just reset it the same, problem solved.
2. Windows doesn't reset anything and doesn't have any issues, clearly
Linux is broken, maybe somebody will finally bother to bisect it.
IDK if anything useful can be learned from seeing that Windows fails.
Regards,
Michal
From: Michal Pecio <hidden> Date: 2026-09-11 09:16:58
On Fri, 11 Sep 2026 07:54:12 +0200, Greg Kroah-Hartman wrote:
quoted
+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot
+Date: October 2026
+Contact: linux-input@vger.kernel.org
+Description:
+ Writing a boolean true value reboots the Valve Index headset to
+ recover its EDID service. Writing a boolean false value has no
+ effect. This file is write-only.
Shouldn't this just be a debugfs file? Making it a sysfs file seems
"risky" as it's not a normal operation.
Not sure what's "risky" about it, it's hopefully a root-only thing?
And it's the only supported way for userspace to recover buggy devices
from certain failure condition, it's been suggested that this could be
run by udev scripts. Isn't it more "risky" to ask userspace to mount
and tinker with debugfs as a matter of routine?
Regards,
Michal
On Fri, Sep 11, 2026 at 11:16:52AM +0200, Michal Pecio wrote:
On Fri, 11 Sep 2026 07:54:12 +0200, Greg Kroah-Hartman wrote:
quoted
quoted
+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot
+Date: October 2026
+Contact: linux-input@vger.kernel.org
+Description:
+ Writing a boolean true value reboots the Valve Index headset to
+ recover its EDID service. Writing a boolean false value has no
+ effect. This file is write-only.
Shouldn't this just be a debugfs file? Making it a sysfs file seems
"risky" as it's not a normal operation.
Not sure what's "risky" about it, it's hopefully a root-only thing?
And it's the only supported way for userspace to recover buggy devices
from certain failure condition, it's been suggested that this could be
run by udev scripts. Isn't it more "risky" to ask userspace to mount
and tinker with debugfs as a matter of routine?
You are creating an "odd" user/kernel api that is used for debugging,
that's not what sysfs is for. sysfs is to show attributes that a device
has NOT to cause the device to go off and do some random thing (yes,
there are exceptions, but generally that's the rule.)
debugfs is "do whatever you want", so that's a better place for this.
thanks,
greg k-h
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-11 15:12:40
On 9/11/26 04:23, Greg Kroah-Hartman wrote:
On Fri, Sep 11, 2026 at 11:16:52AM +0200, Michal Pecio wrote:
quoted
On Fri, 11 Sep 2026 07:54:12 +0200, Greg Kroah-Hartman wrote:
quoted
quoted
+What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/reboot
+Date: October 2026
+Contact: linux-input@vger.kernel.org
+Description:
+ Writing a boolean true value reboots the Valve Index headset to
+ recover its EDID service. Writing a boolean false value has no
+ effect. This file is write-only.
Shouldn't this just be a debugfs file? Making it a sysfs file seems
"risky" as it's not a normal operation.
Not sure what's "risky" about it, it's hopefully a root-only thing?
And it's the only supported way for userspace to recover buggy devices
from certain failure condition, it's been suggested that this could be
run by udev scripts. Isn't it more "risky" to ask userspace to mount
and tinker with debugfs as a matter of routine?
You are creating an "odd" user/kernel api that is used for debugging,
that's not what sysfs is for. sysfs is to show attributes that a device
has NOT to cause the device to go off and do some random thing (yes,
there are exceptions, but generally that's the rule.)
debugfs is "do whatever you want", so that's a better place for this.
thanks,
greg k-h
I suppose an alternative path we can build to all of this reset handling
at power state transitions and sysfs/debugfs is a callback system for a
failed EDID read.
Something like DRM drivers can send a notify to a global queue when an
EDID read failed. Other drivers could subscribe to that notify and
react. I guess this would only work if the USB reset sequence to the
HMD looks like an HPD event to DRM though.
Also it wouldn't be perfect. If the HMD was connected and the read
failed on an unrelated monitor on the system the HMD would reset needlessly.
Eh, I think I'm talking myself back into this approach the patch does
now. I have no qualms moving the on demand knob to debugfs.
From: Michal Pecio <hidden> Date: 2026-09-11 18:20:51
On Fri, 11 Sep 2026 10:12:34 -0500, Mario Limonciello wrote:
On 9/11/26 04:23, Greg Kroah-Hartman wrote:
quoted
On Fri, Sep 11, 2026 at 11:16:52AM +0200, Michal Pecio wrote:
quoted
On Fri, 11 Sep 2026 07:54:12 +0200, Greg Kroah-Hartman wrote:
You are creating an "odd" user/kernel api that is used for
debugging, that's not what sysfs is for. sysfs is to show
attributes that a device has NOT to cause the device to go off and
do some random thing (yes, there are exceptions, but generally
that's the rule.)
debugfs is "do whatever you want", so that's a better place for
this.
thanks,
greg k-h
I suppose an alternative path we can build to all of this reset
handling at power state transitions and sysfs/debugfs is a callback
system for a failed EDID read.
Something like DRM drivers can send a notify to a global queue when
an EDID read failed. Other drivers could subscribe to that notify
and react. I guess this would only work if the USB reset sequence to
the HMD looks like an HPD event to DRM though.
Also it wouldn't be perfect. If the HMD was connected and the read
failed on an unrelated monitor on the system the HMD would reset
needlessly.
Eh, I think I'm talking myself back into this approach the patch does
now. I have no qualms moving the on demand knob to debugfs.
Perhaps one more option is to put this in userspace, with some libusb
or HIDRAW hacking. And if it could be scripted to run on shutdown, no
kernel driver even required at all.
Regards,
Michal
On Thu, Sep 10, 2026 at 03:58:27PM -0500, Mario Limonciello wrote:
On 9/10/26 15:52, Michal Pecio wrote:
quoted
On Thu, 10 Sep 2026 15:43:18 -0500, Mario Limonciello wrote:
quoted
quoted
quoted
+/*
+ * The headset's EDID service is lost when the host disables the DisplayPort
+ * PHY during system suspend, so it needs the reboot on the way out of
+ * suspend. Doing it on the way in does not work: the headset dropping off
+ * USB is a remote-wakeup event from its hub and aborts the suspend.
+ */
The internal hub which will be quirked by the next patch, or its parent?
It has to be the internal hub if quirking it works, no?
The parent needs to be quirked: the breakout box's own hub, 28de:2613,
sits above Microchip USB2744 (0424:2744). Only the 28de:2613 hub ever
registered wakeup events, and quirking it alone is enough.
I also tested the quirk using a stock kernel (7.2.3) using the kernel
param `usbcore.quirks=28de:2613:j` which stopped the headset from waking
the host. Without that param I found that the headset would wake the
host when healthy but not when wedged.
quoted
I believe there are two separate problems here:
1. resetting the device at suspend causes instant wakeup
2. a few seconds later the system wakes up anyway
1. is solved by resetting on resume rather than suspend
2. is solved by the quirk
Questions:
Any chance that 2 also solves 1?
It does. With the quirk from 3/3 and the driver rebooting from the suspend
hook instead of resume the headset reboots during suspend entry and the
host stays asleep.
quoted
Would resetting on suspend be preferable, as the comment suggests?
Maybe it would, if the reset can race with DP seeing empty EDID?
Yes, and the log bears out the ordering concern. With the reboot on
suspend the headset is already back and so the EDID reads cleanly the
first time. With the headset reboot on resume a re-enumeration occurs.
There was no "EDID err" upon resume with either variant. We can go back to
Mario's implementation of headset reboot on suspend.
I do think that resetting on suspend makes a lot more sense for that exact
reason. That's why my original PoC did it that way.
That's a very good idea to see if the quirk + moving it back to suspend
works.
I've validated this approach works. Happy to return to it.
Diff against 2/3 moving the headset reboot back to the suspend hook:
---8<---
drivers/hid/hid-valve-index.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
From: Mario Limonciello <mario.limonciello@amd.com> Date: 2026-09-14 14:45:30
On 9/12/26 09:07, Curtis Vogt wrote:
quoted hunk
On Thu, Sep 10, 2026 at 03:58:27PM -0500, Mario Limonciello wrote:
quoted
On 9/10/26 15:52, Michal Pecio wrote:
quoted
On Thu, 10 Sep 2026 15:43:18 -0500, Mario Limonciello wrote:
quoted
quoted
quoted
+/*
+ * The headset's EDID service is lost when the host disables the DisplayPort
+ * PHY during system suspend, so it needs the reboot on the way out of
+ * suspend. Doing it on the way in does not work: the headset dropping off
+ * USB is a remote-wakeup event from its hub and aborts the suspend.
+ */
The internal hub which will be quirked by the next patch, or its parent?
It has to be the internal hub if quirking it works, no?
The parent needs to be quirked: the breakout box's own hub, 28de:2613,
sits above Microchip USB2744 (0424:2744). Only the 28de:2613 hub ever
registered wakeup events, and quirking it alone is enough.
I also tested the quirk using a stock kernel (7.2.3) using the kernel
param `usbcore.quirks=28de:2613:j` which stopped the headset from waking
the host. Without that param I found that the headset would wake the
host when healthy but not when wedged.
quoted
quoted
I believe there are two separate problems here:
1. resetting the device at suspend causes instant wakeup
2. a few seconds later the system wakes up anyway
1. is solved by resetting on resume rather than suspend
2. is solved by the quirk
Questions:
Any chance that 2 also solves 1?
It does. With the quirk from 3/3 and the driver rebooting from the suspend
hook instead of resume the headset reboots during suspend entry and the
host stays asleep.
quoted
quoted
Would resetting on suspend be preferable, as the comment suggests?
Maybe it would, if the reset can race with DP seeing empty EDID?
Yes, and the log bears out the ordering concern. With the reboot on
suspend the headset is already back and so the EDID reads cleanly the
first time. With the headset reboot on resume a re-enumeration occurs.
There was no "EDID err" upon resume with either variant. We can go back to
Mario's implementation of headset reboot on suspend.
quoted
I do think that resetting on suspend makes a lot more sense for that exact
reason. That's why my original PoC did it that way.
That's a very good idea to see if the quirk + moving it back to suspend
works.
I've validated this approach works. Happy to return to it.
Diff against 2/3 moving the headset reboot back to the suspend hook:
---8<---
drivers/hid/hid-valve-index.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
Thanks for sharing that. If we do stick to a kernel quirk we should do
it at suspend instead of resume.
But to this audience, Curtis had some other findings that libddcutil is
causing part of the problem on Linux. There is still some more
investigation to be done why (for example is it a concurrency issue for
a shared AUX resource?).
If there is still kernel patches to be neeed, they'll be posted in a v2.