@@ -68,16 +68,49 @@ int main(void)
6868 [](usb::df::device& dev, usb::df::device::event ev)
6969 {
7070 using event = enum usb::df::device::event;
71+ using namespace std ::literals;
72+ static high_resolution_mouse<>::resolution_multiplier_report report_backup{};
73+ static os::zephyr::tick_timer::time_point last_reset_time{};
74+
75+ /* Linux hosts produce erroneous behavior when waking up (on a subset of USB ports):
76+ * 1. L2 -> L0
77+ * 2. USB reset
78+ * 3. L0 -> L2
79+ * 4. L2 -> L0
80+ * 5. USB re-enumeration, this time without negotiating high-resolution scrolling
81+ */
7182 if (ev == event::CONFIGURATION_CHANGE )
7283 {
73- LOG_INF (" USB configured: %u, granted current: %uuA" , dev.configured (),
84+ LOG_INF (" USB configured: %u, granted current: %uuA" , ( unsigned ) dev.configured (),
7485 dev.granted_bus_current_uA ());
86+ if (!dev.configured ())
87+ {
88+ last_reset_time = os::zephyr::tick_timer::now ();
89+ }
7590 }
7691 else
7792 {
7893 LOG_INF (" USB power state: %s, granted current: %uuA" ,
7994 magic_enum::enum_name (dev.power_state ()).data (),
8095 dev.granted_bus_current_uA ());
96+ if (dev.power_state () == usb::power::state::L2_SUSPEND )
97+ {
98+ if (dev.configured ())
99+ {
100+ report_backup = mouse ().multiplier_report ();
101+ }
102+ else if (std::chrono::duration_cast<std::chrono::milliseconds>(
103+ os::zephyr::tick_timer::now () - last_reset_time) < 20ms)
104+ {
105+ // reset happened recently, restore the last known multiplier
106+ mouse ().set_report (
107+ high_resolution_mouse<>::resolution_multiplier_report::type (),
108+ std::span<const uint8_t >(
109+ const_cast <const uint8_t *>(report_backup.data ()),
110+ sizeof (report_backup)));
111+ LOG_INF (" restored multiplier: %x" , report_backup.resolutions );
112+ }
113+ }
81114 }
82115 });
83116
0 commit comments