chibios.c (5708B)
1 /* 2 * (c) 2015 flabberast <s3+flabbergast@sdfeu.org> 3 * 4 * Based on the following work: 5 * - Guillaume Duc's raw hid example (MIT License) 6 * https://github.com/guiduc/usb-hid-chibios-example 7 * - PJRC Teensy examples (MIT License) 8 * https://www.pjrc.com/teensy/usb_keyboard.html 9 * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD) 10 * https://github.com/tmk/tmk_keyboard/ 11 * - ChibiOS demo code (Apache 2.0 License) 12 * http://www.chibios.org 13 * 14 * Since some GPL'd code is used, this work is licensed under 15 * GPL v2 or later. 16 */ 17 18 #include <ch.h> 19 #include <hal.h> 20 21 #include "usb_main.h" 22 23 /* TMK includes */ 24 #include "report.h" 25 #include "host.h" 26 #include "host_driver.h" 27 #include "keyboard.h" 28 #include "action.h" 29 #include "action_util.h" 30 #include "usb_device_state.h" 31 #include "mousekey.h" 32 #include "led.h" 33 #include "sendchar.h" 34 #include "debug.h" 35 #include "print.h" 36 37 #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP 38 // Change this to be TRUE once we've migrated keyboards to the new init system 39 // Remember to change docs/platformdev_chibios_earlyinit.md as well. 40 # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP FALSE 41 #endif 42 43 #ifdef MIDI_ENABLE 44 # include "qmk_midi.h" 45 #endif 46 #include "suspend.h" 47 #include "wait.h" 48 49 #define USB_GETSTATUS_REMOTE_WAKEUP_ENABLED (2U) 50 51 #ifdef WAIT_FOR_USB 52 // TODO: Remove backwards compatibility with old define 53 # define USB_WAIT_FOR_ENUMERATION 54 #endif 55 56 /* ------------------------- 57 * TMK host driver defs 58 * ------------------------- 59 */ 60 61 /* declarations */ 62 void send_keyboard(report_keyboard_t *report); 63 void send_nkro(report_nkro_t *report); 64 void send_mouse(report_mouse_t *report); 65 void send_extra(report_extra_t *report); 66 void send_raw_hid(uint8_t *data, uint8_t length); 67 68 /* host struct */ 69 host_driver_t chibios_driver = { 70 .keyboard_leds = usb_device_state_get_leds, 71 .send_keyboard = send_keyboard, 72 .send_nkro = send_nkro, 73 .send_mouse = send_mouse, 74 .send_extra = send_extra, 75 #ifdef RAW_ENABLE 76 .send_raw_hid = send_raw_hid, 77 #endif 78 }; 79 80 #ifdef VIRTSER_ENABLE 81 void virtser_task(void); 82 #endif 83 84 /* TESTING 85 * Amber LED blinker thread, times are in milliseconds. 86 */ 87 /* set this variable to non-zero anywhere to blink once */ 88 // static THD_WORKING_AREA(waThread1, 128); 89 // static THD_FUNCTION(Thread1, arg) { 90 91 // (void)arg; 92 // chRegSetThreadName("blinker"); 93 // while (true) { 94 // systime_t time; 95 96 // time = USB_DRIVER.state == USB_ACTIVE ? 250 : 500; 97 // palClearLine(LINE_CAPS_LOCK); 98 // chSysPolledDelayX(MS2RTC(STM32_HCLK, time)); 99 // palSetLine(LINE_CAPS_LOCK); 100 // chSysPolledDelayX(MS2RTC(STM32_HCLK, time)); 101 // } 102 // } 103 104 /* Early initialisation 105 */ 106 __attribute__((weak)) void early_hardware_init_pre(void) { 107 #if EARLY_INIT_PERFORM_BOOTLOADER_JUMP 108 void enter_bootloader_mode_if_requested(void); 109 enter_bootloader_mode_if_requested(); 110 #endif // EARLY_INIT_PERFORM_BOOTLOADER_JUMP 111 } 112 113 __attribute__((weak)) void early_hardware_init_post(void) {} 114 115 __attribute__((weak)) void board_init(void) {} 116 117 // This overrides what's normally in ChibiOS board definitions 118 void __early_init(void) { 119 early_hardware_init_pre(); 120 121 // This is the renamed equivalent of __early_init in the board.c file 122 void __chibios_override___early_init(void); 123 __chibios_override___early_init(); 124 125 early_hardware_init_post(); 126 } 127 128 // This overrides what's normally in ChibiOS board definitions 129 void boardInit(void) { 130 // This is the renamed equivalent of boardInit in the board.c file 131 void __chibios_override_boardInit(void); 132 __chibios_override_boardInit(); 133 134 board_init(); 135 } 136 137 void protocol_setup(void) { 138 usb_device_state_init(); 139 140 // TESTING 141 // chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); 142 } 143 144 void protocol_pre_init(void) { 145 /* Init USB */ 146 usb_event_queue_init(); 147 init_usb_driver(&USB_DRIVER); 148 149 #ifdef MIDI_ENABLE 150 setup_midi(); 151 #endif 152 153 /* Wait until USB is active */ 154 #ifdef USB_WAIT_FOR_ENUMERATION 155 while (USB_DRIVER.state != USB_ACTIVE) { 156 wait_ms(50); 157 } 158 #endif 159 160 /* Do need to wait here! 161 * Otherwise the next print might start a transfer on console EP 162 * before the USB is completely ready, which sometimes causes 163 * HardFaults. 164 */ 165 wait_ms(50); 166 167 print("USB configured.\n"); 168 } 169 170 void protocol_post_init(void) { 171 host_set_driver(&chibios_driver); 172 } 173 174 void protocol_pre_task(void) { 175 usb_event_queue_task(); 176 177 #if !defined(NO_USB_STARTUP_CHECK) 178 if (USB_DRIVER.state == USB_SUSPENDED) { 179 dprintln("suspending keyboard"); 180 while (USB_DRIVER.state == USB_SUSPENDED) { 181 /* Do this in the suspended state */ 182 suspend_power_down(); // on AVR this deep sleeps for 15ms 183 /* Remote wakeup */ 184 if (suspend_wakeup_condition() && (USB_DRIVER.status & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED)) { 185 usbWakeupHost(&USB_DRIVER); 186 # if USB_SUSPEND_WAKEUP_DELAY > 0 187 // Some hubs, kvm switches, and monitors do 188 // weird things, with USB device state bouncing 189 // around wildly on wakeup, yielding race 190 // conditions that can corrupt the keyboard state. 191 // 192 // Pause for a while to let things settle... 193 wait_ms(USB_SUSPEND_WAKEUP_DELAY); 194 // ...and then update the wakeup matrix again as the waking key 195 // might have been released during the delay 196 update_matrix_state_after_wakeup(); 197 # endif 198 } 199 } 200 /* Woken up */ 201 } 202 #endif 203 } 204 205 void protocol_post_task(void) { 206 #ifdef VIRTSER_ENABLE 207 virtser_task(); 208 #endif 209 usb_idle_task(); 210 }