Address wake from sleep instability (#11450)

* resolve race condition between suspend and wake in LUFA

* avoid multiple calls to suspend_power_down() / suspend_wakeup_init()

* Remove duplicate suspend_power_down_kb() call

* pause on wakeup to wait for USB state to settle

* need the repeated suspend_power_down() (that's where the sleep is)

* more efficient implementation

* fine tune the pause after sending wakeup

* speculative chibios version of pause-after-wake

* make wakeup delay configurable, and adjust value

* better location for wakeup delay
This commit is contained in:
Joshua Diamond
2021-02-01 19:12:41 -05:00
committed by Drashna Jael're
parent 9ee0271c00
commit 0aaf72a2b9
4 changed files with 35 additions and 5 deletions

View File

@@ -110,7 +110,6 @@ static void power_down(uint8_t wdto) {
rgblight_disable_noeeprom(); rgblight_disable_noeeprom();
} }
# endif # endif
suspend_power_down_kb();
// TODO: more power saving // TODO: more power saving
// See PicoPower application note // See PicoPower application note

View File

@@ -12,3 +12,7 @@ void suspend_wakeup_init_user(void);
void suspend_wakeup_init_kb(void); void suspend_wakeup_init_kb(void);
void suspend_power_down_user(void); void suspend_power_down_user(void);
void suspend_power_down_kb(void); void suspend_power_down_kb(void);
#ifndef USB_SUSPEND_WAKEUP_DELAY
# define USB_SUSPEND_WAKEUP_DELAY 200
#endif

View File

@@ -701,6 +701,17 @@ void init_usb_driver(USBDriver *usbp) {
void restart_usb_driver(USBDriver *usbp) { void restart_usb_driver(USBDriver *usbp) {
usbStop(usbp); usbStop(usbp);
usbDisconnectBus(usbp); usbDisconnectBus(usbp);
#if USB_SUSPEND_WAKEUP_DELAY > 0
// Some hubs, kvm switches, and monitors do
// weird things, with USB device state bouncing
// around wildly on wakeup, yielding race
// conditions that can corrupt the keyboard state.
//
// Pause for a while to let things settle...
wait_ms(USB_SUSPEND_WAKEUP_DELAY);
#endif
usbStart(usbp, &usbcfg); usbStart(usbp, &usbcfg);
usbConnectBus(usbp); usbConnectBus(usbp);
} }

View File

@@ -498,7 +498,9 @@ void EVENT_USB_Device_Suspend() {
*/ */
void EVENT_USB_Device_WakeUp() { void EVENT_USB_Device_WakeUp() {
print("[W]"); print("[W]");
#if defined(NO_USB_STARTUP_CHECK)
suspend_wakeup_init(); suspend_wakeup_init();
#endif
#ifdef SLEEP_LED_ENABLE #ifdef SLEEP_LED_ENABLE
sleep_led_disable(); sleep_led_disable();
@@ -1184,13 +1186,27 @@ int main(void) {
print("Keyboard start.\n"); print("Keyboard start.\n");
while (1) { while (1) {
#if !defined(NO_USB_STARTUP_CHECK) #if !defined(NO_USB_STARTUP_CHECK)
while (USB_DeviceState == DEVICE_STATE_Suspended) { if (USB_DeviceState == DEVICE_STATE_Suspended) {
print("[s]"); print("[s]");
while (USB_DeviceState == DEVICE_STATE_Suspended) {
suspend_power_down(); suspend_power_down();
if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) { if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
USB_Device_SendRemoteWakeup(); USB_Device_SendRemoteWakeup();
clear_keyboard();
# if USB_SUSPEND_WAKEUP_DELAY > 0
// Some hubs, kvm switches, and monitors do
// weird things, with USB device state bouncing
// around wildly on wakeup, yielding race
// conditions that can corrupt the keyboard state.
//
// Pause for a while to let things settle...
wait_ms(USB_SUSPEND_WAKEUP_DELAY);
# endif
} }
} }
suspend_wakeup_init();
}
#endif #endif
keyboard_task(); keyboard_task();