diff options
| author | Ryan <fauxpark@gmail.com> | 2021-02-25 15:54:25 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-25 15:54:25 +1100 |
| commit | 39694d5eb0b7e48e06f9544600041fbbedfff956 (patch) | |
| tree | 2427bbf89b955330f793fd7dad3502cfc1e19de9 /tmk_core | |
| parent | 46f4422a87bf7e3aa52bd8770b14f8361d198e06 (diff) | |
| download | qmk_firmware-39694d5eb0b7e48e06f9544600041fbbedfff956.tar.gz qmk_firmware-39694d5eb0b7e48e06f9544600041fbbedfff956.zip | |
V-USB suspend refactor (#11891)
Diffstat (limited to 'tmk_core')
| -rw-r--r-- | tmk_core/common/avr/sleep_led.c | 2 | ||||
| -rw-r--r-- | tmk_core/common/avr/suspend.c | 95 | ||||
| -rw-r--r-- | tmk_core/common/avr/suspend_avr.h | 25 | ||||
| -rw-r--r-- | tmk_core/protocol/vusb/main.c | 54 | ||||
| -rw-r--r-- | tmk_core/protocol/vusb/vusb.h | 3 |
5 files changed, 107 insertions, 72 deletions
diff --git a/tmk_core/common/avr/sleep_led.c b/tmk_core/common/avr/sleep_led.c index 63dcc2afd..9a3b52abe 100644 --- a/tmk_core/common/avr/sleep_led.c +++ b/tmk_core/common/avr/sleep_led.c | |||
| @@ -90,7 +90,7 @@ void sleep_led_toggle(void) { | |||
| 90 | * | 90 | * |
| 91 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | 91 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle |
| 92 | * | 92 | * |
| 93 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | 93 | * https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 |
| 94 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | 94 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } |
| 95 | */ | 95 | */ |
| 96 | static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | 96 | static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c index 86c3df040..cb505ab32 100644 --- a/tmk_core/common/avr/suspend.c +++ b/tmk_core/common/avr/suspend.c | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | #include <avr/interrupt.h> | 4 | #include <avr/interrupt.h> |
| 5 | #include "matrix.h" | 5 | #include "matrix.h" |
| 6 | #include "action.h" | 6 | #include "action.h" |
| 7 | #include "suspend_avr.h" | ||
| 8 | #include "suspend.h" | 7 | #include "suspend.h" |
| 9 | #include "timer.h" | 8 | #include "timer.h" |
| 10 | #include "led.h" | 9 | #include "led.h" |
| @@ -13,6 +12,9 @@ | |||
| 13 | #ifdef PROTOCOL_LUFA | 12 | #ifdef PROTOCOL_LUFA |
| 14 | # include "lufa.h" | 13 | # include "lufa.h" |
| 15 | #endif | 14 | #endif |
| 15 | #ifdef PROTOCOL_VUSB | ||
| 16 | # include "vusb.h" | ||
| 17 | #endif | ||
| 16 | 18 | ||
| 17 | #ifdef BACKLIGHT_ENABLE | 19 | #ifdef BACKLIGHT_ENABLE |
| 18 | # include "backlight.h" | 20 | # include "backlight.h" |
| @@ -52,7 +54,25 @@ __attribute__((weak)) void suspend_power_down_user(void) {} | |||
| 52 | */ | 54 | */ |
| 53 | __attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } | 55 | __attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } |
| 54 | 56 | ||
| 55 | #ifndef NO_SUSPEND_POWER_DOWN | 57 | #if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) |
| 58 | |||
| 59 | // clang-format off | ||
| 60 | #define wdt_intr_enable(value) \ | ||
| 61 | __asm__ __volatile__ ( \ | ||
| 62 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
| 63 | "cli" "\n\t" \ | ||
| 64 | "wdr" "\n\t" \ | ||
| 65 | "sts %0,%1" "\n\t" \ | ||
| 66 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
| 67 | "sts %0,%2" "\n\t" \ | ||
| 68 | : /* no outputs */ \ | ||
| 69 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
| 70 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
| 71 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | _BV(WDIE) | (value & 0x07))) \ | ||
| 72 | : "r0" \ | ||
| 73 | ) | ||
| 74 | // clang-format on | ||
| 75 | |||
| 56 | /** \brief Power down MCU with watchdog timer | 76 | /** \brief Power down MCU with watchdog timer |
| 57 | * | 77 | * |
| 58 | * wdto: watchdog timer timeout defined in <avr/wdt.h> | 78 | * wdto: watchdog timer timeout defined in <avr/wdt.h> |
| @@ -74,37 +94,11 @@ static uint8_t wdt_timeout = 0; | |||
| 74 | * FIXME: needs doc | 94 | * FIXME: needs doc |
| 75 | */ | 95 | */ |
| 76 | static void power_down(uint8_t wdto) { | 96 | static void power_down(uint8_t wdto) { |
| 77 | # ifdef PROTOCOL_LUFA | ||
| 78 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
| 79 | # endif | ||
| 80 | wdt_timeout = wdto; | 97 | wdt_timeout = wdto; |
| 81 | 98 | ||
| 82 | // Watchdog Interrupt Mode | 99 | // Watchdog Interrupt Mode |
| 83 | wdt_intr_enable(wdto); | 100 | wdt_intr_enable(wdto); |
| 84 | 101 | ||
| 85 | # ifdef BACKLIGHT_ENABLE | ||
| 86 | backlight_set(0); | ||
| 87 | # endif | ||
| 88 | |||
| 89 | // Turn off LED indicators | ||
| 90 | uint8_t leds_off = 0; | ||
| 91 | # if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE) | ||
| 92 | if (is_backlight_enabled()) { | ||
| 93 | // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off | ||
| 94 | leds_off |= (1 << USB_LED_CAPS_LOCK); | ||
| 95 | } | ||
| 96 | # endif | ||
| 97 | led_set(leds_off); | ||
| 98 | |||
| 99 | # ifdef AUDIO_ENABLE | ||
| 100 | // This sometimes disables the start-up noise, so it's been disabled | ||
| 101 | // stop_all_notes(); | ||
| 102 | # endif /* AUDIO_ENABLE */ | ||
| 103 | # if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | ||
| 104 | rgblight_suspend(); | ||
| 105 | # endif | ||
| 106 | suspend_power_down_kb(); | ||
| 107 | |||
| 108 | // TODO: more power saving | 102 | // TODO: more power saving |
| 109 | // See PicoPower application note | 103 | // See PicoPower application note |
| 110 | // - I/O port input with pullup | 104 | // - I/O port input with pullup |
| @@ -127,10 +121,46 @@ static void power_down(uint8_t wdto) { | |||
| 127 | * FIXME: needs doc | 121 | * FIXME: needs doc |
| 128 | */ | 122 | */ |
| 129 | void suspend_power_down(void) { | 123 | void suspend_power_down(void) { |
| 124 | #ifdef PROTOCOL_LUFA | ||
| 125 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
| 126 | #endif | ||
| 127 | #ifdef PROTOCOL_VUSB | ||
| 128 | if (!vusb_suspended) return; | ||
| 129 | #endif | ||
| 130 | |||
| 130 | suspend_power_down_kb(); | 131 | suspend_power_down_kb(); |
| 131 | 132 | ||
| 132 | #ifndef NO_SUSPEND_POWER_DOWN | 133 | #ifndef NO_SUSPEND_POWER_DOWN |
| 134 | // Turn off backlight | ||
| 135 | # ifdef BACKLIGHT_ENABLE | ||
| 136 | backlight_set(0); | ||
| 137 | # endif | ||
| 138 | |||
| 139 | // Turn off LED indicators | ||
| 140 | uint8_t leds_off = 0; | ||
| 141 | # if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE) | ||
| 142 | if (is_backlight_enabled()) { | ||
| 143 | // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off | ||
| 144 | leds_off |= (1 << USB_LED_CAPS_LOCK); | ||
| 145 | } | ||
| 146 | # endif | ||
| 147 | led_set(leds_off); | ||
| 148 | |||
| 149 | // Turn off audio | ||
| 150 | # ifdef AUDIO_ENABLE | ||
| 151 | // This sometimes disables the start-up noise, so it's been disabled | ||
| 152 | // stop_all_notes(); | ||
| 153 | # endif | ||
| 154 | |||
| 155 | // Turn off underglow | ||
| 156 | # if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | ||
| 157 | rgblight_suspend(); | ||
| 158 | # endif | ||
| 159 | |||
| 160 | // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt) | ||
| 161 | # if defined(WDT_vect) | ||
| 133 | power_down(WDTO_15MS); | 162 | power_down(WDTO_15MS); |
| 163 | # endif | ||
| 134 | #endif | 164 | #endif |
| 135 | } | 165 | } |
| 136 | 166 | ||
| @@ -164,17 +194,24 @@ __attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_us | |||
| 164 | void suspend_wakeup_init(void) { | 194 | void suspend_wakeup_init(void) { |
| 165 | // clear keyboard state | 195 | // clear keyboard state |
| 166 | clear_keyboard(); | 196 | clear_keyboard(); |
| 197 | |||
| 198 | // Turn on backlight | ||
| 167 | #ifdef BACKLIGHT_ENABLE | 199 | #ifdef BACKLIGHT_ENABLE |
| 168 | backlight_init(); | 200 | backlight_init(); |
| 169 | #endif | 201 | #endif |
| 202 | |||
| 203 | // Restore LED indicators | ||
| 170 | led_set(host_keyboard_leds()); | 204 | led_set(host_keyboard_leds()); |
| 205 | |||
| 206 | // Wake up underglow | ||
| 171 | #if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | 207 | #if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) |
| 172 | rgblight_wakeup(); | 208 | rgblight_wakeup(); |
| 173 | #endif | 209 | #endif |
| 210 | |||
| 174 | suspend_wakeup_init_kb(); | 211 | suspend_wakeup_init_kb(); |
| 175 | } | 212 | } |
| 176 | 213 | ||
| 177 | #ifndef NO_SUSPEND_POWER_DOWN | 214 | #if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) |
| 178 | /* watchdog timeout */ | 215 | /* watchdog timeout */ |
| 179 | ISR(WDT_vect) { | 216 | ISR(WDT_vect) { |
| 180 | // compensate timer for sleep | 217 | // compensate timer for sleep |
diff --git a/tmk_core/common/avr/suspend_avr.h b/tmk_core/common/avr/suspend_avr.h deleted file mode 100644 index 6df048f3b..000000000 --- a/tmk_core/common/avr/suspend_avr.h +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <stdint.h> | ||
| 4 | #include <stdbool.h> | ||
| 5 | #include <avr/sleep.h> | ||
| 6 | #include <avr/wdt.h> | ||
| 7 | #include <avr/interrupt.h> | ||
| 8 | |||
| 9 | // clang-format off | ||
| 10 | #define wdt_intr_enable(value) \ | ||
| 11 | __asm__ __volatile__ ( \ | ||
| 12 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
| 13 | "cli" "\n\t" \ | ||
| 14 | "wdr" "\n\t" \ | ||
| 15 | "sts %0,%1" "\n\t" \ | ||
| 16 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
| 17 | "sts %0,%2" "\n\t" \ | ||
| 18 | : /* no outputs */ \ | ||
| 19 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
| 20 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
| 21 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ | ||
| 22 | _BV(WDIE) | (value & 0x07)) ) \ | ||
| 23 | : "r0" \ | ||
| 24 | ) | ||
| 25 | // clang-format on | ||
diff --git a/tmk_core/protocol/vusb/main.c b/tmk_core/protocol/vusb/main.c index 2e8bb2fbb..af64f4e56 100644 --- a/tmk_core/protocol/vusb/main.c +++ b/tmk_core/protocol/vusb/main.c | |||
| @@ -53,10 +53,10 @@ static void initForUsbConnectivity(void) { | |||
| 53 | usbDeviceConnect(); | 53 | usbDeviceConnect(); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static void usb_remote_wakeup(void) { | 56 | static void vusb_send_remote_wakeup(void) { |
| 57 | cli(); | 57 | cli(); |
| 58 | 58 | ||
| 59 | int8_t ddr_orig = USBDDR; | 59 | uint8_t ddr_orig = USBDDR; |
| 60 | USBOUT |= (1 << USBMINUS); | 60 | USBOUT |= (1 << USBMINUS); |
| 61 | USBDDR = ddr_orig | USBMASK; | 61 | USBDDR = ddr_orig | USBMASK; |
| 62 | USBOUT ^= USBMASK; | 62 | USBOUT ^= USBMASK; |
| @@ -70,6 +70,27 @@ static void usb_remote_wakeup(void) { | |||
| 70 | sei(); | 70 | sei(); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | bool vusb_suspended = false; | ||
| 74 | |||
| 75 | static void vusb_suspend(void) { | ||
| 76 | vusb_suspended = true; | ||
| 77 | |||
| 78 | #ifdef SLEEP_LED_ENABLE | ||
| 79 | sleep_led_enable(); | ||
| 80 | #endif | ||
| 81 | |||
| 82 | suspend_power_down(); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void vusb_wakeup(void) { | ||
| 86 | vusb_suspended = false; | ||
| 87 | suspend_wakeup_init(); | ||
| 88 | |||
| 89 | #ifdef SLEEP_LED_ENABLE | ||
| 90 | sleep_led_disable(); | ||
| 91 | #endif | ||
| 92 | } | ||
| 93 | |||
| 73 | /** \brief Setup USB | 94 | /** \brief Setup USB |
| 74 | * | 95 | * |
| 75 | * FIXME: Needs doc | 96 | * FIXME: Needs doc |
| @@ -87,9 +108,8 @@ static void setup_usb(void) { | |||
| 87 | */ | 108 | */ |
| 88 | int main(void) __attribute__((weak)); | 109 | int main(void) __attribute__((weak)); |
| 89 | int main(void) { | 110 | int main(void) { |
| 90 | bool suspended = false; | ||
| 91 | #if USB_COUNT_SOF | 111 | #if USB_COUNT_SOF |
| 92 | uint16_t last_timer = timer_read(); | 112 | uint16_t sof_timer = timer_read(); |
| 93 | #endif | 113 | #endif |
| 94 | 114 | ||
| 95 | #ifdef CLKPR | 115 | #ifdef CLKPR |
| @@ -112,23 +132,24 @@ int main(void) { | |||
| 112 | while (1) { | 132 | while (1) { |
| 113 | #if USB_COUNT_SOF | 133 | #if USB_COUNT_SOF |
| 114 | if (usbSofCount != 0) { | 134 | if (usbSofCount != 0) { |
| 115 | suspended = false; | ||
| 116 | usbSofCount = 0; | 135 | usbSofCount = 0; |
| 117 | last_timer = timer_read(); | 136 | sof_timer = timer_read(); |
| 118 | # ifdef SLEEP_LED_ENABLE | 137 | if (vusb_suspended) { |
| 119 | sleep_led_disable(); | 138 | vusb_wakeup(); |
| 120 | # endif | 139 | } |
| 121 | } else { | 140 | } else { |
| 122 | // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) | 141 | // Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) |
| 123 | if (timer_elapsed(last_timer) > 5) { | 142 | if (!vusb_suspended && timer_elapsed(sof_timer) > 5) { |
| 124 | suspended = true; | 143 | vusb_suspend(); |
| 125 | # ifdef SLEEP_LED_ENABLE | ||
| 126 | sleep_led_enable(); | ||
| 127 | # endif | ||
| 128 | } | 144 | } |
| 129 | } | 145 | } |
| 130 | #endif | 146 | #endif |
| 131 | if (!suspended) { | 147 | if (vusb_suspended) { |
| 148 | vusb_suspend(); | ||
| 149 | if (suspend_wakeup_condition()) { | ||
| 150 | vusb_send_remote_wakeup(); | ||
| 151 | } | ||
| 152 | } else { | ||
| 132 | usbPoll(); | 153 | usbPoll(); |
| 133 | 154 | ||
| 134 | // TODO: configuration process is inconsistent. it sometime fails. | 155 | // TODO: configuration process is inconsistent. it sometime fails. |
| @@ -145,6 +166,7 @@ int main(void) { | |||
| 145 | raw_hid_task(); | 166 | raw_hid_task(); |
| 146 | } | 167 | } |
| 147 | #endif | 168 | #endif |
| 169 | |||
| 148 | #ifdef CONSOLE_ENABLE | 170 | #ifdef CONSOLE_ENABLE |
| 149 | usbPoll(); | 171 | usbPoll(); |
| 150 | 172 | ||
| @@ -156,8 +178,6 @@ int main(void) { | |||
| 156 | // Run housekeeping | 178 | // Run housekeeping |
| 157 | housekeeping_task_kb(); | 179 | housekeeping_task_kb(); |
| 158 | housekeeping_task_user(); | 180 | housekeeping_task_user(); |
| 159 | } else if (suspend_wakeup_condition()) { | ||
| 160 | usb_remote_wakeup(); | ||
| 161 | } | 181 | } |
| 162 | } | 182 | } |
| 163 | } | 183 | } |
diff --git a/tmk_core/protocol/vusb/vusb.h b/tmk_core/protocol/vusb/vusb.h index b4c73aaba..b1ecc98f3 100644 --- a/tmk_core/protocol/vusb/vusb.h +++ b/tmk_core/protocol/vusb/vusb.h | |||
| @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #include "host_driver.h" | 20 | #include "host_driver.h" |
| 21 | #include <usbdrv/usbdrv.h> | ||
| 21 | 22 | ||
| 22 | typedef struct usbDescriptorHeader { | 23 | typedef struct usbDescriptorHeader { |
| 23 | uchar bLength; | 24 | uchar bLength; |
| @@ -119,5 +120,7 @@ typedef struct usbConfigurationDescriptor { | |||
| 119 | 120 | ||
| 120 | #define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1)) | 121 | #define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1)) |
| 121 | 122 | ||
| 123 | extern bool vusb_suspended; | ||
| 124 | |||
| 122 | host_driver_t *vusb_driver(void); | 125 | host_driver_t *vusb_driver(void); |
| 123 | void vusb_transfer_keyboard(void); | 126 | void vusb_transfer_keyboard(void); |
