Squashed 'tmk_core/' changes from 57d27a8..08ce4c3
authortmk <hasu@tmk-kbd.com>
Thu, 11 Feb 2016 03:21:21 +0000 (12:21 +0900)
committertmk <hasu@tmk-kbd.com>
Thu, 11 Feb 2016 03:21:21 +0000 (12:21 +0900)
08ce4c3 Add update for chibios in README
30cac1d Merge remote-tracking branch 'flabbergast-tmk_keyboard/chibios'
f218a38 core: Remove unused warning. Fix tmk_keyboard/#293
3e68807 Chibios: add more guards for transmitting (fix a deadlock bug).
cecc807 core: Speed up compilation
d01d959 Merge remote-tracking branch 'upstream/master' into chibios
8ff12ae Merge pull request #230 from jerryen/master
3afb83d core: Add note about sudo and git
2525d5d Chibios: Update to new USB API.
2fc5cd6 Merge branch 'master' into chibios
6f5511a core: Fix variable initialize
02a15fa core: Fix variable init and header include
1833ca1 Merge pull request #292 from obones/command_warning
bc9dc6f Merge pull request #294 from shayneholmes/fix-debug-message
c1b891b Merge pull request #295 from doopai/master
1da837c core: Add macro commands SM(), RM() and CM()
d9d5a93 Add support for storing, restoring and clearing modifiers in macros
4f371c0 core: Add dfu-programmer example to doc/build.md
ba3792e core: Fix doc/build.md
4b99fed remove  SERIAL_SOFT_DEBUG macro
984accb Fix typo in bootmagic debug message
67a7ea1 usb_usb: Fix for keymap editor
2fc9ae4 host_driver is only used if KEYBOARD_LOCK_ENABLE is defined
a35cdea Chibios: add 'core/protocol' to the makefiles' search path.
5ed2fd6 Merge remote-tracking branch 'upstream/master' into chibios
bbc4851 Do timeout when writing to CONSOLE EP queue.
2450559 Remove an errant comma trailing the KC_ERAS macro alias
8465747 Merge pull request #270 from jeffgran/single-tap-toggle
a37339a Merge pull request #271 from jeffgran/default-layer-toggle
8e732f7 core: Update doc/build.md and remove other_projects.md
e47dc15 Workaround for compiler warnings when console disabled.
4184c52 Add maple mini code.
b555238 core: Fix rules.mk for dfu target
26dacf4 add ACTION_DEFAULT_LAYER_TOGGLE to toggle a default layer on/off
83607d9 enable TAPPING_TOGGLE=1 to work correctly
bef3089 Merge branch 'master' into chibios
f7a55fd core: Fix debug print of usb_hid
1402f7d core: Add keycode KC_JPY for JIS
8e3a460 Chibios: Remove the wait in the main loop.
7d41746 ChibiOS: prettify/document sleep_led code.
235cdee ChibiOS: Update infinity bootloader code to match updated ChibiOS.
807bf1e Chibios: Add breathing sleep LED on Kinetis MCUs.
ba3bf7c ChibiOS: make reset request more CMSISy.
bf2ffd4 Add correct chibios/bootloader_jump for infinity KB.
f5e03fd Chibios/usb_main: rename a variable for clarity.
63a330c Fix drop key stroke
d8f5b06 Fix report size of boot protocol.
38abb50 ChibiOS/STM32: send remote wakeup.
6725650 ChibiOS/kinetis: sending remote wakeup.
69f6e54 Chibios: use WFI in idle. WIP suspend stuff.
02f044b Move chibios/cortex selection to local Makefiles.
fa59dfa Rename chibios example keyboard.
5c060de Add eeprom support for chibios/kinetis.
efd0044 Move declaration of keymap_config.
7196b24 Make bootmagic.c code portable (_delay_ms -> wait_ms).
37b15b2 Add missing #include to keymap.c.
31316e3 Merge branch 'master' into chibios
166f312 Fix chibios/usb_main GET_REPORT handing.
57ac6c2 Add ARM Teensies bootloader code.
1758086 Move STM32 bootloader address config to separate .h file.
03bb026 Rename some Makefile defines.
76ba6ac NKRO fixes.
06498f8 Update chibios README.
db0a4f5 Add basic sleep_led for chibios.
c3f930e Move AVR specific sleep_led.c into avr.
4069494 Fix bootloader-jump compiling.
9117f7b Small updates.
269cb85 Implement jump-to-bootloader.
7e81b34 Move chibios to tool.
923a892 Make usb_main more USB_DRIVER #define independent.
aa054f0 Add ChibiOS support (USB stack + support files).
1e3e282 Modularity and gcc warnings fixes.
2f60ce0 Add KEYBOARD_LOCK_ENABLE to makefile

git-subtree-dir: tmk_core
git-subtree-split: 08ce4c3021d2ecd446c5b9a137aded65423d241e

41 files changed:
README.md
common.mk
common/action.c
common/action_code.h
common/action_macro.c
common/action_macro.h
common/action_tapping.c
common/avr/sleep_led.c [moved from common/sleep_led.c with 100% similarity]
common/bootmagic.c
common/chibios/bootloader.c [new file with mode: 0644]
common/chibios/eeconfig.c [new file with mode: 0644]
common/chibios/printf.c [new file with mode: 0644]
common/chibios/printf.h [new file with mode: 0644]
common/chibios/sleep_led.c [new file with mode: 0644]
common/chibios/suspend.c [new file with mode: 0644]
common/chibios/timer.c [new file with mode: 0644]
common/command.c
common/keycode.h
common/keymap.c
common/keymap.h
common/nodebug.h
common/print.c
common/print.h
common/progmem.h
common/report.h
common/wait.h
doc/build.md
doc/keymap.md
doc/other_projects.md [deleted file]
protocol/chibios/README.md [new file with mode: 0644]
protocol/chibios/main.c [new file with mode: 0644]
protocol/chibios/usb_main.c [new file with mode: 0644]
protocol/chibios/usb_main.h [new file with mode: 0644]
protocol/serial_soft.c
protocol/usb_hid/parser.cpp
rules.mk
tool/chibios/.gitignore [new file with mode: 0644]
tool/chibios/ch-bootloader-jump.patch [new file with mode: 0644]
tool/chibios/chibios.mk [new file with mode: 0644]
tool/chibios/common.mk [new file with mode: 0644]
tool/mbed/common.mk

index 6b6714a6a25a4c2da86499b4f082bf54e38381ff..f460d0ed44aaf7079b2ae47273fe9f36f09c8b43 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,6 +5,16 @@ This is a keyboard firmware library with some useful features for Atmel AVR and
 Source code is available here: <https://github.com/tmk/tmk_keyboard/tree/core>
 
 
+Updates
+-------
+#### 2016/02/10
+flabbergast's Chibios protocol was merged from <https://github.com/flabbergast/tmk_keyboard/tree/chibios>. See [protocol/chibios/README.md](protocol/chibios/README.md). Chibios protocol supports Cortex-M such as STM32 and Kinetis.
+
+#### 2015/04/22
+separated with TMK Keyboard Firmware Collection
+
+
+
 Features
 --------
 These features can be used in your keyboard.
@@ -27,12 +37,6 @@ These features can be used in your keyboard.
 
 
 
-Updates
--------
-2015/04/22  separated with TMK Keyboard Firmware Collection
-
-
-
 TMK Keyboard Firmware Collection
 --------------------------------
 Complete firmwares for various keyboards and protocol converters.
index cb030b331333cd45cc965a4433819174faa92c01..ebaafd1d311deb55ca1ed0ae5ef37da947ebc622 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -1,4 +1,4 @@
-COMMON_DIR = common
+COMMON_DIR = $(TMK_DIR)/common
 SRC += $(COMMON_DIR)/host.c \
        $(COMMON_DIR)/keyboard.c \
        $(COMMON_DIR)/action.c \
@@ -53,8 +53,12 @@ ifdef USB_6KRO_ENABLE
     OPT_DEFS += -DUSB_6KRO_ENABLE
 endif
 
+ifdef KEYBOARD_LOCK_ENABLE
+    OPT_DEFS += -DKEYBOARD_LOCK_ENABLE
+endif
+
 ifdef SLEEP_LED_ENABLE
-    SRC += $(COMMON_DIR)/sleep_led.c
+    SRC += $(COMMON_DIR)/avr/sleep_led.c
     OPT_DEFS += -DSLEEP_LED_ENABLE
     OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
 endif
@@ -77,7 +81,8 @@ ifdef KEYMAP_SECTION_ENABLE
 endif
 
 # Version string
-OPT_DEFS += -DVERSION=$(shell (git describe --always --dirty || echo 'unknown') 2> /dev/null)
+VERSION := $(shell (git describe --always --dirty || echo 'unknown') 2> /dev/null)
+OPT_DEFS += -DVERSION=$(VERSION)
 
 
 # Search Path
index 1f15bd091861735b1b621510edb1e161035896ea..339b3ee67edf6628f30b33fc64cd63ea834b1a96 100644 (file)
@@ -131,10 +131,17 @@ void process_action(keyrecord_t *record)
                     case MODS_TAP_TOGGLE:
                         if (event.pressed) {
                             if (tap_count <= TAPPING_TOGGLE) {
-                                register_mods(mods);
+                                if (mods & get_mods()) {
+                                    dprint("MODS_TAP_TOGGLE: toggle mods off\n");
+                                    unregister_mods(mods);
+                                } else {
+                                    dprint("MODS_TAP_TOGGLE: toggle mods on\n");
+                                    register_mods(mods);
+                                }
                             }
                         } else {
                             if (tap_count < TAPPING_TOGGLE) {
+                                dprint("MODS_TAP_TOGGLE: release : unregister_mods\n");
                                 unregister_mods(mods);
                             }
                         }
index 4fe9c1d581fcf19064c563bad186e46ec2172847..da93f77b2276760850e157364882497de2962145 100644 (file)
@@ -255,6 +255,7 @@ enum layer_pram_tap_op {
 #define ACTION_LAYER_TAP(layer, key)                (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))
 /* Default Layer */
 #define ACTION_DEFAULT_LAYER_SET(layer)             ACTION_DEFAULT_LAYER_BIT_SET((layer)/4, 1<<((layer)%4))
+#define ACTION_DEFAULT_LAYER_TOGGLE(layer)          ACTION_DEFAULT_LAYER_BIT_XOR((layer)/4, 1<<((layer)%4))
 /* Layer Operation */
 #define ACTION_LAYER_CLEAR(on)                      ACTION_LAYER_BIT_AND(0, 0, (on))
 #define ACTION_LAYER_MOMENTARY(layer)               ACTION_LAYER_ON_OFF(layer)
index ffaf125c06ce8850c8e66135a71ef07c986513ba..b2891bf4bc9cc34a72dc42f5cf6b2bcd5699e0d4 100644 (file)
@@ -34,6 +34,8 @@ void action_macro_play(const macro_t *macro_p)
     macro_t macro = END;
     uint8_t interval = 0;
 
+    uint8_t mod_storage = 0;
+
     if (!macro_p) return;
     while (true) {
         switch (MACRO_READ()) {
@@ -66,6 +68,17 @@ void action_macro_play(const macro_t *macro_p)
                 interval = MACRO_READ();
                 dprintf("INTERVAL(%u)\n", interval);
                 break;
+            case MOD_STORE:
+                mod_storage = get_mods();
+                break;
+            case MOD_RESTORE:
+                set_mods(mod_storage);
+                send_keyboard_report();
+                break;
+            case MOD_CLEAR:
+                clear_mods();
+                send_keyboard_report();
+                break;
             case 0x04 ... 0x73:
                 dprintf("DOWN(%02X)\n", macro);
                 register_code(macro);
index aedc32ec6b2c428e53cd24d3d5c105eb1f1143eb..4cf2216dad0a6a0571dd5ecc579f874c266f70c7 100644 (file)
@@ -64,6 +64,9 @@ enum macro_command_id{
     /* 0x74 - 0x83 */
     WAIT                = 0x74,
     INTERVAL,
+    MOD_STORE,
+    MOD_RESTORE,
+    MOD_CLEAR,
 
     /* 0x84 - 0xf3 (reserved for keycode up) */
 
@@ -82,6 +85,9 @@ enum macro_command_id{
 #define TYPE(key)       DOWN(key), UP(key)
 #define WAIT(ms)        WAIT, (ms)
 #define INTERVAL(ms)    INTERVAL, (ms)
+#define STORE()         MOD_STORE
+#define RESTORE()       MOD_RESTORE
+#define CLEAR()         MOD_CLEAR
 
 /* key down */
 #define D(key)          DOWN(KC_##key)
@@ -93,6 +99,12 @@ enum macro_command_id{
 #define W(ms)           WAIT(ms)
 /* interval */
 #define I(ms)           INTERVAL(ms)
+/* store modifier(s) */
+#define SM()            STORE()
+/* restore modifier(s) */
+#define RM()            RESTORE()
+/* clear modifier(s) */
+#define CM()            CLEAR()
 
 /* for backward comaptibility */
 #define MD(key)         DOWN(KC_##key)
index 826c2330966a00050565b1358e6ee43f0baa0814..a3a5a7d0f82264a52e16aed20a958d799a982644 100644 (file)
@@ -30,7 +30,6 @@ static bool process_tapping(keyrecord_t *record);
 static bool waiting_buffer_enq(keyrecord_t record);
 static void waiting_buffer_clear(void);
 static bool waiting_buffer_typed(keyevent_t event);
-static bool waiting_buffer_has_anykey_pressed(void);
 static void waiting_buffer_scan_tap(void);
 static void debug_tapping_key(void);
 static void debug_waiting_buffer(void);
@@ -257,7 +256,7 @@ bool process_tapping(keyrecord_t *keyp)
                     return true;
                 }
             } else {
-                if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
+                if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n") {};
                 process_action(keyp);
                 return true;
             }
@@ -324,14 +323,6 @@ bool waiting_buffer_typed(keyevent_t event)
     return false;
 }
 
-bool waiting_buffer_has_anykey_pressed(void)
-{
-    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
-        if (waiting_buffer[i].event.pressed) return true;
-    }
-    return false;
-}
-
 /* scan buffer for tapping */
 void waiting_buffer_scan_tap(void)
 {
similarity index 100%
rename from common/sleep_led.c
rename to common/avr/sleep_led.c
index b002a585622029f998a94adf8d95d2fa0ce7672b..08241f7de3d360ea7a0904ff305b7045d69fffe1 100644 (file)
@@ -1,6 +1,6 @@
 #include <stdint.h>
 #include <stdbool.h>
-#include <util/delay.h>
+#include "wait.h"
 #include "matrix.h"
 #include "bootloader.h"
 #include "debug.h"
@@ -10,6 +10,7 @@
 #include "eeconfig.h"
 #include "bootmagic.h"
 
+keymap_config_t keymap_config;
 
 void bootmagic(void)
 {
@@ -19,9 +20,9 @@ void bootmagic(void)
     }
 
     /* do scans in case of bounce */
-    print("boogmagic scan: ... ");
+    print("bootmagic scan: ... ");
     uint8_t scan = 100;
-    while (scan--) { matrix_scan(); _delay_ms(10); }
+    while (scan--) { matrix_scan(); wait_ms(10); }
     print("done.\n");
 
     /* bootmagic skip */
diff --git a/common/chibios/bootloader.c b/common/chibios/bootloader.c
new file mode 100644 (file)
index 0000000..c8888f3
--- /dev/null
@@ -0,0 +1,46 @@
+#include "bootloader.h"
+
+#include "ch.h"
+#include "hal.h"
+
+#ifdef STM32_BOOTLOADER_ADDRESS
+/* STM32 */
+
+#if defined(STM32F0XX)
+/* This code should be checked whether it runs correctly on platforms */
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+extern uint32_t __ram0_end__;
+
+void bootloader_jump(void) {
+  *((unsigned long *)(SYMVAL(__ram0_end__) - 4)) = 0xDEADBEEF; // set magic flag => reset handler will jump into boot loader
+   NVIC_SystemReset();
+}
+
+#else /* defined(STM32F0XX) */
+#error Check that the bootloader code works on your platform and add it to bootloader.c!
+#endif /* defined(STM32F0XX) */
+
+#elif defined(KL2x) || defined(K20x) /* STM32_BOOTLOADER_ADDRESS */
+/* Kinetis */
+
+#if defined(KIIBOHD_BOOTLOADER)
+/* Kiibohd Bootloader (MCHCK and Infinity KB) */
+#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
+const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
+void bootloader_jump(void) {
+  __builtin_memcpy((void *)VBAT, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
+  // request reset
+  SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
+}
+
+#else /* defined(KIIBOHD_BOOTLOADER) */
+/* Default for Kinetis - expecting an ARM Teensy */
+void bootloader_jump(void) {
+       chThdSleepMilliseconds(100);
+       __BKPT(0);
+}
+#endif /* defined(KIIBOHD_BOOTLOADER) */
+
+#else /* neither STM32 nor KINETIS */
+void bootloader_jump(void) {}
+#endif
\ No newline at end of file
diff --git a/common/chibios/eeconfig.c b/common/chibios/eeconfig.c
new file mode 100644 (file)
index 0000000..f9e2718
--- /dev/null
@@ -0,0 +1,551 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "eeconfig.h"
+
+/*************************************/
+/*          Hardware backend         */
+/*                                   */
+/*    Code from PJRC/Teensyduino     */
+/*************************************/
+
+/* Teensyduino Core Library
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2013 PJRC.COM, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be 
+ * included in all copies or substantial portions of the Software.
+ *
+ * 2. If the Software is incorporated into a build system that allows 
+ * selection among a list of target devices, then similar target
+ * devices manufactured by PJRC.COM must be included in the list of
+ * target devices and selectable in the same manner.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#if defined(K20x) /* chip selection */
+/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
+
+// The EEPROM is really RAM with a hardware-based backup system to
+// flash memory.  Selecting a smaller size EEPROM allows more wear
+// leveling, for higher write endurance.  If you edit this file,
+// set this to the smallest size your application can use.  Also,
+// due to Freescale's implementation, writing 16 or 32 bit words
+// (aligned to 2 or 4 byte boundaries) has twice the endurance
+// compared to writing 8 bit bytes.
+//
+#define EEPROM_SIZE 32
+
+// Writing unaligned 16 or 32 bit data is handled automatically when
+// this is defined, but at a cost of extra code size.  Without this,
+// any unaligned write will cause a hard fault exception!  If you're
+// absolutely sure all 16 and 32 bit writes will be aligned, you can
+// remove the extra unnecessary code.
+//
+#define HANDLE_UNALIGNED_WRITES
+
+// Minimum EEPROM Endurance
+// ------------------------
+#if (EEPROM_SIZE == 2048)      // 35000 writes/byte or 70000 writes/word
+  #define EEESIZE 0x33
+#elif (EEPROM_SIZE == 1024)    // 75000 writes/byte or 150000 writes/word
+  #define EEESIZE 0x34
+#elif (EEPROM_SIZE == 512)     // 155000 writes/byte or 310000 writes/word
+  #define EEESIZE 0x35
+#elif (EEPROM_SIZE == 256)     // 315000 writes/byte or 630000 writes/word
+  #define EEESIZE 0x36
+#elif (EEPROM_SIZE == 128)     // 635000 writes/byte or 1270000 writes/word
+  #define EEESIZE 0x37
+#elif (EEPROM_SIZE == 64)      // 1275000 writes/byte or 2550000 writes/word
+  #define EEESIZE 0x38
+#elif (EEPROM_SIZE == 32)      // 2555000 writes/byte or 5110000 writes/word
+  #define EEESIZE 0x39
+#endif
+
+void eeprom_initialize(void)
+{
+       uint32_t count=0;
+       uint16_t do_flash_cmd[] = {
+               0xf06f, 0x037f, 0x7003, 0x7803,
+               0xf013, 0x0f80, 0xd0fb, 0x4770};
+       uint8_t status;
+
+       if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
+               // FlexRAM is configured as traditional RAM
+               // We need to reconfigure for EEPROM usage
+               FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
+               FTFL->FCCOB4 = EEESIZE; // EEPROM Size
+               FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
+               __disable_irq();
+               // do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
+               (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
+               __enable_irq();
+               status = FTFL->FSTAT;
+               if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
+                       FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
+                       return; // error
+               }
+       }
+       // wait for eeprom to become ready (is this really necessary?)
+       while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+               if (++count > 20000) break;
+       }
+}
+
+#define FlexRAM ((uint8_t *)0x14000000)
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       if (offset >= EEPROM_SIZE) return 0;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       return FlexRAM[offset];
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       if (offset >= EEPROM_SIZE-1) return 0;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       return *(uint16_t *)(&FlexRAM[offset]);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       if (offset >= EEPROM_SIZE-3) return 0;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       return *(uint32_t *)(&FlexRAM[offset]);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+       uint32_t offset = (uint32_t)addr;
+       uint8_t *dest = (uint8_t *)buf;
+       uint32_t end = offset + len;
+       
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       if (end > EEPROM_SIZE) end = EEPROM_SIZE;
+       while (offset < end) {
+               *dest++ = FlexRAM[offset++];
+       }
+}
+
+int eeprom_is_ready(void)
+{
+       return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
+}
+
+static void flexram_wait(void)
+{
+       while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+               // TODO: timeout
+       }
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value)
+{
+       uint32_t offset = (uint32_t)addr;
+
+       if (offset >= EEPROM_SIZE) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       if (FlexRAM[offset] != value) {
+               FlexRAM[offset] = value;
+               flexram_wait();
+       }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+       uint32_t offset = (uint32_t)addr;
+
+       if (offset >= EEPROM_SIZE-1) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+       if ((offset & 1) == 0) {
+#endif
+               if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+                       *(uint16_t *)(&FlexRAM[offset]) = value;
+                       flexram_wait();
+               }
+#ifdef HANDLE_UNALIGNED_WRITES
+       } else {
+               if (FlexRAM[offset] != value) {
+                       FlexRAM[offset] = value;
+                       flexram_wait();
+               }
+               if (FlexRAM[offset + 1] != (value >> 8)) {
+                       FlexRAM[offset + 1] = value >> 8;
+                       flexram_wait();
+               }
+       }
+#endif
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+       uint32_t offset = (uint32_t)addr;
+
+       if (offset >= EEPROM_SIZE-3) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+       switch (offset & 3) {
+       case 0:
+#endif
+               if (*(uint32_t *)(&FlexRAM[offset]) != value) {
+                       *(uint32_t *)(&FlexRAM[offset]) = value;
+                       flexram_wait();
+               }
+               return;
+#ifdef HANDLE_UNALIGNED_WRITES
+       case 2:
+               if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+                       *(uint16_t *)(&FlexRAM[offset]) = value;
+                       flexram_wait();
+               }
+               if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
+                       *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
+                       flexram_wait();
+               }
+               return;
+       default:
+               if (FlexRAM[offset] != value) {
+                       FlexRAM[offset] = value;
+                       flexram_wait();
+               }
+               if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
+                       *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
+                       flexram_wait();
+               }
+               if (FlexRAM[offset + 3] != (value >> 24)) {
+                       FlexRAM[offset + 3] = value >> 24;
+                       flexram_wait();
+               }
+       }
+#endif
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+       uint32_t offset = (uint32_t)addr;
+       const uint8_t *src = (const uint8_t *)buf;
+
+       if (offset >= EEPROM_SIZE) return;
+       if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+       if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
+       if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
+       while (len > 0) {
+               uint32_t lsb = offset & 3;
+               if (lsb == 0 && len >= 4) {
+                       // write aligned 32 bits
+                       uint32_t val32;
+                       val32 = *src++;
+                       val32 |= (*src++ << 8);
+                       val32 |= (*src++ << 16);
+                       val32 |= (*src++ << 24);
+                       if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
+                               *(uint32_t *)(&FlexRAM[offset]) = val32;
+                               flexram_wait();
+                       }
+                       offset += 4;
+                       len -= 4;
+               } else if ((lsb == 0 || lsb == 2) && len >= 2) {
+                       // write aligned 16 bits
+                       uint16_t val16;
+                       val16 = *src++;
+                       val16 |= (*src++ << 8);
+                       if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
+                               *(uint16_t *)(&FlexRAM[offset]) = val16;
+                               flexram_wait();
+                       }
+                       offset += 2;
+                       len -= 2;
+               } else {
+                       // write 8 bits
+                       uint8_t val8 = *src++;
+                       if (FlexRAM[offset] != val8) {
+                               FlexRAM[offset] = val8;
+                               flexram_wait();
+                       }
+                       offset++;
+                       len--;
+               }
+       }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+       *fstat = 0x80;
+       while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+   0:  f06f 037f       mvn.w   r3, #127        ; 0x7f
+   4:  7003            strb    r3, [r0, #0]
+   6:  7803            ldrb    r3, [r0, #0]
+   8:  f013 0f80       tst.w   r3, #128        ; 0x80
+   c:  d0fb            beq.n   6 <do_flash_cmd+0x6>
+   e:  4770            bx      lr
+*/
+
+#elif defined(KL2x) /* chip selection */
+/* Teensy LC (emulated) */
+
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+
+extern uint32_t __eeprom_workarea_start__;
+extern uint32_t __eeprom_workarea_end__;
+
+#define EEPROM_SIZE 128
+
+static uint32_t flashend = 0;
+
+void eeprom_initialize(void)
+{
+       const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+
+       do {
+               if (*p++ == 0xFFFF) {
+                       flashend = (uint32_t)(p - 2);
+                       return;
+               }
+       } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
+       flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
+}
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+       uint32_t offset = (uint32_t)addr;
+       const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+       const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
+       uint16_t val;
+       uint8_t data=0xFF;
+
+       if (!end) {
+               eeprom_initialize();
+               end = (const uint16_t *)((uint32_t)flashend);
+       }
+       if (offset < EEPROM_SIZE) {
+               while (p <= end) {
+                       val = *p++;
+                       if ((val & 255) == offset) data = val >> 8;
+               }
+       }
+       return data;
+}
+
+static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
+{
+       // with great power comes great responsibility....
+       uint32_t stat;
+       *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
+       *(uint32_t *)&(FTFA->FCCOB7) = data;
+       __disable_irq();
+       (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
+       __enable_irq();
+       stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
+       if (stat) {
+               FTFA->FSTAT = stat;
+       }
+       MCM->PLACR |= MCM_PLACR_CFCC;
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t data)
+{
+       uint32_t offset = (uint32_t)addr;
+       const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
+       uint32_t i, val, flashaddr;
+       uint16_t do_flash_cmd[] = {
+               0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
+       uint8_t buf[EEPROM_SIZE];
+
+       if (offset >= EEPROM_SIZE) return;
+       if (!end) {
+               eeprom_initialize();
+               end = (const uint16_t *)((uint32_t)flashend);
+       }
+       if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
+               val = (data << 8) | offset;
+               flashaddr = (uint32_t)end;
+               flashend = flashaddr;
+               if ((flashaddr & 2) == 0) {
+                       val |= 0xFFFF0000;
+               } else {
+                       val <<= 16;
+                       val |= 0x0000FFFF;
+               }
+               flash_write(do_flash_cmd, flashaddr, val);
+       } else {
+               for (i=0; i < EEPROM_SIZE; i++) {
+                       buf[i] = 0xFF;
+               }
+               for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
+                       val = *p;
+                       if ((val & 255) < EEPROM_SIZE) {
+                               buf[val & 255] = val >> 8;
+                       }
+               }
+               buf[offset] = data;
+               for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
+                       *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
+                       __disable_irq();
+                       (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
+                       __enable_irq();
+                       val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
+                       if (val) FTFA->FSTAT = val;
+                       MCM->PLACR |= MCM_PLACR_CFCC;
+               }
+               flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
+               for (i=0; i < EEPROM_SIZE; i++) {
+                       if (buf[i] == 0xFF) continue;
+                       if ((flashaddr & 2) == 0) {
+                               val = (buf[i] << 8) | i;
+                       } else {
+                               val = val | (buf[i] << 24) | (i << 16);
+                               flash_write(do_flash_cmd, flashaddr, val);
+                       }
+                       flashaddr += 2;
+               }
+               flashend = flashaddr;
+               if ((flashaddr & 2)) {
+                       val |= 0xFFFF0000;
+                       flash_write(do_flash_cmd, flashaddr, val);
+               }
+       }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+        *fstat = 0x80;
+        while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+   0:  2380            movs    r3, #128        ; 0x80
+   2:  7003            strb    r3, [r0, #0]
+   4:  7803            ldrb    r3, [r0, #0]
+   6:  b25b            sxtb    r3, r3
+   8:  2b00            cmp     r3, #0
+   a:  dafb            bge.n   4 <do_flash_cmd+0x4>
+   c:  4770            bx      lr
+*/
+
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+       const uint8_t *p = (const uint8_t *)addr;
+       return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+       const uint8_t *p = (const uint8_t *)addr;
+       return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+               | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+       const uint8_t *p = (const uint8_t *)addr;
+       uint8_t *dest = (uint8_t *)buf;
+       while (len--) {
+               *dest++ = eeprom_read_byte(p++);
+       }
+}
+
+int eeprom_is_ready(void)
+{
+       return 1;
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+       uint8_t *p = (uint8_t *)addr;
+       eeprom_write_byte(p++, value);
+       eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+       uint8_t *p = (uint8_t *)addr;
+       eeprom_write_byte(p++, value);
+       eeprom_write_byte(p++, value >> 8);
+       eeprom_write_byte(p++, value >> 16);
+       eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+       uint8_t *p = (uint8_t *)addr;
+       const uint8_t *src = (const uint8_t *)buf;
+       while (len--) {
+               eeprom_write_byte(p++, *src++);
+       }
+}
+
+#else
+#error EEPROM support not implemented for your chip
+#endif /* chip selection */
+
+
+/*****************/
+/* TMK functions */
+/*****************/
+
+void eeconfig_init(void)
+{
+    eeprom_write_word(EECONFIG_MAGIC,          EECONFIG_MAGIC_NUMBER);
+    eeprom_write_byte(EECONFIG_DEBUG,          0);
+    eeprom_write_byte(EECONFIG_DEFAULT_LAYER,  0);
+    eeprom_write_byte(EECONFIG_KEYMAP,         0);
+    eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
+#ifdef BACKLIGHT_ENABLE
+    eeprom_write_byte(EECONFIG_BACKLIGHT,      0);
+#endif
+}
+
+void eeconfig_enable(void)
+{
+    eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
+}
+
+void eeconfig_disable(void)
+{
+    eeprom_write_word(EECONFIG_MAGIC, 0xFFFF);
+}
+
+bool eeconfig_is_enabled(void)
+{
+    return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER);
+}
+
+uint8_t eeconfig_read_debug(void)      { return eeprom_read_byte(EECONFIG_DEBUG); }
+void eeconfig_write_debug(uint8_t val) { eeprom_write_byte(EECONFIG_DEBUG, val); }
+
+uint8_t eeconfig_read_default_layer(void)      { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
+void eeconfig_write_default_layer(uint8_t val) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER, val); }
+
+uint8_t eeconfig_read_keymap(void)      { return eeprom_read_byte(EECONFIG_KEYMAP); }
+void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val); }
+
+#ifdef BACKLIGHT_ENABLE
+uint8_t eeconfig_read_backlight(void)      { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
+void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); }
+#endif
diff --git a/common/chibios/printf.c b/common/chibios/printf.c
new file mode 100644 (file)
index 0000000..72e3d4f
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and:      http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.c
+
+Copyright (C) 2004  Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+// this adds cca 400 bytes
+#define PRINTF_LONG_SUPPORT
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+    {
+    int n=0;
+    unsigned int d=1;
+    while (num/d >= base)
+        d*=base;         
+    while (d!=0) {
+        int dgt = num / d;
+        num%=d;
+        d/=base;
+        if (n || dgt>0|| d==0) {
+            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+            ++n;
+            }
+        }
+    *bf=0;
+    }
+
+static void li2a (long num, char * bf)
+    {
+    if (num<0) {
+        num=-num;
+        *bf++ = '-';
+        }
+    uli2a(num,10,0,bf);
+    }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+    {
+    int n=0;
+    unsigned int d=1;
+    while (num/d >= base)
+        d*=base;        
+    while (d!=0) {
+        int dgt = num / d;
+        num%= d;
+        d/=base;
+        if (n || dgt>0 || d==0) {
+            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+            ++n;
+            }
+        }
+    *bf=0;
+    }
+
+static void i2a (int num, char * bf)
+    {
+    if (num<0) {
+        num=-num;
+        *bf++ = '-';
+        }
+    ui2a(num,10,0,bf);
+    }
+
+static int a2d(char ch)
+    {
+    if (ch>='0' && ch<='9') 
+        return ch-'0';
+    else if (ch>='a' && ch<='f')
+        return ch-'a'+10;
+    else if (ch>='A' && ch<='F')
+        return ch-'A'+10;
+    else return -1;
+    }
+
+static char a2i(char ch, char** src,int base,int* nump)
+    {
+    char* p= *src;
+    int num=0;
+    int digit;
+    while ((digit=a2d(ch))>=0) {
+        if (digit>base) break;
+        num=num*base+digit;
+        ch=*p++;
+        }
+    *src=p;
+    *nump=num;
+    return ch;
+    }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+    {
+    char fc=z? '0' : ' ';
+    char ch;
+    char* p=bf;
+    while (*p++ && n > 0)
+        n--;
+    while (n-- > 0) 
+        putf(putp,fc);
+    while ((ch= *bf++))
+        putf(putp,ch);
+    }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+    {
+    char bf[12];
+    
+    char ch;
+
+
+    while ((ch=*(fmt++))) {
+        if (ch!='%') 
+            putf(putp,ch);
+        else {
+            char lz=0;
+#ifdef  PRINTF_LONG_SUPPORT
+            char lng=0;
+#endif
+            int w=0;
+            ch=*(fmt++);
+            if (ch=='0') {
+                ch=*(fmt++);
+                lz=1;
+                }
+            if (ch>='0' && ch<='9') {
+                ch=a2i(ch,&fmt,10,&w);
+                }
+#ifdef  PRINTF_LONG_SUPPORT
+            if (ch=='l') {
+                ch=*(fmt++);
+                lng=1;
+            }
+#endif
+            switch (ch) {
+                case 0: 
+                    goto abort;
+                case 'u' : {
+#ifdef  PRINTF_LONG_SUPPORT
+                    if (lng)
+                        uli2a(va_arg(va, unsigned long int),10,0,bf);
+                    else
+#endif
+                    ui2a(va_arg(va, unsigned int),10,0,bf);
+                    putchw(putp,putf,w,lz,bf);
+                    break;
+                    }
+                case 'd' :  {
+#ifdef  PRINTF_LONG_SUPPORT
+                    if (lng)
+                        li2a(va_arg(va, unsigned long int),bf);
+                    else
+#endif
+                    i2a(va_arg(va, int),bf);
+                    putchw(putp,putf,w,lz,bf);
+                    break;
+                    }
+                case 'x': case 'X' : 
+#ifdef  PRINTF_LONG_SUPPORT
+                    if (lng)
+                        uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+                    else
+#endif
+                    ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+                    putchw(putp,putf,w,lz,bf);
+                    break;
+                case 'c' : 
+                    putf(putp,(char)(va_arg(va, int)));
+                    break;
+                case 's' : 
+                    putchw(putp,putf,w,0,va_arg(va, char*));
+                    break;
+                case '%' :
+                    putf(putp,ch);
+                default:
+                    break;
+                }
+            }
+        }
+    abort:;
+    }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+    {
+    stdout_putf=putf;
+    stdout_putp=putp;
+    }
+
+void tfp_printf(char *fmt, ...)
+    {
+    va_list va;
+    va_start(va,fmt);
+    tfp_format(stdout_putp,stdout_putf,fmt,va);
+    va_end(va);
+    }
+
+static void putcp(void* p,char c)
+    {
+    *(*((char**)p))++ = c;
+    }
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+    {
+    va_list va;
+    va_start(va,fmt);
+    tfp_format(&s,putcp,fmt,va);
+    putcp(&s,0);
+    va_end(va);
+    }
diff --git a/common/chibios/printf.h b/common/chibios/printf.h
new file mode 100644 (file)
index 0000000..678a100
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and:      http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.h
+
+Copyright (C) 2004  Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to 
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a 
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them 
+into your project. 
+
+Two printf variants are provided: printf and sprintf. 
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the 
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and 
+compiler options, but a rough guestimate (based on a H8S target) is about 
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. 
+Not too bad. Your milage may vary. By hacking the source code you can 
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of 
+functionality and flexibility versus  code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function, 
+something like :
+
+    void putc ( void* p, char c)
+        {
+        while (!SERIAL_PORT_EMPTY) ;
+        SERIAL_PORT_TX_REGISTER = c;
+        }
+
+Before you can call printf you need to initialize it to use your 
+character output function with something like:
+
+    init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', 
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be 
+passed to your 'putc' routine. This allows you to pass some storage space (or 
+anything realy) to the character output function, if necessary. 
+This is not often needed but it was implemented like that because it made 
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it 
+is safe to call it from interupts too, although this may result in mixed output. 
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to 
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file. 
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include <stdarg.h>
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf tfp_printf 
+#define sprintf tfp_sprintf 
+
+#endif
diff --git a/common/chibios/sleep_led.c b/common/chibios/sleep_led.c
new file mode 100644 (file)
index 0000000..50cf4eb
--- /dev/null
@@ -0,0 +1,164 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "led.h"
+#include "sleep_led.h"
+
+#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
+/* All right, we go the "software" way: LP timer, toggle LED in interrupt.
+ * Based on hasu's code for AVRs.
+ */
+
+/* Breathing Sleep LED brighness(PWM On period) table
+ * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
+ *
+ * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
+ * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
+ */
+static const uint8_t breathing_table[64] = {
+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
+};
+
+/* Low Power Timer interrupt handler */
+OSAL_IRQ_HANDLER(KINETIS_LPTMR0_IRQ_VECTOR) {
+    OSAL_IRQ_PROLOGUE();
+
+    /* Software PWM
+    * timer:1111 1111 1111 1111
+    *       \_____/\/ \_______/____  count(0-255)
+    *          \    \______________  duration of step(4)
+    *           \__________________  index of step table(0-63)
+    */
+
+    // this works for cca 65536 irqs/sec
+    static union {
+    uint16_t row;
+    struct {
+      uint8_t count:8;
+      uint8_t duration:2;
+      uint8_t index:6;
+    } pwm;
+    } timer = { .row = 0 };
+
+    timer.row++;
+
+    // LED on
+    if (timer.pwm.count == 0) {
+        led_set(1<<USB_LED_CAPS_LOCK);
+    }
+    // LED off
+    if (timer.pwm.count == breathing_table[timer.pwm.index]) {
+        led_set(0);
+    }
+
+    /* Reset the counter */
+    LPTMR0->CSR |= LPTMRx_CSR_TCF;
+
+    OSAL_IRQ_EPILOGUE();
+}
+
+/* LPTMR clock options */
+#define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
+#define LPTMR_CLOCK_LPO      1 /* 1kHz clock */
+#define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
+#define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
+
+/* Work around inconsistencies in Freescale naming */
+#if !defined(SIM_SCGC5_LPTMR)
+#define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
+#endif
+
+/* Initialise the timer */
+void sleep_led_init(void) {
+    /* Make sure the clock to the LPTMR is enabled */
+    SIM->SCGC5 |= SIM_SCGC5_LPTMR;
+    /* Reset LPTMR settings */
+    LPTMR0->CSR = 0;
+    /* Set the compare value */
+    LPTMR0->CMR = 0;  // trigger on counter value (i.e. every time)
+
+    /* Set up clock source and prescaler */
+    /* Software PWM
+    *  ______           ______           __
+    * |  ON  |___OFF___|  ON  |___OFF___|   ....
+    * |<-------------->|<-------------->|<- ....
+    *     PWM period       PWM period
+    *
+    * R                interrupts/period[resolution]
+    * F                periods/second[frequency]
+    * R * F            interrupts/second
+    */
+
+    /* === OPTION 1 === */
+    #if 0
+    //  1kHz LPO
+    //  No prescaler => 1024 irqs/sec
+    //  Note: this is too slow for a smooth breathe
+    LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
+    #endif /* OPTION 1 */
+
+    /* === OPTION 2 === */
+    #if 1
+    //  nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
+    MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
+    #if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
+    MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
+    #endif /* KL27 */
+    MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
+    //  to work in stop mode, also MCG_C1_IREFSTEN
+    //  Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
+    //  => approx F=61, R=256, duration = 4
+    LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(6);
+    #endif /* OPTION 2 */
+
+    /* === OPTION 3 === */
+    #if 0
+    //  OSC output (external crystal), usually 8MHz or 16MHz
+    OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
+    //  to work in stop mode, also OSC_CR_EREFSTEN
+    //  Divide by 2^N
+    LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
+    #endif /* OPTION 3 */
+    /* === END OPTIONS === */
+
+    /* Interrupt on TCF set (compare flag) */
+    nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
+    LPTMR0->CSR |= LPTMRx_CSR_TIE;
+}
+
+void sleep_led_enable(void) {
+    /* Enable the timer */
+    LPTMR0->CSR |= LPTMRx_CSR_TEN;
+}
+
+void sleep_led_disable(void) {
+    /* Disable the timer */
+    LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
+}
+
+void sleep_led_toggle(void) {
+    /* Toggle the timer */
+    LPTMR0->CSR ^= LPTMRx_CSR_TEN;
+}
+
+#else /* platform selection: not on familiar Kinetis chips */
+
+void sleep_led_init(void) {
+}
+void sleep_led_enable(void) {
+    led_set(1<<USB_LED_CAPS_LOCK);
+}
+void sleep_led_disable(void) {
+    led_set(0);
+}
+void sleep_led_toggle(void) {
+    // not implemented
+}
+
+#endif /* platform selection */
\ No newline at end of file
diff --git a/common/chibios/suspend.c b/common/chibios/suspend.c
new file mode 100644 (file)
index 0000000..6ca1603
--- /dev/null
@@ -0,0 +1,65 @@
+/* TODO */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "matrix.h"
+#include "action.h"
+#include "action_util.h"
+#include "mousekey.h"
+#include "host.h"
+#include "backlight.h"
+#include "suspend.h"
+
+void suspend_idle(uint8_t time) {
+       // TODO: this is not used anywhere - what units is 'time' in?
+       chThdSleepMilliseconds(time);
+}
+
+void suspend_power_down(void) {
+       // TODO: figure out what to power down and how
+       // shouldn't power down TPM/FTM if we want a breathing LED
+       // also shouldn't power down USB
+
+       // on AVR, this enables the watchdog for 15ms (max), and goes to
+       // SLEEP_MODE_PWR_DOWN
+
+       chThdSleepMilliseconds(17);
+}
+
+__attribute__ ((weak)) void matrix_power_up(void) {}
+__attribute__ ((weak)) void matrix_power_down(void) {}
+bool suspend_wakeup_condition(void)
+{
+    matrix_power_up();
+    matrix_scan();
+    matrix_power_down();
+    for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+        if (matrix_get_row(r)) return true;
+    }
+    return false;
+}
+
+// run immediately after wakeup
+void suspend_wakeup_init(void)
+{
+    // clear keyboard state
+    // need to do it manually, because we're running from ISR
+    //  and clear_keyboard() calls print
+    // so only clear the variables in memory
+    // the reports will be sent from main.c afterwards
+    // or if the PC asks for GET_REPORT
+    clear_mods();
+    clear_weak_mods();
+    clear_keys();
+#ifdef MOUSEKEY_ENABLE
+    mousekey_clear();
+#endif /* MOUSEKEY_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+    host_system_send(0);
+    host_consumer_send(0);
+#endif /* EXTRAKEY_ENABLE */
+#ifdef BACKLIGHT_ENABLE
+    backlight_init();
+#endif /* BACKLIGHT_ENABLE */
+}
diff --git a/common/chibios/timer.c b/common/chibios/timer.c
new file mode 100644 (file)
index 0000000..3de4cc3
--- /dev/null
@@ -0,0 +1,27 @@
+#include "ch.h"
+
+#include "timer.h"
+
+void timer_init(void) {}
+
+void timer_clear(void) {}
+
+uint16_t timer_read(void)
+{
+    return (uint16_t)ST2MS(chVTGetSystemTime());
+}
+
+uint32_t timer_read32(void)
+{
+    return ST2MS(chVTGetSystemTime());
+}
+
+uint16_t timer_elapsed(uint16_t last)
+{
+    return (uint16_t)(ST2MS(chVTTimeElapsedSinceX(MS2ST(last))));
+}
+
+uint32_t timer_elapsed32(uint32_t last)
+{
+    return ST2MS(chVTTimeElapsedSinceX(MS2ST(last)));
+}
index d59bb01bbcbd9151430fdf79444a84636a5cd9c9..6920970020cc3f0a8ec72e645940b39132074362 100644 (file)
@@ -16,7 +16,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include <stdint.h>
 #include <stdbool.h>
-#include <util/delay.h>
+#include "wait.h"
 #include "keycode.h"
 #include "host.h"
 #include "keymap.h"
@@ -97,12 +97,14 @@ bool command_proc(uint8_t code)
 bool command_extra(uint8_t code) __attribute__ ((weak));
 bool command_extra(uint8_t code)
 {
+    (void)code;
     return false;
 }
 
 bool command_console_extra(uint8_t code) __attribute__ ((weak));
 bool command_console_extra(uint8_t code)
 {
+    (void)code;
     return false;
 }
 
@@ -178,7 +180,9 @@ static void print_eeconfig(void)
 
 static bool command_common(uint8_t code)
 {
+#ifdef KEYBOARD_LOCK_ENABLE
     static host_driver_t *host_driver = 0;
+#endif
     switch (code) {
 #ifdef SLEEP_LED_ENABLE
         case KC_Z:
@@ -223,7 +227,7 @@ static bool command_common(uint8_t code)
         case KC_PAUSE:
             clear_keyboard();
             print("\n\nbootloader... ");
-            _delay_ms(1000);
+            wait_ms(1000);
             bootloader_jump(); // not return
             break;
         case KC_D:
@@ -283,6 +287,9 @@ static bool command_common(uint8_t code)
 #ifdef PROTOCOL_VUSB
             " VUSB"
 #endif
+#ifdef PROTOCOL_CHIBIOS
+            " CHIBIOS"
+#endif
 #ifdef BOOTMAGIC_ENABLE
             " BOOTMAGIC"
 #endif
@@ -307,8 +314,13 @@ static bool command_common(uint8_t code)
             " " STR(BOOTLOADER_SIZE) "\n");
 
             print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
+#if defined(__AVR__)
                   " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
                   " AVR_ARCH: avr" STR(__AVR_ARCH__) "\n");
+#elif defined(__arm__)
+            // TODO
+            );
+#endif
             break;
         case KC_S:
             print("\n\t- Status -\n");
@@ -318,7 +330,7 @@ static bool command_common(uint8_t code)
 #ifdef NKRO_ENABLE
             print_val_hex8(keyboard_nkro);
 #endif
-            print_val_hex32(timer_count);
+            print_val_hex32(timer_read32());
 
 #ifdef PROTOCOL_PJRC
             print_val_hex8(UDCON);
@@ -338,10 +350,11 @@ static bool command_common(uint8_t code)
         case KC_N:
             clear_keyboard(); //Prevents stuck keys.
             keyboard_nkro = !keyboard_nkro;
-            if (keyboard_nkro)
+            if (keyboard_nkro) {
                 print("NKRO: on\n");
-            else
+            } else {
                 print("NKRO: off\n");
+            }
             break;
 #endif
         case KC_ESC:
@@ -595,10 +608,11 @@ static bool mousekey_console(uint8_t code)
             print("?");
             return false;
     }
-    if (mousekey_param)
+    if (mousekey_param) {
         xprintf("M%d> ", mousekey_param);
-    else
+    } else {
         print("M>" );
+    }
     return true;
 }
 #endif
index 448195306f138cf939e4c8a440327885210eeffc..f34027120093530c1f9b274a5374e5ad68cec7e8 100644 (file)
@@ -85,15 +85,19 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define KC_LCAP KC_LOCKING_CAPS
 #define KC_LNUM KC_LOCKING_NUM
 #define KC_LSCR KC_LOCKING_SCROLL
-#define KC_ERAS KC_ALT_ERASE,
+#define KC_ERAS KC_ALT_ERASE
 #define KC_CLR  KC_CLEAR
 /* Japanese specific */
 #define KC_ZKHK KC_GRAVE
 #define KC_RO   KC_INT1
 #define KC_KANA KC_INT2
 #define KC_JYEN KC_INT3
+#define KC_JPY  KC_INT3
 #define KC_HENK KC_INT4
 #define KC_MHEN KC_INT5
+/* Korean specific */
+#define KC_HAEN KC_LANG1
+#define KC_HANJ KC_LANG2
 /* Keypad */
 #define KC_P1   KC_KP_1
 #define KC_P2   KC_KP_2
@@ -113,6 +117,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define KC_PPLS KC_KP_PLUS
 #define KC_PEQL KC_KP_EQUAL
 #define KC_PENT KC_KP_ENTER
+/* Unix function key */
+#define KC_EXEC KC_EXECUTE
+#define KC_SLCT KC_SELECT
+#define KC_AGIN KC_AGAIN
+#define KC_PSTE KC_PASTE
 /* Mousekey */
 #define KC_MS_U KC_MS_UP
 #define KC_MS_D KC_MS_DOWN
index d4892380854486bb25d1c8abd3c7a95d7786e381..134e01c20942451fe19edcd16c2db8ef32d651cd 100644 (file)
@@ -22,7 +22,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "action_macro.h"
 #include "wait.h"
 #include "debug.h"
+#include "bootloader.h"
 
+#ifdef BOOTMAGIC_ENABLE
+extern keymap_config_t keymap_config;
+#endif
 
 static action_t keycode_to_action(uint8_t keycode);
 
@@ -109,6 +113,9 @@ action_t action_for_key(uint8_t layer, keypos_t key)
 __attribute__ ((weak))
 const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 {
+    (void)record;
+    (void)id;
+    (void)opt;
     return MACRO_NONE;
 }
 
@@ -116,6 +123,9 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 __attribute__ ((weak))
 void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
 {
+    (void)record;
+    (void)id;
+    (void)opt;
 }
 
 
@@ -123,7 +133,7 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
 /* translates keycode to action */
 static action_t keycode_to_action(uint8_t keycode)
 {
-    action_t action;
+    action_t action = {};
     switch (keycode) {
         case KC_A ... KC_EXSEL:
         case KC_LCTRL ... KC_RGUI:
index e1a6f992e64cf47e0201790ddce1b8f069c6c06a..659ea357dbac73c3ffb688e6568169cf77b306d8 100644 (file)
@@ -38,7 +38,6 @@ typedef union {
         bool nkro:1;
     };
 } keymap_config_t;
-keymap_config_t keymap_config;
 #endif
 
 
index 93309ada4761f356ee82b7bba2b3871ad7a236dc..6ef9f91a2857fd441cebf07d49eae19d36145ba7 100644 (file)
@@ -18,7 +18,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #ifndef NODEBUG_H
 #define NODEBUG_H 1
 
+#if !defined(NO_DEBUG)
 #define NO_DEBUG
+#endif
 #include "debug.h"
 #undef NO_DEBUG
 
index ca94e1e5d6a7ffb9649648ef367b2ab2c5fa21c3..00489557f2245b6fcef72f7c8053188586c9d08d 100644 (file)
@@ -38,11 +38,15 @@ void print_set_sendchar(int8_t (*sendchar_func)(uint8_t))
     xdev_out(sendchar_func);
 }
 
-#elif defined(__arm__)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+
+// don't need anything extra
+
+#elif defined(__arm__) /* __AVR__ */
 
 // TODO
 //void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { }
 
-#endif
+#endif /* __AVR__ */
 
 #endif
index c0e9e14309d9ca03985097a2fbf95914ff0eceb6..5f491abac96f348aa6a2d0a2e8816509e67135e2 100644 (file)
@@ -47,7 +47,15 @@ extern "C"
 /* function pointer of sendchar to be used by print utility */
 void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
 
-#elif defined(__arm__)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+
+#include "chibios/printf.h"
+
+#define print(s)    printf(s)
+#define println(s)  printf(s "\r\n")
+#define xprintf  printf
+
+#elif defined(__arm__) /* __AVR__ */
 
 #include "mbed/xprintf.h"
 
@@ -91,9 +99,9 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
 
 #else   /* NO_PRINT */
 
-#define xprintf
-#define print
-#define println
+#define xprintf(s,...)
+#define print(s)
+#define println(s)
 #define print_set_sendchar(func)
 #define print_dec(data)
 #define print_decs(data)
@@ -119,6 +127,7 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
 #define print_val_bin_reverse8(v)
 #define print_val_bin_reverse16(v)
 #define print_val_bin_reverse32(v)
+#define init_printf(s,ss)
 
 #endif  /* NO_PRINT */
 
index 199b1bedfea9f7018903420ddca146da38482a60..5b276562505e55403ddd1687f685bdc5b2060b2b 100644 (file)
@@ -5,8 +5,8 @@
 #   include <avr/pgmspace.h>
 #elif defined(__arm__)
 #   define PROGMEM
-#   define pgm_read_byte(p)     *(p)
-#   define pgm_read_word(p)     *(p)
+#   define pgm_read_byte(p)     *((unsigned char*)p)
+#   define pgm_read_word(p)     *((uint16_t*)p)
 #endif
 
 #endif
index f6c0a315de9307de6c62ac6e2489e3ce2e62e750..0c799eca39af5581cb22912f24ea749524afc11a 100644 (file)
@@ -84,6 +84,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #   define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
 #   define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
 #   define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+#elif defined(PROTOCOL_CHIBIOS) && defined(NKRO_ENABLE)
+#   include "protocol/chibios/usb_main.h"
+#   define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
+#   define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
+#   define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
 
 #else
 #   define KEYBOARD_REPORT_SIZE 8
index 40d00b0c75184e88f1effc9a9153bde01979d9fc..82727be01254d93eb73f4eb9a05945df197583ff 100644 (file)
@@ -9,9 +9,13 @@ extern "C" {
 #   include <util/delay.h>
 #   define wait_ms(ms)  _delay_ms(ms)
 #   define wait_us(us)  _delay_us(us)
-#elif defined(__arm__)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+#   include "ch.h"
+#   define wait_ms(ms) chThdSleepMilliseconds(ms)
+#   define wait_us(us) chThdSleepMicroseconds(us)
+#elif defined(__arm__) /* __AVR__ */
 #   include "wait_api.h"
-#endif
+#endif /* __AVR__ */
 
 #ifdef __cplusplus
 }
index 20702e94c96304612fd72c5ba1ee66dc9e8e1d54..57a36ac42b56b203e913868ae1c78db4fa241b17 100644 (file)
@@ -6,11 +6,11 @@ Download and Install
 --------------------
 ### 1. Install Tools
 
-1. **Toolchain** On Windows install [MHV AVR Tools][mhv] for AVR GCC compiler and [Cygwin][cygwin](or [MinGW][mingw]) for shell terminal. On Mac you can use [CrossPack][crosspack]. On Linux you can install AVR GCC with your favorite package manager.
+1. **Toolchain** On Windows install [Atmel AVR Toolchain][atmelgcc] for AVR GCC compiler and [Cygwin][cygwin](or [MinGW][mingw]) for shell terminal. On Mac you can use [CrossPack][crosspack] or your favorite package manager. On Linux you can install AVR GCC with your favorite package manager.
 
-2. **Programmer** On Windows install [Atmel FLIP][flip]. On Mac and Linux install [dfu-programmer][dfu-prog].
+2. **Programmer** Install [dfu-programmer][dfu-prog]. GUI tool [Atmel FLIP][flip] also can be used on Windows.
 
-3. **Driver** On Windows you start DFU bootloader on the chip first time you will see 'Found New Hardware Wizard' to install driver. If you install device driver properly you can find chip name like 'ATmega32U4' under 'LibUSB-Win32 Devices' tree on 'Device Manager'. If not you shall need to update its driver on 'Device Manager'. You will find the driver in `FLIP` install directory like: C:\Program Files (x86)\Atmel\Flip 3.4.5\usb\. In case of `dfu-programmer` use its driver.
+3. **Driver** On Windows when you start DFU bootloader on the chip first time you will see **Found New Hardware Wizard** to install driver. If you install device driver properly you will find chip name like **ATmega32U4** under **LibUSB-Win32 Devices** tree on **Device Manager**. If not you shall need to update its driver on **Device Manager**. You will find the driver in `FLIP` install directory like: `C:\Program Files (x86)\Atmel\Flip 3.4.5\usb\`. In case of `dfu-programmer` install driver distributed with it.
 
 If you use PJRC Teensy you don't need step 2 and 3 above, just get [Teensy loader][teensy-loader].
 
@@ -20,7 +20,7 @@ You can find firmware source at github:
 
 - <https://github.com/tmk/tmk_keyboard>
 
-If you are familiar with `Git` tools you are recommended to use it but you can also download zip archive from:
+If you are familiar with [`git`][git] tools you are recommended to use it but you can also download zip archive from:
 
 - <https://github.com/tmk/tmk_keyboard/archive/master.zip>
 
@@ -28,7 +28,7 @@ If you are familiar with `Git` tools you are recommended to use it but you can a
 Build firmware
 --------------
 ### 1. Open terminal
-Open terminal window to get access to commands. Use Cygwin(or MingGW) `shell terminal` in Windows or `Terminal.app` on Mac OSX. In Windows press `Windows` key and `R` then enter `cmd` in 'Run command' dialog showing up.
+Open terminal window to get access to commands. Use Cygwin(or MingGW) shell terminal in Windows or `Terminal.app` on Mac OSX.
 
 ### 2. Change directory
 Move to project directory in the firmware source.
@@ -53,60 +53,65 @@ Now you have **hex** file to program on current directory. This **hex** is only
 How to program controller depends on controller chip and its board design. To program AVR USB chips you'll need to start it up in bootloader mode. Most of boards with the chip have a push button to let bootloader come up. Consult with your controller board manual.
 
 ### 2. Program with DFU bootloader
-Stock AVR USB chip including ATmega32U4 has DFU bootloader by factory default. `FLIP` is a DFU programmer on Windows offered by Atmel. Open source command line tool `dfu-programmer` also supports AVR chips, it runs on Linux, Mac OSX and even Windows.
+Stock AVR USB chips have DFU bootloader by factory default. `FLIP` is a DFU programmer on Windows offered by Atmel. `FLIP` has two version of tool, GUI app and command line program. If you want GUI see tutorial below. Open source alternative `dfu-programmer` also supports AVR chips, it is command line tool and runs on Linux, Mac OSX and even Windows.
 
-To program AVR chip with DFU bootloader use `FLIP` or `dfu-programmer`.
-If you have a proper program command in `Makefile` just type this.
 
-`FLIP` has two version of tool, GUI app and command line program. If you want GUI see tutorial below.
-To use command line tool run this command. Note that you need to set PATH variable properly.
+To program with command of `FLIP` run this. Note that you need to set PATH variable properly.
 
     $ make -f Makefile.<variant> flip
 
-Or to program with `dfu-programmer` run:
+With `dfu-programmer` run this.
 
     $ make -f Makefile.<variant> dfu
 
+Or you can execute the command directly as the following.
+
+    $ dfu-programmer <controller> erase --force
+    $ dfu-programmer <controller> flash <your_firmware.hex>
+    $ dfu-programmer <controller> reset
+
+`<controller>` part will be `atmega32u4` or `atmega32u2` in most cases. See manual of the command for the detail. On Linux and Mac OSX you will need proper permission to program a controller and you can use `sudo` command for this purpose probably. On Linux you also can configure `udev` rules to set permission.
+
+
 #### FLIP GUI tutorial
-1. On menu bar click Device -> Select, then. `ATmega32u4`.
-2. On menu bar click Settings -> Communication -> USB, then click 'Open' button on 'USB Port Connection' dialog.
-At this point you'll see grey-outed widgets on the app get colored and ready.
+1. On menu bar click **Device** -> **Select**, then choose your chip name. (In most cases **ATmega32U2** or **ATmega32U4**)
+2. On menu bar click **Settings** -> **Communication** -> **USB**, then click **Open** button on **USB Port Connection** dialog. At this point you'll have to plug into USB and start bootloader.
 
-3. On menu bar click File -> Load HEX File, then select your firmware hex file on File Selector dialog.
-4. On 'Operations Flow' panel click 'Run' button to load the firmware binary to the chip. Note that you should keep 'Erase', 'Blank Check', 'Program' and 'Verify' check boxes selected.
-5. Re-plug USB cord or click 'Start Application' button to restart your controller.
+3. On menu bar click **File** -> **Load HEX File**, then select your firmware hex file on File Selector dialog.
+4. On **Operations Flow** panel click **Run** button to load the firmware binary to the chip. Note that you should keep **Erase**, **Blank Check**, **Program** and **Verify** check boxes selected.
+5. Re-plug USB cord or click **Start Application** button to restart your controller.
 Done.
 
-See also these instructions if you need.
+See also these instructions if needed.
 
 - <http://code.google.com/p/micropendous/wiki/LoadingFirmwareWithFLIP>
 - <http://www.atmel.com/Images/doc7769.pdf>
 
 
-### 3. Program with Teensy Loader
-If you have PJRC Teensy see instruction of `Teensy Loader`.
+##### Troubleshoot
+* **FLIP: AtLibUsbDfu.dll not found**
+Remove current driver and re-install one FLIP provides from DeviceManager of WIndows. See <http://imgur.com/a/bnwzy>
 
-- <http://www.pjrc.com/teensy/loader.html>
 
-Or use this command if you have command line version of Teensy Loader installed.
+### 3. Program with Other programmer
+If you are using PJRC Teensy consult with instruction of [Teensy Loader][teensy-loader]. Or run this target with `make` after you install command line version of it.
 
     $ make -f Makefile.<variant> teensy
 
-
-### 4. Program with Other programmer
-You may want to use other programmer like `avrdude` with AVRISPmkII, Arduino or USBasp. In that case you can still use make target `program` for build with configuring `PROGRAM_CMD` in Makefile.
+You may want to use other programmer like [`avrdude`][avrdude]. In that case you can still use make target `program` for build with configuring `PROGRAM_CMD` in Makefile. See below.
 
     $ make -f Makefile.<variant> program
 
 
+[atmelgcc]:     http://www.atmel.com/tools/ATMELAVRTOOLCHAINFORWINDOWS.aspx
 [cygwin]:       https://www.cygwin.com/
 [mingw]:        http://www.mingw.org/
-[mhv]:          https://infernoembedded.com/products/avr-tools
-[winavr]:       http://winavr.sourceforge.net/
 [crosspack]:    http://www.obdev.at/products/crosspack/index.html
 [flip]:         http://www.atmel.com/tools/FLIP.aspx
 [dfu-prog]:     http://dfu-programmer.sourceforge.net/
 [teensy-loader]:http://www.pjrc.com/teensy/loader.html
+[avrdude]:      http://savannah.nongnu.org/projects/avrdude/
+[git]:          https://git-scm.com/
 
 
 
@@ -122,6 +127,7 @@ Set your MCU and its clock in Hz.
 
     # Boot Section Size in *bytes*
     #   Teensy halfKay   512
+    #   Teensy++ halfKay 2048
     #   Atmel DFU loader 4096
     #   LUFA bootloader  4096
     OPT_DEFS += -DBOOTLOADER_SIZE=4096
@@ -141,7 +147,7 @@ Optional. Note that ***comment out*** with `#` to disable them.
     #BACKLIGHT_ENABLE = yes     # Enable keyboard backlight functionality
 
 ### 3. Programmer
-Optional. Set proper command for your controller, bootloader and programmer. This command can be used with `make program`. Not needed if you use `FLIP`, `dfu-programmer` or `Teensy Loader`.
+Optional. Set proper command for your controller, bootloader and programmer. This command can be used with `make program`.
 
     # avrdude with AVRISPmkII
     PROGRAM_CMD = avrdude -p $(MCU) -c avrispmkII -P USB -U flash:w:$(TARGET).hex
index d4a129b208150062ff8a7bf7705396ce1d1f32a5..566936c69640f64809f9a22910bba427c634903b 100644 (file)
@@ -368,17 +368,37 @@ Default Layer also has bitwise operations, they are executed when key is release
     MACRO( I(255), T(H), T(E), T(L), T(L), W(255), T(O), END )
 
 #### 2.3.1 Macro Commands
+- **MACRO()**
+- **MACRO_NONE**
+
 - **I()**   change interval of stroke.
 - **D()**   press key
 - **U()**   release key
 - **T()**   type key(press and release)
 - **W()**   wait
+- **SM()**  store modifier state
+- **RM()**  restore modifier state
+- **CM()**  clear modifier state
 - **END**   end mark
 
 #### 2.3.2 Examples
+***TBD***
+
+    const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
+    {
+        switch (id) {
+            case HELLO:
+                return (record->event.pressed ?
+                        MACRO( I(0), T(H), T(E), T(L), T(L), W(255), T(O), END ) :
+                        MACRO_NONE );
+            case ALT_TAB:
+                return (record->event.pressed ?
+                        MACRO( D(LALT), D(TAB), END ) :
+                        MACRO( U(TAB), END ));
+        }
+        return MACRO_NONE;
+    }
 
-***TODO: sample implementation***
-See `keyboard/hhkb/keymap.c` for sample.
 
 
 
diff --git a/doc/other_projects.md b/doc/other_projects.md
deleted file mode 100644 (file)
index bf980b0..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-Other Keyboard Firmware Projects
-================================
-## PJRC USB Keyboard/Mouse Example[USB][PJRC][Teensy][AVR]
-- <http://www.pjrc.com/teensy/usb_keyboard.html>
-- <http://www.pjrc.com/teensy/usb_mouse.html>
-
-## kbupgrade[USB][V-USB][AVR]
-- <http://github.com/rhomann/kbupgrade>
-- <http://geekhack.org/showwiki.php?title=Island:8406>
-
-## c64key[USB][V-USB][AVR]
-- <http://symlink.dk/projects/c64key/>
-
-## rump[USB][V-USB][AVR]
-- <http://mg8.org/rump/>
-- <http://github.com/clee/rump>
-
-## dulcimer[USB][V-USB][AVR]
-- <http://www.schatenseite.de/dulcimer.html>
-
-## humblehacker-keyboard[USB][LUFA][AVR][Ergo]
-- <http://github.com/humblehacker>
-- <http://www.humblehacker.com/keyboard/>
-- <http://geekhack.org/showwiki.php?title=Island:6292>
-
-## ps2avr[PS/2][AVR]
-- <http://sourceforge.net/projects/ps2avr/>
-
-## ErgoDox[Ergo][Split][USB][AVR]
-- <http://geekhack.org/index.php?topic=22780.0>
-- <https://github.com/benblazak/ergodox-firmware>
-- <https://github.com/cub-uanic/tmk_keyboard>
-
-## Suka's keyboard collection[Ergo][Split][3DPrinting][USB][AVR]
-- <http://deskthority.net/workshop-f7/my-diy-keyboard-collection-or-how-i-became-a-kb-geek-t2534.html>
-- <https://github.com/frobiac/adnw>
-
-## bpiphany's AVR-Keyboard[PJRC][AVR][USB]
-- <https://github.com/BathroomEpiphanies/AVR-Keyboard>
-- <http://deskthority.net/wiki/HID_Liberation_Device_-_DIY_Instructions>
-- <http://deskthority.net/wiki/Phantom>
-
-## USB-USB keyboard remapper[converter][USB-USB][AVR][Arduino]
-- <http://forum.colemak.com/viewtopic.php?pid=10837>
-- <https://github.com/darkytoothpaste/keymapper>
-
-## USB-USB converter threads[converter][USB-USB]
-- <http://deskthority.net/workshop-f7/is-remapping-a-usb-keyboard-using-teensy-possible-t2841-30.html>
-- <http://geekhack.org/index.php?topic=19458.0>
-
-## kbdbabel.org[converter][vintage][protocol][8051]
-Great resource of vintage keyboard protocol information and code
-
-- <http://www.kbdbabel.org/>
-
-## Haata's kiibohd Controller[converter][vintage][protocol][AVR][PJRC][Cortex]
-A lots of vintage keyboard protocol supports
-
-- <http://gitorious.org/kiibohd-controller>
-
-## Kinesis ergonomic keyboard firmware replacement[V-USB][LUFA][Ergo]
-- <https://github.com/chrisandreae/kinesis-firmware>
diff --git a/protocol/chibios/README.md b/protocol/chibios/README.md
new file mode 100644 (file)
index 0000000..9796f8c
--- /dev/null
@@ -0,0 +1,50 @@
+## TMK running on top of ChibiOS
+
+### Notes
+
+- To use, unpack or symlink [ChibiOS] {currently 3.0.2} to `tmk_core/tool/chibios/chibios`. For Kinetis support, you'll need a fork which implements the USB driver, e.g. [this one](https://github.com/flabbergast/ChibiOS/tree/kinetis).
+- For gcc options, inspect `tmk_core/tool/chibios/chibios.mk`. For instance, I enabled `-Wno-missing-field-initializers`, because TMK common bits generated a lot of warnings on that.
+Also pay attention to `-O0` (enabled for debugging); for deployment use `-O2`.
+- USB string descriptors are messy. I did not find a way to cleanly generate the right structures from actual strings, so the definitions in individual keyboards' `config.h` are ugly as heck.
+- There are some random constants left so far, e.g. 5ms sleep between calling `keyboard_task`, or 1.5sec wait for USB init, in `main.c`. There should be no such in `usb_main.c` (the main USB stack). Everything is based on timers/interrupts/kernel scheduling (well except `keyboard_task`), so no periodically called things (again, except `keyboard_task`, which is just how TMK is designed).
+- It is easy to add some code for testing (e.g. blink LED, do stuff on button press, etc...) - just create another thread in `main.c`, it will run independently of the keyboard business.
+- Jumping to (the built-in) bootloaders on STM32 works, but it is not entirely pleasant, since it is very much MCU dependent. So, one needs to dig out the right address to jump to, and either pass it to the compiler in the `Makefile`, or better, define it in `<your_kb>/bootloader_defs.h`. Also, a patch to upstream ChibiOS is needed (supplied), because it `ResetHandler` needs adjusting.
+- Sleep LED works, but at the moment only on/off, i.e. no breathing.
+
+### Immediate todo
+
+- host-wakeup packet sending during suspend
+- power saving for suspend?
+- PWM for sleep led
+
+### Not tested, but possibly working
+
+- backlight
+
+### Missing / not working (TMK vs ChibiOS bits)
+
+- eeprom / bootmagic for STM32 (will be chip dependent; eeprom needs to be emulated in flash, which means less writes; wear-levelling?) There is a semi-official ST "driver" for eeprom, with wear-levelling, but I think it consumes a lot of RAM (like 2 pages, i.e. 1kB or so).
+
+### Tried with
+
+- ChibiOS 3.0.1, 3.0.2 and ST F072RB DISCOVERY board.
+- Need to test on other STM32 chips (F3, F4) to make it as much chip-independent as possible.
+- ChibiOS with Kinetis patches and Teensy LC and 3.0.
+
+## ChibiOS-supported MCUs (as of 3.0.2)
+
+- Pretty much all STM32 chips.
+- There is some support for K20x and KL2x Freescale chips (i.e. Teensy 3.x/LC, mchck, FRDM-KL2{5,6}Z, FRDM-K20D50M), but again, no official USB stack yet. However the `kinetis` branch of [my ChibiOS fork](https://github.com/flabbergast/ChibiOS). With this fork, TMK work normally on all the ARM Teensies.
+- There is also support for AVR8, but the USB stack is not implemented for them yet, and also the kernel itself takes about 1k of RAM. I think people managed to get ChibiOS running on atmega32[8p/u4] though.
+- I've seen community support for Nordic NRF51822 (the chip in Adafruit's Bluefruit bluetooth-low-energy boards), but not sure about the extent.
+
+## STM32-based keyboard design considerations
+
+- STM32F0x2 chips can do crystal-less USB, but they still need a 3.3V voltage regulator.
+- The BOOT0 pin should be tied to GND.
+- For a hardware way of accessing the in-built DFU bootloader, in addition to the reset button, put another button between the BOOT0 pin and 3V3.
+- For breathing the caps lock LED during the suspended state ("sleep LED"), it is desirable to have that LED on a hardware PWM pin (there's usually plenty of those, look for TIMERs in the datasheet). However this is not strictly necessary, because instead of direct output of a timer to a pin (better of course), it is easy to define timer callbacks in ChibiOS that turn on/off an arbitrary pin.
+
+
+
+[ChibiOS]: http://chibios.org
diff --git a/protocol/chibios/main.c b/protocol/chibios/main.c
new file mode 100644 (file)
index 0000000..b62cfa9
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
+ *
+ * Based on the following work:
+ *  - Guillaume Duc's raw hid example (MIT License)
+ *    https://github.com/guiduc/usb-hid-chibios-example
+ *  - PJRC Teensy examples (MIT License)
+ *    https://www.pjrc.com/teensy/usb_keyboard.html
+ *  - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
+ *    https://github.com/tmk/tmk_keyboard/
+ *  - ChibiOS demo code (Apache 2.0 License)
+ *    http://www.chibios.org
+ *
+ * Since some GPL'd code is used, this work is licensed under
+ * GPL v2 or later.
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "usb_main.h"
+
+/* TMK includes */
+#include "report.h"
+#include "host.h"
+#include "host_driver.h"
+#include "keyboard.h"
+#include "action.h"
+#include "action_util.h"
+#include "mousekey.h"
+#include "led.h"
+#include "sendchar.h"
+#include "debug.h"
+#ifdef SLEEP_LED_ENABLE
+#include "sleep_led.h"
+#endif
+#include "suspend.h"
+
+
+/* -------------------------
+ *   TMK host driver defs
+ * -------------------------
+ */
+
+/* declarations */
+uint8_t keyboard_leds(void);
+void send_keyboard(report_keyboard_t *report);
+void send_mouse(report_mouse_t *report);
+void send_system(uint16_t data);
+void send_consumer(uint16_t data);
+
+/* host struct */
+host_driver_t chibios_driver = {
+  keyboard_leds,
+  send_keyboard,
+  send_mouse,
+  send_system,
+  send_consumer
+};
+
+
+/* TESTING
+ * Amber LED blinker thread, times are in milliseconds.
+ */
+/* set this variable to non-zero anywhere to blink once */
+// uint8_t blinkLed = 0;
+// static THD_WORKING_AREA(waBlinkerThread, 128);
+// static THD_FUNCTION(blinkerThread, arg) {
+//   (void)arg;
+//   chRegSetThreadName("blinkOrange");
+//   while(true) {
+//     if(blinkLed) {
+//       blinkLed = 0;
+//       palSetPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
+//       chThdSleepMilliseconds(100);
+//       palClearPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
+//     }
+//     chThdSleepMilliseconds(100);
+//   }
+// }
+
+
+
+/* Main thread
+ */
+int main(void) {
+  /* ChibiOS/RT init */
+  halInit();
+  chSysInit();
+
+  // TESTING
+  // chThdCreateStatic(waBlinkerThread, sizeof(waBlinkerThread), NORMALPRIO, blinkerThread, NULL);
+
+  /* Init USB */
+  init_usb_driver(&USB_DRIVER);
+
+  /* init printf */
+  init_printf(NULL,sendchar_pf);
+
+  /* Wait until the USB is active */
+  while(USB_DRIVER.state != USB_ACTIVE)
+    chThdSleepMilliseconds(50);
+
+  print("USB configured.\n");
+
+  /* init TMK modules */
+  keyboard_init();
+  host_set_driver(&chibios_driver);
+
+#ifdef SLEEP_LED_ENABLE
+  sleep_led_init();
+#endif
+
+  print("Keyboard start.\n");
+
+  /* Main loop */
+  while(true) {
+
+    if(USB_DRIVER.state == USB_SUSPENDED) {
+      print("[s]");
+      while(USB_DRIVER.state == USB_SUSPENDED) {
+        /* Do this in the suspended state */
+        suspend_power_down(); // on AVR this deep sleeps for 15ms
+        /* Remote wakeup */
+        if((USB_DRIVER.status & 2) && suspend_wakeup_condition()) {
+          send_remote_wakeup(&USB_DRIVER);
+        }
+      }
+      /* Woken up */
+      // variables has been already cleared by the wakeup hook
+      send_keyboard_report();
+#ifdef MOUSEKEY_ENABLE
+      mousekey_send();
+#endif /* MOUSEKEY_ENABLE */
+    }
+
+    keyboard_task();
+  }
+}
diff --git a/protocol/chibios/usb_main.c b/protocol/chibios/usb_main.c
new file mode 100644 (file)
index 0000000..d248b44
--- /dev/null
@@ -0,0 +1,1372 @@
+/*
+ * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
+ *
+ * Based on the following work:
+ *  - Guillaume Duc's raw hid example (MIT License)
+ *    https://github.com/guiduc/usb-hid-chibios-example
+ *  - PJRC Teensy examples (MIT License)
+ *    https://www.pjrc.com/teensy/usb_keyboard.html
+ *  - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
+ *    https://github.com/tmk/tmk_keyboard/
+ *  - ChibiOS demo code (Apache 2.0 License)
+ *    http://www.chibios.org
+ *
+ * Since some GPL'd code is used, this work is licensed under
+ * GPL v2 or later.
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "usb_main.h"
+
+#include "host.h"
+#include "debug.h"
+#include "suspend.h"
+#ifdef SLEEP_LED_ENABLE
+#include "sleep_led.h"
+#include "led.h"
+#endif
+
+/* ---------------------------------------------------------
+ *       Global interface variables and declarations
+ * ---------------------------------------------------------
+ */
+
+uint8_t keyboard_idle = 0;
+uint8_t keyboard_protocol = 1;
+uint16_t keyboard_led_stats = 0;
+volatile uint16_t keyboard_idle_count = 0;
+static virtual_timer_t keyboard_idle_timer;
+static void keyboard_idle_timer_cb(void *arg);
+#ifdef NKRO_ENABLE
+extern bool keyboard_nkro;
+#endif /* NKRO_ENABLE */
+
+report_keyboard_t keyboard_report_sent = {{0}};
+#ifdef MOUSE_ENABLE
+report_mouse_t mouse_report_blank = {0};
+#endif /* MOUSE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+uint8_t extra_report_blank[3] = {0};
+#endif /* EXTRAKEY_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+/* The emission buffers queue */
+output_buffers_queue_t console_buf_queue;
+static uint8_t console_queue_buffer[BQ_BUFFER_SIZE(CONSOLE_QUEUE_CAPACITY, CONSOLE_EPSIZE)];
+
+static virtual_timer_t console_flush_timer;
+void console_queue_onotify(io_buffers_queue_t *bqp);
+static void console_flush_cb(void *arg);
+#endif /* CONSOLE_ENABLE */
+
+/* ---------------------------------------------------------
+ *            Descriptors and USB driver objects
+ * ---------------------------------------------------------
+ */
+
+/* HID specific constants */
+#define USB_DESCRIPTOR_HID 0x21
+#define USB_DESCRIPTOR_HID_REPORT 0x22
+#define HID_GET_REPORT 0x01
+#define HID_GET_IDLE 0x02
+#define HID_GET_PROTOCOL 0x03
+#define HID_SET_REPORT 0x09
+#define HID_SET_IDLE 0x0A
+#define HID_SET_PROTOCOL 0x0B
+
+/* USB Device Descriptor */
+static const uint8_t usb_device_descriptor_data[] = {
+  USB_DESC_DEVICE(0x0200,      // bcdUSB (1.1)
+                  0,           // bDeviceClass (defined in later in interface)
+                  0,           // bDeviceSubClass
+                  0,           // bDeviceProtocol
+                  64,          // bMaxPacketSize (64 bytes) (the driver didn't work with 32)
+                  VENDOR_ID,   // idVendor
+                  PRODUCT_ID,  // idProduct
+                  DEVICE_VER,      // bcdDevice
+                  1,           // iManufacturer
+                  2,           // iProduct
+                  3,           // iSerialNumber
+                  1)           // bNumConfigurations
+};
+
+/* Device Descriptor wrapper */
+static const USBDescriptor usb_device_descriptor = {
+  sizeof usb_device_descriptor_data,
+  usb_device_descriptor_data
+};
+
+/*
+ * HID Report Descriptor
+ *
+ * See "Device Class Definition for Human Interface Devices (HID)"
+ * (http://www.usb.org/developers/hidpage/HID1_11.pdf) for the
+ * detailed descrition of all the fields
+ */
+
+/* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */
+static const uint8_t keyboard_hid_report_desc_data[] = {
+  0x05, 0x01,                // Usage Page (Generic Desktop),
+  0x09, 0x06,                // Usage (Keyboard),
+  0xA1, 0x01,                // Collection (Application),
+  0x75, 0x01,                //   Report Size (1),
+  0x95, 0x08,                //   Report Count (8),
+  0x05, 0x07,                //   Usage Page (Key Codes),
+  0x19, 0xE0,                //   Usage Minimum (224),
+  0x29, 0xE7,                //   Usage Maximum (231),
+  0x15, 0x00,                //   Logical Minimum (0),
+  0x25, 0x01,                //   Logical Maximum (1),
+  0x81, 0x02,                //   Input (Data, Variable, Absolute), ;Modifier byte
+  0x95, 0x01,                //   Report Count (1),
+  0x75, 0x08,                //   Report Size (8),
+  0x81, 0x03,                //   Input (Constant),                 ;Reserved byte
+  0x95, 0x05,                //   Report Count (5),
+  0x75, 0x01,                //   Report Size (1),
+  0x05, 0x08,                //   Usage Page (LEDs),
+  0x19, 0x01,                //   Usage Minimum (1),
+  0x29, 0x05,                //   Usage Maximum (5),
+  0x91, 0x02,                //   Output (Data, Variable, Absolute), ;LED report
+  0x95, 0x01,                //   Report Count (1),
+  0x75, 0x03,                //   Report Size (3),
+  0x91, 0x03,                //   Output (Constant),                 ;LED report padding
+  0x95, KBD_REPORT_KEYS,          //   Report Count (),
+  0x75, 0x08,                //   Report Size (8),
+  0x15, 0x00,                //   Logical Minimum (0),
+  0x25, 0xFF,                //   Logical Maximum(255),
+  0x05, 0x07,                //   Usage Page (Key Codes),
+  0x19, 0x00,                //   Usage Minimum (0),
+  0x29, 0xFF,                //   Usage Maximum (255),
+  0x81, 0x00,                //   Input (Data, Array),
+  0xc0                       // End Collection
+};
+/* wrapper */
+static const USBDescriptor keyboard_hid_report_descriptor = {
+  sizeof keyboard_hid_report_desc_data,
+  keyboard_hid_report_desc_data
+};
+
+#ifdef NKRO_ENABLE
+static const uint8_t nkro_hid_report_desc_data[] = {
+  0x05, 0x01,                           // Usage Page (Generic Desktop),
+  0x09, 0x06,                           // Usage (Keyboard),
+  0xA1, 0x01,                           // Collection (Application),
+  // bitmap of modifiers
+  0x75, 0x01,                           //   Report Size (1),
+  0x95, 0x08,                           //   Report Count (8),
+  0x05, 0x07,                           //   Usage Page (Key Codes),
+  0x19, 0xE0,                           //   Usage Minimum (224),
+  0x29, 0xE7,                           //   Usage Maximum (231),
+  0x15, 0x00,                           //   Logical Minimum (0),
+  0x25, 0x01,                           //   Logical Maximum (1),
+  0x81, 0x02,                           //   Input (Data, Variable, Absolute), ;Modifier byte
+  // LED output report
+  0x95, 0x05,                           //   Report Count (5),
+  0x75, 0x01,                           //   Report Size (1),
+  0x05, 0x08,                           //   Usage Page (LEDs),
+  0x19, 0x01,                           //   Usage Minimum (1),
+  0x29, 0x05,                           //   Usage Maximum (5),
+  0x91, 0x02,                           //   Output (Data, Variable, Absolute),
+  0x95, 0x01,                           //   Report Count (1),
+  0x75, 0x03,                           //   Report Size (3),
+  0x91, 0x03,                           //   Output (Constant),
+  // bitmap of keys
+  0x95, NKRO_REPORT_KEYS * 8,           //   Report Count (),
+  0x75, 0x01,                           //   Report Size (1),
+  0x15, 0x00,                           //   Logical Minimum (0),
+  0x25, 0x01,                           //   Logical Maximum(1),
+  0x05, 0x07,                           //   Usage Page (Key Codes),
+  0x19, 0x00,                           //   Usage Minimum (0),
+  0x29, NKRO_REPORT_KEYS * 8 - 1,       //   Usage Maximum (),
+  0x81, 0x02,                           //   Input (Data, Variable, Absolute),
+  0xc0                                  // End Collection
+};
+/* wrapper */
+static const USBDescriptor nkro_hid_report_descriptor = {
+  sizeof nkro_hid_report_desc_data,
+  nkro_hid_report_desc_data
+};
+#endif /* NKRO_ENABLE */
+
+#ifdef MOUSE_ENABLE
+/* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
+ * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
+ * http://www.keil.com/forum/15671/
+ * http://www.microsoft.com/whdc/device/input/wheel.mspx */
+static const uint8_t mouse_hid_report_desc_data[] = {
+  /* mouse */
+  0x05, 0x01,                      // USAGE_PAGE (Generic Desktop)
+  0x09, 0x02,                      // USAGE (Mouse)
+  0xa1, 0x01,                      // COLLECTION (Application)
+  //0x85, REPORT_ID_MOUSE,         //   REPORT_ID (1)
+  0x09, 0x01,                      //   USAGE (Pointer)
+  0xa1, 0x00,                      //   COLLECTION (Physical)
+                                   // ----------------------------  Buttons
+  0x05, 0x09,                      //     USAGE_PAGE (Button)
+  0x19, 0x01,                      //     USAGE_MINIMUM (Button 1)
+  0x29, 0x05,                      //     USAGE_MAXIMUM (Button 5)
+  0x15, 0x00,                      //     LOGICAL_MINIMUM (0)
+  0x25, 0x01,                      //     LOGICAL_MAXIMUM (1)
+  0x75, 0x01,                      //     REPORT_SIZE (1)
+  0x95, 0x05,                      //     REPORT_COUNT (5)
+  0x81, 0x02,                      //     INPUT (Data,Var,Abs)
+  0x75, 0x03,                      //     REPORT_SIZE (3)
+  0x95, 0x01,                      //     REPORT_COUNT (1)
+  0x81, 0x03,                      //     INPUT (Cnst,Var,Abs)
+                                   // ----------------------------  X,Y position
+  0x05, 0x01,                      //     USAGE_PAGE (Generic Desktop)
+  0x09, 0x30,                      //     USAGE (X)
+  0x09, 0x31,                      //     USAGE (Y)
+  0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
+  0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
+  0x75, 0x08,                      //     REPORT_SIZE (8)
+  0x95, 0x02,                      //     REPORT_COUNT (2)
+  0x81, 0x06,                      //     INPUT (Data,Var,Rel)
+                                   // ----------------------------  Vertical wheel
+  0x09, 0x38,                      //     USAGE (Wheel)
+  0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
+  0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
+  0x35, 0x00,                      //     PHYSICAL_MINIMUM (0)        - reset physical
+  0x45, 0x00,                      //     PHYSICAL_MAXIMUM (0)
+  0x75, 0x08,                      //     REPORT_SIZE (8)
+  0x95, 0x01,                      //     REPORT_COUNT (1)
+  0x81, 0x06,                      //     INPUT (Data,Var,Rel)
+                                   // ----------------------------  Horizontal wheel
+  0x05, 0x0c,                      //     USAGE_PAGE (Consumer Devices)
+  0x0a, 0x38, 0x02,                //     USAGE (AC Pan)
+  0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
+  0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
+  0x75, 0x08,                      //     REPORT_SIZE (8)
+  0x95, 0x01,                      //     REPORT_COUNT (1)
+  0x81, 0x06,                      //     INPUT (Data,Var,Rel)
+  0xc0,                            //   END_COLLECTION
+  0xc0,                            // END_COLLECTION
+};
+/* wrapper */
+static const USBDescriptor mouse_hid_report_descriptor = {
+  sizeof mouse_hid_report_desc_data,
+  mouse_hid_report_desc_data
+};
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+static const uint8_t console_hid_report_desc_data[] = {
+  0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
+  0x09, 0x74,       // Usage 0x74
+  0xA1, 0x53,       // Collection 0x53
+  0x75, 0x08,       // report size = 8 bits
+  0x15, 0x00,       // logical minimum = 0
+  0x26, 0xFF, 0x00, // logical maximum = 255
+  0x95, CONSOLE_EPSIZE, // report count
+  0x09, 0x75,       // usage
+  0x81, 0x02,       // Input (array)
+  0xC0              // end collection
+};
+/* wrapper */
+static const USBDescriptor console_hid_report_descriptor = {
+  sizeof console_hid_report_desc_data,
+  console_hid_report_desc_data
+};
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+/* audio controls & system controls
+ * http://www.microsoft.com/whdc/archive/w2kbd.mspx */
+static const uint8_t extra_hid_report_desc_data[] = {
+  /* system control */
+  0x05, 0x01,                      // USAGE_PAGE (Generic Desktop)
+  0x09, 0x80,                      // USAGE (System Control)
+  0xa1, 0x01,                      // COLLECTION (Application)
+  0x85, REPORT_ID_SYSTEM,          //   REPORT_ID (2)
+  0x15, 0x01,                      //   LOGICAL_MINIMUM (0x1)
+  0x25, 0xb7,                      //   LOGICAL_MAXIMUM (0xb7)
+  0x19, 0x01,                      //   USAGE_MINIMUM (0x1)
+  0x29, 0xb7,                      //   USAGE_MAXIMUM (0xb7)
+  0x75, 0x10,                      //   REPORT_SIZE (16)
+  0x95, 0x01,                      //   REPORT_COUNT (1)
+  0x81, 0x00,                      //   INPUT (Data,Array,Abs)
+  0xc0,                            // END_COLLECTION
+  /* consumer */
+  0x05, 0x0c,                      // USAGE_PAGE (Consumer Devices)
+  0x09, 0x01,                      // USAGE (Consumer Control)
+  0xa1, 0x01,                      // COLLECTION (Application)
+  0x85, REPORT_ID_CONSUMER,        //   REPORT_ID (3)
+  0x15, 0x01,                      //   LOGICAL_MINIMUM (0x1)
+  0x26, 0x9c, 0x02,                //   LOGICAL_MAXIMUM (0x29c)
+  0x19, 0x01,                      //   USAGE_MINIMUM (0x1)
+  0x2a, 0x9c, 0x02,                //   USAGE_MAXIMUM (0x29c)
+  0x75, 0x10,                      //   REPORT_SIZE (16)
+  0x95, 0x01,                      //   REPORT_COUNT (1)
+  0x81, 0x00,                      //   INPUT (Data,Array,Abs)
+  0xc0,                            // END_COLLECTION
+};
+/* wrapper */
+static const USBDescriptor extra_hid_report_descriptor = {
+  sizeof extra_hid_report_desc_data,
+  extra_hid_report_desc_data
+};
+#endif /* EXTRAKEY_ENABLE */
+
+
+/*
+ * Configuration Descriptor tree for a HID device
+ *
+ * The HID Specifications version 1.11 require the following order:
+ * - Configuration Descriptor
+ * - Interface Descriptor
+ * - HID Descriptor
+ * - Endpoints Descriptors
+ */
+#define KBD_HID_DESC_NUM                0
+#define KBD_HID_DESC_OFFSET             (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9)
+
+#ifdef MOUSE_ENABLE
+#   define MOUSE_HID_DESC_NUM           (KBD_HID_DESC_NUM + 1)
+#   define MOUSE_HID_DESC_OFFSET        (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9)
+#else /* MOUSE_ENABLE */
+#   define MOUSE_HID_DESC_NUM           (KBD_HID_DESC_NUM + 0)
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+#define CONSOLE_HID_DESC_NUM            (MOUSE_HID_DESC_NUM + 1)
+#define CONSOLE_HID_DESC_OFFSET         (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9)
+#else /* CONSOLE_ENABLE */
+#   define CONSOLE_HID_DESC_NUM         (MOUSE_HID_DESC_NUM + 0)
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+#   define EXTRA_HID_DESC_NUM           (CONSOLE_HID_DESC_NUM + 1)
+#   define EXTRA_HID_DESC_OFFSET        (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
+#else /* EXTRAKEY_ENABLE */
+#   define EXTRA_HID_DESC_NUM           (CONSOLE_HID_DESC_NUM + 0)
+#endif /* EXTRAKEY_ENABLE */
+
+#ifdef NKRO_ENABLE
+#   define NKRO_HID_DESC_NUM            (EXTRA_HID_DESC_NUM + 1)
+#   define NKRO_HID_DESC_OFFSET         (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
+#else /* NKRO_ENABLE */
+#   define NKRO_HID_DESC_NUM            (EXTRA_HID_DESC_NUM + 0)
+#endif /* NKRO_ENABLE */
+
+#define NUM_INTERFACES                  (NKRO_HID_DESC_NUM + 1)
+#define CONFIG1_DESC_SIZE               (9 + (9 + 9 + 7) * NUM_INTERFACES)
+
+static const uint8_t hid_configuration_descriptor_data[] = {
+  /* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */
+  USB_DESC_CONFIGURATION(CONFIG1_DESC_SIZE, // wTotalLength
+                         NUM_INTERFACES,    // bNumInterfaces
+                         1,    // bConfigurationValue
+                         0,    // iConfiguration
+                         0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP)
+                         50),  // bMaxPower (50mA)
+
+  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+  USB_DESC_INTERFACE(KBD_INTERFACE,        // bInterfaceNumber
+                     0,        // bAlternateSetting
+                     1,        // bNumEndpoints
+                     0x03,     // bInterfaceClass: HID
+                     0x01,     // bInterfaceSubClass: Boot
+                     0x01,     // bInterfaceProtocol: Keyboard
+                     0),       // iInterface
+
+  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+  USB_DESC_BYTE(9),            // bLength
+  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
+  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
+  USB_DESC_BYTE(0),            // bCountryCode
+  USB_DESC_BYTE(1),            // bNumDescriptors
+  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
+  USB_DESC_WORD(sizeof(keyboard_hid_report_desc_data)), // wDescriptorLength
+
+  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+  USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80,  // bEndpointAddress
+                    0x03,      // bmAttributes (Interrupt)
+                    KBD_EPSIZE,// wMaxPacketSize
+                    10),       // bInterval
+
+  #ifdef MOUSE_ENABLE
+  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+  USB_DESC_INTERFACE(MOUSE_INTERFACE,   // bInterfaceNumber
+                     0,        // bAlternateSetting
+                     1,        // bNumEndpoints
+                     0x03,     // bInterfaceClass (0x03 = HID)
+                     // ThinkPad T23 BIOS doesn't work with boot mouse.
+                     0x00,     // bInterfaceSubClass (0x01 = Boot)
+                     0x00,     // bInterfaceProtocol (0x02 = Mouse)
+                     /*
+                        0x01,      // bInterfaceSubClass (0x01 = Boot)
+                        0x02,      // bInterfaceProtocol (0x02 = Mouse)
+                      */
+                     0),        // iInterface
+
+  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+  USB_DESC_BYTE(9),            // bLength
+  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
+  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
+  USB_DESC_BYTE(0),            // bCountryCode
+  USB_DESC_BYTE(1),            // bNumDescriptors
+  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
+  USB_DESC_WORD(sizeof(mouse_hid_report_desc_data)), // wDescriptorLength
+
+  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+  USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80,  // bEndpointAddress
+                    0x03,      // bmAttributes (Interrupt)
+                    MOUSE_EPSIZE,  // wMaxPacketSize
+                    1),        // bInterval
+  #endif /* MOUSE_ENABLE */
+
+  #ifdef CONSOLE_ENABLE
+  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+  USB_DESC_INTERFACE(CONSOLE_INTERFACE, // bInterfaceNumber
+                     0,        // bAlternateSetting
+                     1,        // bNumEndpoints
+                     0x03,     // bInterfaceClass: HID
+                     0x00,     // bInterfaceSubClass: None
+                     0x00,     // bInterfaceProtocol: None
+                     0),       // iInterface
+
+  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+  USB_DESC_BYTE(9),            // bLength
+  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
+  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
+  USB_DESC_BYTE(0),            // bCountryCode
+  USB_DESC_BYTE(1),            // bNumDescriptors
+  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
+  USB_DESC_WORD(sizeof(console_hid_report_desc_data)), // wDescriptorLength
+
+  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+  USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80,  // bEndpointAddress
+                    0x03,      // bmAttributes (Interrupt)
+                    CONSOLE_EPSIZE, // wMaxPacketSize
+                    1),        // bInterval
+  #endif /* CONSOLE_ENABLE */
+
+  #ifdef EXTRAKEY_ENABLE
+  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+  USB_DESC_INTERFACE(EXTRA_INTERFACE, // bInterfaceNumber
+                     0,        // bAlternateSetting
+                     1,        // bNumEndpoints
+                     0x03,     // bInterfaceClass: HID
+                     0x00,     // bInterfaceSubClass: None
+                     0x00,     // bInterfaceProtocol: None
+                     0),       // iInterface
+
+  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+  USB_DESC_BYTE(9),            // bLength
+  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
+  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
+  USB_DESC_BYTE(0),            // bCountryCode
+  USB_DESC_BYTE(1),            // bNumDescriptors
+  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
+  USB_DESC_WORD(sizeof(extra_hid_report_desc_data)), // wDescriptorLength
+
+  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+  USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80,  // bEndpointAddress
+                    0x03,      // bmAttributes (Interrupt)
+                    EXTRA_EPSIZE, // wMaxPacketSize
+                    10),       // bInterval
+  #endif /* EXTRAKEY_ENABLE */
+
+  #ifdef NKRO_ENABLE
+  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+  USB_DESC_INTERFACE(NKRO_INTERFACE, // bInterfaceNumber
+                     0,        // bAlternateSetting
+                     1,        // bNumEndpoints
+                     0x03,     // bInterfaceClass: HID
+                     0x00,     // bInterfaceSubClass: None
+                     0x00,     // bInterfaceProtocol: None
+                     0),       // iInterface
+
+  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+  USB_DESC_BYTE(9),            // bLength
+  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
+  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
+  USB_DESC_BYTE(0),            // bCountryCode
+  USB_DESC_BYTE(1),            // bNumDescriptors
+  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
+  USB_DESC_WORD(sizeof(nkro_hid_report_desc_data)), // wDescriptorLength
+
+  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+  USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80,  // bEndpointAddress
+                    0x03,      // bmAttributes (Interrupt)
+                    NKRO_EPSIZE, // wMaxPacketSize
+                    1),       // bInterval
+  #endif /* NKRO_ENABLE */
+};
+
+/* Configuration Descriptor wrapper */
+static const USBDescriptor hid_configuration_descriptor = {
+  sizeof hid_configuration_descriptor_data,
+  hid_configuration_descriptor_data
+};
+
+/* wrappers */
+#define HID_DESCRIPTOR_SIZE 9
+static const USBDescriptor keyboard_hid_descriptor = {
+  HID_DESCRIPTOR_SIZE,
+  &hid_configuration_descriptor_data[KBD_HID_DESC_OFFSET]
+};
+#ifdef MOUSE_ENABLE
+static const USBDescriptor mouse_hid_descriptor = {
+  HID_DESCRIPTOR_SIZE,
+  &hid_configuration_descriptor_data[MOUSE_HID_DESC_OFFSET]
+};
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+static const USBDescriptor console_hid_descriptor = {
+  HID_DESCRIPTOR_SIZE,
+  &hid_configuration_descriptor_data[CONSOLE_HID_DESC_OFFSET]
+};
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+static const USBDescriptor extra_hid_descriptor = {
+  HID_DESCRIPTOR_SIZE,
+  &hid_configuration_descriptor_data[EXTRA_HID_DESC_OFFSET]
+};
+#endif /* EXTRAKEY_ENABLE */
+#ifdef NKRO_ENABLE
+static const USBDescriptor nkro_hid_descriptor = {
+  HID_DESCRIPTOR_SIZE,
+  &hid_configuration_descriptor_data[NKRO_HID_DESC_OFFSET]
+};
+#endif /* NKRO_ENABLE */
+
+
+/* U.S. English language identifier */
+static const uint8_t usb_string_langid[] = {
+  USB_DESC_BYTE(4),                        // bLength
+  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
+  USB_DESC_WORD(0x0409)                    // wLANGID (U.S. English)
+};
+
+/* ugly ugly hack */
+#define PP_NARG(...) \
+         PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
+#define PP_NARG_(...) \
+         PP_ARG_N(__VA_ARGS__)
+#define PP_ARG_N( \
+          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
+         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
+         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
+         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
+         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
+         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
+         _61,_62,_63,N,...) N
+#define PP_RSEQ_N() \
+         63,62,61,60,                   \
+         59,58,57,56,55,54,53,52,51,50, \
+         49,48,47,46,45,44,43,42,41,40, \
+         39,38,37,36,35,34,33,32,31,30, \
+         29,28,27,26,25,24,23,22,21,20, \
+         19,18,17,16,15,14,13,12,11,10, \
+         9,8,7,6,5,4,3,2,1,0
+
+/* Vendor string = manufacturer */
+static const uint8_t usb_string_vendor[] = {
+  USB_DESC_BYTE(PP_NARG(USBSTR_MANUFACTURER)+2),                       // bLength
+  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
+  USBSTR_MANUFACTURER
+};
+
+/* Device Description string = product */
+static const uint8_t usb_string_description[] = {
+  USB_DESC_BYTE(PP_NARG(USBSTR_PRODUCT)+2),           // bLength
+  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
+  USBSTR_PRODUCT
+};
+
+/* Serial Number string (will be filled by the function init_usb_serial_string) */
+static uint8_t usb_string_serial[] = {
+  USB_DESC_BYTE(22),                       // bLength
+  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
+  '0', 0, 'x', 0, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'B', 0, 'E', 0, 'E', 0, 'F', 0
+};
+
+/* Strings wrappers array */
+static const USBDescriptor usb_strings[] = {
+  { sizeof usb_string_langid, usb_string_langid }
+  ,
+  { sizeof usb_string_vendor, usb_string_vendor }
+  ,
+  { sizeof usb_string_description, usb_string_description }
+  ,
+  { sizeof usb_string_serial, usb_string_serial }
+};
+
+/*
+ * Handles the GET_DESCRIPTOR callback
+ *
+ * Returns the proper descriptor
+ */
+static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) {
+  (void)usbp;
+  (void)lang;
+  switch(dtype) {
+  /* Generic descriptors */
+  case USB_DESCRIPTOR_DEVICE:   /* Device Descriptor */
+    return &usb_device_descriptor;
+
+  case USB_DESCRIPTOR_CONFIGURATION:    /* Configuration Descriptor */
+    return &hid_configuration_descriptor;
+
+  case USB_DESCRIPTOR_STRING:   /* Strings */
+    if(dindex < 4)
+      return &usb_strings[dindex];
+    break;
+
+  /* HID specific descriptors */
+  case USB_DESCRIPTOR_HID:      /* HID Descriptors */
+    switch(lang) {    /* yea, poor label, it's actually wIndex from the setup packet */
+    case KBD_INTERFACE:
+      return &keyboard_hid_descriptor;
+
+#ifdef MOUSE_ENABLE
+    case MOUSE_INTERFACE:
+      return &mouse_hid_descriptor;
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+    case CONSOLE_INTERFACE:
+      return &console_hid_descriptor;
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+    case EXTRA_INTERFACE:
+      return &extra_hid_descriptor;
+#endif /* EXTRAKEY_ENABLE */
+#ifdef NKRO_ENABLE
+    case NKRO_INTERFACE:
+      return &nkro_hid_descriptor;
+#endif /* NKRO_ENABLE */
+    }
+
+  case USB_DESCRIPTOR_HID_REPORT:       /* HID Report Descriptor */
+    switch(lang) {
+    case KBD_INTERFACE:
+      return &keyboard_hid_report_descriptor;
+
+#ifdef MOUSE_ENABLE
+    case MOUSE_INTERFACE:
+      return &mouse_hid_report_descriptor;
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+    case CONSOLE_INTERFACE:
+      return &console_hid_report_descriptor;
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+    case EXTRA_INTERFACE:
+      return &extra_hid_report_descriptor;
+#endif /* EXTRAKEY_ENABLE */
+#ifdef NKRO_ENABLE
+    case NKRO_INTERFACE:
+      return &nkro_hid_report_descriptor;
+#endif /* NKRO_ENABLE */
+    }
+  }
+  return NULL;
+}
+
+/* keyboard endpoint state structure */
+static USBInEndpointState kbd_ep_state;
+/* keyboard endpoint initialization structure (IN) */
+static const USBEndpointConfig kbd_ep_config = {
+  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
+  NULL,                         /* SETUP packet notification callback */
+  kbd_in_cb,                    /* IN notification callback */
+  NULL,                         /* OUT notification callback */
+  KBD_EPSIZE,                   /* IN maximum packet size */
+  0,                            /* OUT maximum packet size */
+  &kbd_ep_state,                /* IN Endpoint state */
+  NULL,                         /* OUT endpoint state */
+  2,                            /* IN multiplier */
+  NULL                          /* SETUP buffer (not a SETUP endpoint) */
+};
+
+#ifdef MOUSE_ENABLE
+/* mouse endpoint state structure */
+static USBInEndpointState mouse_ep_state;
+
+/* mouse endpoint initialization structure (IN) */
+static const USBEndpointConfig mouse_ep_config = {
+  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
+  NULL,                         /* SETUP packet notification callback */
+  mouse_in_cb,                  /* IN notification callback */
+  NULL,                         /* OUT notification callback */
+  MOUSE_EPSIZE,                 /* IN maximum packet size */
+  0,                            /* OUT maximum packet size */
+  &mouse_ep_state,              /* IN Endpoint state */
+  NULL,                         /* OUT endpoint state */
+  2,                            /* IN multiplier */
+  NULL                          /* SETUP buffer (not a SETUP endpoint) */
+};
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+/* console endpoint state structure */
+static USBInEndpointState console_ep_state;
+
+/* console endpoint initialization structure (IN) */
+static const USBEndpointConfig console_ep_config = {
+  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
+  NULL,                         /* SETUP packet notification callback */
+  console_in_cb,                /* IN notification callback */
+  NULL,                         /* OUT notification callback */
+  CONSOLE_EPSIZE,               /* IN maximum packet size */
+  0,                            /* OUT maximum packet size */
+  &console_ep_state,            /* IN Endpoint state */
+  NULL,                         /* OUT endpoint state */
+  2,                            /* IN multiplier */
+  NULL                          /* SETUP buffer (not a SETUP endpoint) */
+};
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+/* extrakey endpoint state structure */
+static USBInEndpointState extra_ep_state;
+
+/* extrakey endpoint initialization structure (IN) */
+static const USBEndpointConfig extra_ep_config = {
+  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
+  NULL,                         /* SETUP packet notification callback */
+  extra_in_cb,                  /* IN notification callback */
+  NULL,                         /* OUT notification callback */
+  EXTRA_EPSIZE,                 /* IN maximum packet size */
+  0,                            /* OUT maximum packet size */
+  &extra_ep_state,              /* IN Endpoint state */
+  NULL,                         /* OUT endpoint state */
+  2,                            /* IN multiplier */
+  NULL                          /* SETUP buffer (not a SETUP endpoint) */
+};
+#endif /* EXTRAKEY_ENABLE */
+
+#ifdef NKRO_ENABLE
+/* nkro endpoint state structure */
+static USBInEndpointState nkro_ep_state;
+
+/* nkro endpoint initialization structure (IN) */
+static const USBEndpointConfig nkro_ep_config = {
+  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
+  NULL,                         /* SETUP packet notification callback */
+  nkro_in_cb,                   /* IN notification callback */
+  NULL,                         /* OUT notification callback */
+  NKRO_EPSIZE,                  /* IN maximum packet size */
+  0,                            /* OUT maximum packet size */
+  &nkro_ep_state,               /* IN Endpoint state */
+  NULL,                         /* OUT endpoint state */
+  2,                            /* IN multiplier */
+  NULL                          /* SETUP buffer (not a SETUP endpoint) */
+};
+#endif /* NKRO_ENABLE */
+
+/* ---------------------------------------------------------
+ *                  USB driver functions
+ * ---------------------------------------------------------
+ */
+
+/* Handles the USB driver global events
+ * TODO: maybe disable some things when connection is lost? */
+static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
+  switch(event) {
+  case USB_EVENT_RESET:
+    //TODO: from ISR! print("[R]");
+    return;
+
+  case USB_EVENT_ADDRESS:
+    return;
+
+  case USB_EVENT_CONFIGURED:
+    osalSysLockFromISR();
+    /* Enable the endpoints specified into the configuration. */
+    usbInitEndpointI(usbp, KBD_ENDPOINT, &kbd_ep_config);
+#ifdef MOUSE_ENABLE
+    usbInitEndpointI(usbp, MOUSE_ENDPOINT, &mouse_ep_config);
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+    usbInitEndpointI(usbp, CONSOLE_ENDPOINT, &console_ep_config);
+    /* don't need to start the flush timer, it starts from console_in_cb automatically */
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+    usbInitEndpointI(usbp, EXTRA_ENDPOINT, &extra_ep_config);
+#endif /* EXTRAKEY_ENABLE */
+#ifdef NKRO_ENABLE
+    usbInitEndpointI(usbp, NKRO_ENDPOINT, &nkro_ep_config);
+#endif /* NKRO_ENABLE */
+    osalSysUnlockFromISR();
+    return;
+
+  case USB_EVENT_SUSPEND:
+    //TODO: from ISR! print("[S]");
+#ifdef SLEEP_LED_ENABLE
+    sleep_led_enable();
+#endif /* SLEEP_LED_ENABLE */
+    return;
+
+  case USB_EVENT_WAKEUP:
+    //TODO: from ISR! print("[W]");
+    suspend_wakeup_init();
+#ifdef SLEEP_LED_ENABLE
+    sleep_led_disable();
+    // NOTE: converters may not accept this
+    led_set(host_keyboard_leds());
+#endif /* SLEEP_LED_ENABLE */
+    return;
+
+  case USB_EVENT_STALLED:
+    return;
+  }
+}
+
+/* Function used locally in os/hal/src/usb.c for getting descriptors
+ * need it here for HID descriptor */
+static uint16_t get_hword(uint8_t *p) {
+  uint16_t hw;
+
+  hw = (uint16_t)*p++;
+  hw |= (uint16_t)*p << 8U;
+  return hw;
+}
+
+/*
+ * Appendix G: HID Request Support Requirements
+ *
+ * The following table enumerates the requests that need to be supported by various types of HID class devices.
+ * Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
+ * ------------------------------------------------------------------------------------------
+ * Boot Mouse      Required    Optional    Optional    Optional    Required    Required
+ * Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
+ * Boot Keyboard   Required    Optional    Required    Required    Required    Required
+ * Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
+ * Other Device    Required    Optional    Optional    Optional    Optional    Optional
+ */
+
+/* Callback for SETUP request on the endpoint 0 (control) */
+static bool usb_request_hook_cb(USBDriver *usbp) {
+  const USBDescriptor *dp;
+
+  /* usbp->setup fields:
+   *  0:   bmRequestType (bitmask)
+   *  1:   bRequest
+   *  2,3: (LSB,MSB) wValue
+   *  4,5: (LSB,MSB) wIndex
+   *  6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */
+
+  /* Handle HID class specific requests */
+  if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
+     ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
+    switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) {
+    case USB_RTYPE_DIR_DEV2HOST:
+      switch(usbp->setup[1]) {   /* bRequest */
+      case HID_GET_REPORT:
+        switch(usbp->setup[4]) {     /* LSB(wIndex) (check MSB==0?) */
+        case KBD_INTERFACE:
+#ifdef NKRO_ENABLE
+        case NKRO_INTERFACE:
+#endif /* NKRO_ENABLE */
+          usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL);
+          return TRUE;
+          break;
+
+#ifdef MOUSE_ENABLE
+        case MOUSE_INTERFACE:
+          usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL);
+          return TRUE;
+          break;
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+        case CONSOLE_INTERFACE:
+          usbSetupTransfer(usbp, console_queue_buffer, CONSOLE_EPSIZE, NULL);
+          return TRUE;
+          break;
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+        case EXTRA_INTERFACE:
+          if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
+            switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */
+              case REPORT_ID_SYSTEM:
+                extra_report_blank[0] = REPORT_ID_SYSTEM;
+                usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
+                return TRUE;
+                break;
+              case REPORT_ID_CONSUMER:
+                extra_report_blank[0] = REPORT_ID_CONSUMER;
+                usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
+                return TRUE;
+                break;
+              default:
+                return FALSE;
+            }
+          } else {
+            return FALSE;
+          }
+          break;
+#endif /* EXTRAKEY_ENABLE */
+
+        default:
+          usbSetupTransfer(usbp, NULL, 0, NULL);
+          return TRUE;
+          break;
+        }
+        break;
+
+      case HID_GET_PROTOCOL:
+        if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
+          usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL);
+          return TRUE;
+        }
+        break;
+
+      case HID_GET_IDLE:
+        usbSetupTransfer(usbp, &keyboard_idle, 1, NULL);
+        return TRUE;
+        break;
+      }
+      break;
+
+    case USB_RTYPE_DIR_HOST2DEV:
+      switch(usbp->setup[1]) {   /* bRequest */
+      case HID_SET_REPORT:
+        switch(usbp->setup[4]) {       /* LSB(wIndex) (check MSB==0 and wLength==1?) */
+        case KBD_INTERFACE:
+#ifdef NKRO_ENABLE
+        case NKRO_INTERFACE:
+#endif  /* NKRO_ENABLE */
+        /* keyboard_led_stats = <read byte from next OUT report>
+         * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */
+          usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
+          return TRUE;
+          break;
+        }
+        break;
+
+      case HID_SET_PROTOCOL:
+        if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
+          keyboard_protocol = ((usbp->setup[2]) != 0x00);   /* LSB(wValue) */
+#ifdef NKRO_ENABLE
+          keyboard_nkro = !!keyboard_protocol;
+          if(!keyboard_nkro && keyboard_idle) {
+#else /* NKRO_ENABLE */
+          if(keyboard_idle) {
+#endif /* NKRO_ENABLE */
+          /* arm the idle timer if boot protocol & idle */
+            osalSysLockFromISR();
+            chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
+            osalSysUnlockFromISR();
+          }
+        }
+        usbSetupTransfer(usbp, NULL, 0, NULL);
+        return TRUE;
+        break;
+
+      case HID_SET_IDLE:
+        keyboard_idle = usbp->setup[3];     /* MSB(wValue) */
+        /* arm the timer */
+#ifdef NKRO_ENABLE
+        if(!keyboard_nkro && keyboard_idle) {
+#else /* NKRO_ENABLE */
+        if(keyboard_idle) {
+#endif /* NKRO_ENABLE */
+          osalSysLockFromISR();
+          chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
+          osalSysUnlockFromISR();
+        }
+        usbSetupTransfer(usbp, NULL, 0, NULL);
+        return TRUE;
+        break;
+      }
+      break;
+    }
+  }
+
+  /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */
+  if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) {
+    dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4]));
+    if(dp == NULL)
+      return FALSE;
+    usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* Start-of-frame callback */
+static void usb_sof_cb(USBDriver *usbp) {
+  kbd_sof_cb(usbp);
+}
+
+
+/* USB driver configuration */
+static const USBConfig usbcfg = {
+  usb_event_cb,                 /* USB events callback */
+  usb_get_descriptor_cb,        /* Device GET_DESCRIPTOR request callback */
+  usb_request_hook_cb,          /* Requests hook callback */
+  usb_sof_cb                    /* Start Of Frame callback */
+};
+
+/*
+ * Initialize the USB driver
+ */
+void init_usb_driver(USBDriver *usbp) {
+  /*
+   * Activates the USB driver and then the USB bus pull-up on D+.
+   * Note, a delay is inserted in order to not have to disconnect the cable
+   * after a reset.
+   */
+  usbDisconnectBus(usbp);
+  chThdSleepMilliseconds(1500);
+  usbStart(usbp, &usbcfg);
+  usbConnectBus(usbp);
+
+  chVTObjectInit(&keyboard_idle_timer);
+#ifdef CONSOLE_ENABLE
+  obqObjectInit(&console_buf_queue, console_queue_buffer, CONSOLE_EPSIZE, CONSOLE_QUEUE_CAPACITY, console_queue_onotify, (void*)usbp);
+  chVTObjectInit(&console_flush_timer);
+#endif
+}
+
+/*
+ * Send remote wakeup packet
+ * Note: should not be called from ISR
+ */
+void send_remote_wakeup(USBDriver *usbp) {
+  (void)usbp;
+#if defined(K20x) || defined(KL2x)
+#if KINETIS_USB_USE_USB0
+  USB0->CTL |= USBx_CTL_RESUME;
+  chThdSleepMilliseconds(15);
+  USB0->CTL &= ~USBx_CTL_RESUME;
+#endif /* KINETIS_USB_USE_USB0 */
+#elif defined(STM32F0XX) || defined(STM32F1XX) /* K20x || KL2x */
+  STM32_USB->CNTR |= CNTR_RESUME;
+  chThdSleepMilliseconds(15);
+  STM32_USB->CNTR &= ~CNTR_RESUME;
+#else /* STM32F0XX || STM32F1XX */
+#warning Sending remote wakeup packet not implemented for your platform.
+#endif /* K20x || KL2x */
+}
+
+/* ---------------------------------------------------------
+ *                  Keyboard functions
+ * ---------------------------------------------------------
+ */
+
+/* keyboard IN callback hander (a kbd report has made it IN) */
+void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
+  /* STUB */
+  (void)usbp;
+  (void)ep;
+}
+
+#ifdef NKRO_ENABLE
+/* nkro IN callback hander (a nkro report has made it IN) */
+void nkro_in_cb(USBDriver *usbp, usbep_t ep) {
+  /* STUB */
+  (void)usbp;
+  (void)ep;
+}
+#endif /* NKRO_ENABLE */
+
+/* start-of-frame handler
+ * TODO: i guess it would be better to re-implement using timers,
+ *  so that this is not going to have to be checked every 1ms */
+void kbd_sof_cb(USBDriver *usbp) {
+  (void)usbp;
+}
+
+/* Idle requests timer code
+ * callback (called from ISR, unlocked state) */
+static void keyboard_idle_timer_cb(void *arg) {
+  USBDriver *usbp = (USBDriver *)arg;
+
+  osalSysLockFromISR();
+
+  /* check that the states of things are as they're supposed to */
+  if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
+    /* do not rearm the timer, should be enabled on IDLE request */
+    osalSysUnlockFromISR();
+    return;
+  }
+
+#ifdef NKRO_ENABLE
+  if(!keyboard_nkro && keyboard_idle) {
+#else /* NKRO_ENABLE */
+  if(keyboard_idle) {
+#endif /* NKRO_ENABLE */
+    /* TODO: are we sure we want the KBD_ENDPOINT? */
+    if(!usbGetTransmitStatusI(usbp, KBD_ENDPOINT)) {
+      usbStartTransmitI(usbp, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, KBD_EPSIZE);
+    }
+    /* rearm the timer */
+    chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
+  }
+
+  /* do not rearm the timer if the condition above fails
+   * it should be enabled again on either IDLE or SET_PROTOCOL requests */
+  osalSysUnlockFromISR();
+}
+
+/* LED status */
+uint8_t keyboard_leds(void) {
+  return (uint8_t)(keyboard_led_stats & 0xFF);
+}
+
+/* prepare and start sending a report IN
+ * not callable from ISR or locked state */
+void send_keyboard(report_keyboard_t *report) {
+  osalSysLock();
+  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
+    osalSysUnlock();
+    return;
+  }
+  osalSysUnlock();
+
+#ifdef NKRO_ENABLE
+  if(keyboard_nkro) {  /* NKRO protocol */
+    /* need to wait until the previous packet has made it through */
+    /* can rewrite this using the synchronous API, then would wait
+     * until *after* the packet has been transmitted. I think
+     * this is more efficient */
+    /* busy wait, should be short and not very common */
+    osalSysLock();
+    if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_ENDPOINT)) {
+      /* Need to either suspend, or loop and call unlock/lock during
+       * every iteration - otherwise the system will remain locked,
+       * no interrupts served, so USB not going through as well.
+       * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
+      osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_ENDPOINT]->in_state->thread);
+    }
+    usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
+    osalSysUnlock();
+  } else
+#endif /* NKRO_ENABLE */
+  { /* boot protocol */
+    /* need to wait until the previous packet has made it through */
+    /* busy wait, should be short and not very common */
+    osalSysLock();
+    if(usbGetTransmitStatusI(&USB_DRIVER, KBD_ENDPOINT)) {
+      /* Need to either suspend, or loop and call unlock/lock during
+       * every iteration - otherwise the system will remain locked,
+       * no interrupts served, so USB not going through as well.
+       * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
+      osalThreadSuspendS(&(&USB_DRIVER)->epc[KBD_ENDPOINT]->in_state->thread);
+    }
+    usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE);
+    osalSysUnlock();
+  }
+  keyboard_report_sent = *report;
+}
+
+/* ---------------------------------------------------------
+ *                     Mouse functions
+ * ---------------------------------------------------------
+ */
+
+#ifdef MOUSE_ENABLE
+
+/* mouse IN callback hander (a mouse report has made it IN) */
+void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
+  (void)usbp;
+  (void)ep;
+}
+
+void send_mouse(report_mouse_t *report) {
+  osalSysLock();
+  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
+    osalSysUnlock();
+    return;
+  }
+  osalSysUnlock();
+
+  /* TODO: LUFA manually waits for the endpoint to become ready
+   * for about 10ms for mouse, kbd, system; 1ms for nkro
+   * is this really needed?
+   */
+
+  osalSysLock();
+  usbStartTransmitI(&USB_DRIVER, MOUSE_ENDPOINT, (uint8_t *)report, sizeof(report_mouse_t));
+  osalSysUnlock();
+}
+
+#else /* MOUSE_ENABLE */
+void send_mouse(report_mouse_t *report) {
+  (void)report;
+}
+#endif /* MOUSE_ENABLE */
+
+/* ---------------------------------------------------------
+ *                   Extrakey functions
+ * ---------------------------------------------------------
+ */
+
+#ifdef EXTRAKEY_ENABLE
+
+/* extrakey IN callback hander */
+void extra_in_cb(USBDriver *usbp, usbep_t ep) {
+  /* STUB */
+  (void)usbp;
+  (void)ep;
+}
+
+static void send_extra_report(uint8_t report_id, uint16_t data) {
+  osalSysLock();
+  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
+    osalSysUnlock();
+    return;
+  }
+
+  report_extra_t report = {
+    .report_id = report_id,
+    .usage = data
+  };
+
+  usbStartTransmitI(&USB_DRIVER, EXTRA_ENDPOINT, (uint8_t *)&report, sizeof(report_extra_t));
+  osalSysUnlock();
+}
+
+void send_system(uint16_t data) {
+  send_extra_report(REPORT_ID_SYSTEM, data);
+}
+
+void send_consumer(uint16_t data) {
+  send_extra_report(REPORT_ID_CONSUMER, data);
+}
+
+#else /* EXTRAKEY_ENABLE */
+void send_system(uint16_t data) {
+  (void)data;
+}
+void send_consumer(uint16_t data) {
+  (void)data;
+}
+#endif /* EXTRAKEY_ENABLE */
+
+/* ---------------------------------------------------------
+ *                   Console functions
+ * ---------------------------------------------------------
+ */
+
+#ifdef CONSOLE_ENABLE
+
+/* console IN callback hander */
+void console_in_cb(USBDriver *usbp, usbep_t ep) {
+  (void)ep; /* should have ep == CONSOLE_ENDPOINT, so use that to save time/space */
+  uint8_t *buf;
+  size_t n;
+
+  osalSysLockFromISR();
+
+  /* rearm the timer */
+  chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
+
+  /* Freeing the buffer just transmitted, if it was not a zero size packet.*/
+  if (usbp->epc[CONSOLE_ENDPOINT]->in_state->txsize > 0U) {
+    obqReleaseEmptyBufferI(&console_buf_queue);
+  }
+
+  /* Checking if there is a buffer ready for transmission.*/
+  buf = obqGetFullBufferI(&console_buf_queue, &n);
+
+  if (buf != NULL) {
+    /* The endpoint cannot be busy, we are in the context of the callback,
+       so it is safe to transmit without a check.*/
+    /* Should have n == CONSOLE_EPSIZE; check it? */
+    usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
+  } else {
+    /* Nothing to transmit.*/
+  }
+
+  osalSysUnlockFromISR();
+}
+
+/* Callback when data is inserted into the output queue
+ * Called from a locked state */
+void console_queue_onotify(io_buffers_queue_t *bqp) {
+  size_t n;
+  USBDriver *usbp = bqGetLinkX(bqp);
+
+  if(usbGetDriverStateI(usbp) != USB_ACTIVE)
+    return;
+
+  /* Checking if there is already a transaction ongoing on the endpoint.*/
+  if (!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) {
+    /* Trying to get a full buffer.*/
+    uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n);
+    if (buf != NULL) {
+      /* Buffer found, starting a new transaction.*/
+      /* Should have n == CONSOLE_EPSIZE; check this? */
+      usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
+    }
+  }
+}
+
+/* Flush timer code
+ * callback (called from ISR, unlocked state) */
+static void console_flush_cb(void *arg) {
+  USBDriver *usbp = (USBDriver *)arg;
+  osalSysLockFromISR();
+
+  /* check that the states of things are as they're supposed to */
+  if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
+    /* rearm the timer */
+    chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
+    osalSysUnlockFromISR();
+    return;
+  }
+
+  /* If there is already a transaction ongoing then another one cannot be
+     started.*/
+  if (usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) {
+    /* rearm the timer */
+    chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
+    osalSysUnlockFromISR();
+    return;
+  }
+
+  /* Checking if there only a buffer partially filled, if so then it is
+     enforced in the queue and transmitted.*/
+  if(obqTryFlushI(&console_buf_queue)) {
+    size_t n,i;
+    uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n);
+
+    osalDbgAssert(buf != NULL, "queue is empty");
+
+    /* zero the rest of the buffer (buf should point to allocated space) */
+    for(i=n; i<CONSOLE_EPSIZE; i++)
+      buf[i]=0;
+    usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
+  }
+
+  /* rearm the timer */
+  chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
+  osalSysUnlockFromISR();
+}
+
+
+int8_t sendchar(uint8_t c) {
+  osalSysLock();
+  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
+    osalSysUnlock();
+    return 0;
+  }
+  osalSysUnlock();
+  /* Timeout after 5us if the queue is full.
+   * Increase this timeout if too much stuff is getting
+   * dropped (i.e. the buffer is getting full too fast
+   * for USB/HIDRAW to dequeue). Another possibility
+   * for fixing this kind of thing is to increase
+   * CONSOLE_QUEUE_CAPACITY. */
+  return(obqPutTimeout(&console_buf_queue, c, US2ST(100)));
+}
+
+#else /* CONSOLE_ENABLE */
+int8_t sendchar(uint8_t c) {
+  (void)c;
+  return 0;
+}
+#endif /* CONSOLE_ENABLE */
+
+void sendchar_pf(void *p, char c) {
+  (void)p;
+  sendchar((uint8_t)c);
+}
diff --git a/protocol/chibios/usb_main.h b/protocol/chibios/usb_main.h
new file mode 100644 (file)
index 0000000..d8f30e9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
+ *
+ * Based on the following work:
+ *  - Guillaume Duc's raw hid example (MIT License)
+ *    https://github.com/guiduc/usb-hid-chibios-example
+ *  - PJRC Teensy examples (MIT License)
+ *    https://www.pjrc.com/teensy/usb_keyboard.html
+ *  - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
+ *    https://github.com/tmk/tmk_keyboard/
+ *  - ChibiOS demo code (Apache 2.0 License)
+ *    http://www.chibios.org
+ *
+ * Since some GPL'd code is used, this work is licensed under
+ * GPL v2 or later.
+ */
+
+
+#ifndef _USB_MAIN_H_
+#define _USB_MAIN_H_
+
+// TESTING
+// extern uint8_t blinkLed;
+
+#include "ch.h"
+#include "hal.h"
+
+/* -------------------------
+ * General USB driver header
+ * -------------------------
+ */
+
+/* The USB driver to use */
+#define USB_DRIVER USBD1
+
+/* Initialize the USB driver and bus */
+void init_usb_driver(USBDriver *usbp);
+
+/* Send remote wakeup packet */
+void send_remote_wakeup(USBDriver *usbp);
+
+/* ---------------
+ * Keyboard header
+ * ---------------
+ */
+
+/* main keyboard (6kro) */
+#define KBD_INTERFACE   0
+#define KBD_ENDPOINT    1
+#define KBD_EPSIZE      8
+#define KBD_REPORT_KEYS (KBD_EPSIZE - 2)
+
+/* secondary keyboard */
+#ifdef NKRO_ENABLE
+#define NKRO_INTERFACE    4
+#define NKRO_ENDPOINT     5
+#define NKRO_EPSIZE       16
+#define NKRO_REPORT_KEYS  (NKRO_EPSIZE - 1)
+#endif
+
+/* this defines report_keyboard_t and computes REPORT_SIZE defines */
+// #include "report.h"
+
+/* extern report_keyboard_t keyboard_report_sent; */
+
+/* keyboard IN request callback handler */
+void kbd_in_cb(USBDriver *usbp, usbep_t ep);
+
+/* start-of-frame handler */
+void kbd_sof_cb(USBDriver *usbp);
+
+#ifdef NKRO_ENABLE
+/* nkro IN callback hander */
+void nkro_in_cb(USBDriver *usbp, usbep_t ep);
+#endif /* NKRO_ENABLE */
+
+/* ------------
+ * Mouse header
+ * ------------
+ */
+
+#ifdef MOUSE_ENABLE
+
+#define MOUSE_INTERFACE         1
+#define MOUSE_ENDPOINT          2
+#define MOUSE_EPSIZE            8
+
+/* mouse IN request callback handler */
+void mouse_in_cb(USBDriver *usbp, usbep_t ep);
+#endif /* MOUSE_ENABLE */
+
+/* ---------------
+ * Extrakey header
+ * ---------------
+ */
+
+#ifdef EXTRAKEY_ENABLE
+
+#define EXTRA_INTERFACE         3
+#define EXTRA_ENDPOINT          4
+#define EXTRA_EPSIZE            8
+
+/* extrakey IN request callback handler */
+void extra_in_cb(USBDriver *usbp, usbep_t ep);
+
+/* extra report structure */
+typedef struct {
+  uint8_t report_id;
+  uint16_t usage;
+} __attribute__ ((packed)) report_extra_t;
+#endif /* EXTRAKEY_ENABLE */
+
+/* --------------
+ * Console header
+ * --------------
+ */
+
+#ifdef CONSOLE_ENABLE
+
+#define CONSOLE_INTERFACE      2
+#define CONSOLE_ENDPOINT       3
+#define CONSOLE_EPSIZE         16
+
+/* Number of IN reports that can be stored inside the output queue */
+#define CONSOLE_QUEUE_CAPACITY 2
+#define CONSOLE_QUEUE_BUFFER_SIZE (CONSOLE_QUEUE_CAPACITY * CONSOLE_EPSIZE)
+
+/* Console flush time */
+#define CONSOLE_FLUSH_MS 50
+
+/* Putchar over the USB console */
+int8_t sendchar(uint8_t c);
+
+/* Flush output (send everything immediately) */
+void console_flush_output(void);
+
+/* console IN request callback handler */
+void console_in_cb(USBDriver *usbp, usbep_t ep);
+#endif /* CONSOLE_ENABLE */
+
+void sendchar_pf(void *p, char c);
+
+#endif /* _USB_MAIN_H_ */
index 44822b7e43e2500daabb11a5c3faa49a1c3b2ce1..569205bf302262306c017e5db338c6bad437217e 100644 (file)
@@ -68,7 +68,6 @@ POSSIBILITY OF SUCH DAMAGE.
 #endif
 
 /* debug for signal timing, see debug pin with oscilloscope */
-#define SERIAL_SOFT_DEBUG
 #ifdef SERIAL_SOFT_DEBUG
     #define SERIAL_SOFT_DEBUG_INIT()    (DDRD |= 1<<7)
     #define SERIAL_SOFT_DEBUG_TGL()     (PORTD ^= 1<<7)
@@ -176,7 +175,7 @@ void serial_send(uint8_t data)
 ISR(SERIAL_SOFT_RXD_VECT)
 {
     SERIAL_SOFT_DEBUG_TGL();
-    SERIAL_SOFT_RXD_INT_ENTER()
+    SERIAL_SOFT_RXD_INT_ENTER();
 
     uint8_t data = 0;
 
index 1a152ff3f2a1a7f82fb3cd300d21ae5e20b8070c..fe002c0d961d75fb72da070e5b8d959ca8ebd967 100644 (file)
@@ -13,7 +13,7 @@ void KBDReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
     bool is_error = false;
     report_keyboard_t *report = (report_keyboard_t *)buf;
 
-    dprintf("KBDReport: %02X %02X", report->mods, report->reserved);
+    dprintf("keyboard input:  %02X %02X", report->mods, report->reserved);
     for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
         if (IS_ERROR(report->keys[i])) {
             is_error = true;
index 860fc1a9310da970ebecba597c150802f522f37e..0ae84d912fd452b1a9a2000402b487e91569f1c7 100644 (file)
--- a/rules.mk
+++ b/rules.mk
@@ -425,7 +425,6 @@ ifneq (, $(findstring 0.7, $(shell dfu-programmer --version 2>&1)))
 else
        dfu-programmer $(MCU) erase
 endif
-       dfu-programmer $(MCU) erase
        dfu-programmer $(MCU) flash $(TARGET).hex
        dfu-programmer $(MCU) reset
        
diff --git a/tool/chibios/.gitignore b/tool/chibios/.gitignore
new file mode 100644 (file)
index 0000000..3118dbe
--- /dev/null
@@ -0,0 +1 @@
+chibios
diff --git a/tool/chibios/ch-bootloader-jump.patch b/tool/chibios/ch-bootloader-jump.patch
new file mode 100644 (file)
index 0000000..d886576
--- /dev/null
@@ -0,0 +1,116 @@
+diff --git a/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s b/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s
+index 51a79bb..42d07bd 100644
+--- a/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s
++++ b/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s
+@@ -105,6 +105,13 @@
+ #define CRT0_CALL_DESTRUCTORS               TRUE\r
+ #endif\r
\r
++/**\r
++ * @brief   Magic number for jumping to bootloader.\r
++ */\r
++#if !defined(MAGIC_BOOTLOADER_NUMBER) || defined(__DOXYGEN__)\r
++#define MAGIC_BOOTLOADER_NUMBER 0xDEADBEEF\r
++#endif\r
++\r
+ /*===========================================================================*/\r
+ /* Code section.                                                             */\r
+ /*===========================================================================*/\r
+@@ -124,6 +131,17 @@
+                 .thumb_func\r
+                 .global Reset_Handler\r
+ Reset_Handler:\r
++\r
++#ifdef STM32_BOOTLOADER_ADDRESS\r
++                /* jump to bootloader code */\r
++                ldr        r0, =__ram0_end__-4\r
++                ldr        r1, =MAGIC_BOOTLOADER_NUMBER\r
++                ldr        r2, [r0, #0]\r
++                str        r0, [r0, #0] /* erase stored magic */\r
++                cmp        r2, r1\r
++                beq        Bootloader_Jump\r
++#endif /* STM32_BOOTLOADER_ADDRESS */\r
++\r
+                 /* Interrupts are globally masked initially.*/\r
+                 cpsid   i\r
\r
+@@ -242,6 +260,21 @@ endfiniloop:
+                 ldr     r1, =__default_exit\r
+                 bx      r1\r
\r
++#ifdef STM32_BOOTLOADER_ADDRESS\r
++/*\r
++ * Jump-to-bootloader function.\r
++ */\r
++\r
++                .align  2\r
++                .thumb_func\r
++Bootloader_Jump:\r
++                ldr     r0, =STM32_BOOTLOADER_ADDRESS\r
++                ldr     r1, [r0, #0]\r
++                mov     sp, r1\r
++                ldr     r0, [r0, #4]\r
++                bx      r0\r
++#endif /* STM32_BOOTLOADER_ADDRESS */\r
++\r
+ #endif\r
\r
+ /** @} */\r
+diff --git a/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s b/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s
+index 4812a29..dca9f88 100644
+--- a/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s
++++ b/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s
+@@ -140,6 +140,13 @@
+ #define CRT0_CPACR_INIT                     0x00F00000\r
+ #endif\r
\r
++/**\r
++ * @brief   Magic number for jumping to bootloader.\r
++ */\r
++#if !defined(MAGIC_BOOTLOADER_NUMBER) || defined(__DOXYGEN__)\r
++#define MAGIC_BOOTLOADER_NUMBER 0xDEADBEEF\r
++#endif\r
++\r
+ /*===========================================================================*/\r
+ /* Code section.                                                             */\r
+ /*===========================================================================*/\r
+@@ -164,6 +171,17 @@
+                 .thumb_func\r
+                 .global Reset_Handler\r
+ Reset_Handler:\r
++\r
++#ifdef STM32_BOOTLOADER_ADDRESS\r
++                /* jump to bootloader code */\r
++                ldr        r0, =__ram0_end__-4\r
++                ldr        r1, =MAGIC_BOOTLOADER_NUMBER\r
++                ldr        r2, [r0, #0]\r
++                str        r0, [r0, #0] /* erase stored magic */\r
++                cmp        r2, r1\r
++                beq        Bootloader_Jump\r
++#endif /* STM32_BOOTLOADER_ADDRESS */\r
++\r
+                 /* Interrupts are globally masked initially.*/\r
+                 cpsid   i\r
\r
+@@ -305,6 +323,21 @@ endfiniloop:
+                 /* Branching to the defined exit handler.*/\r
+                 b       __default_exit\r
\r
++#ifdef STM32_BOOTLOADER_ADDRESS\r
++/*\r
++ * Jump-to-bootloader function.\r
++ */\r
++\r
++                .align  2\r
++                .thumb_func\r
++Bootloader_Jump:\r
++                ldr     r0, =STM32_BOOTLOADER_ADDRESS\r
++                ldr     r1, [r0, #0]\r
++                mov     sp, r1\r
++                ldr     r0, [r0, #4]\r
++                bx      r0\r
++#endif /* STM32_BOOTLOADER_ADDRESS */\r
++\r
+ #endif /* !defined(__DOXYGEN__) */\r
\r
+ /** @} */\r
diff --git a/tool/chibios/chibios.mk b/tool/chibios/chibios.mk
new file mode 100644 (file)
index 0000000..a67e067
--- /dev/null
@@ -0,0 +1,231 @@
+##############################################################################
+# Build global options
+# NOTE: Can be overridden externally.
+#
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+  USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 -std=gnu99 -DPROTOCOL_CHIBIOS
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+  USE_COPT =
+endif
+
+# include specific config.h?
+ifdef CONFIG_H
+    USE_COPT += -include $(CONFIG_H)
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+  USE_CPPOPT = -fno-rtti
+endif
+
+# Enable this if you want the linker to remove unused code and data
+ifeq ($(USE_LINK_GC),)
+  USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+  USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO)
+ifeq ($(USE_LTO),)
+  USE_LTO = yes
+endif
+
+# If enabled, this option allows to compile the application in THUMB mode.
+ifeq ($(USE_THUMB),)
+  USE_THUMB = yes
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+  USE_VERBOSE_COMPILE = no
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+  USE_SMART_BUILD = yes
+endif
+
+#
+# Build global options
+##############################################################################
+
+##############################################################################
+# Architecture or project specific options
+#
+
+# Stack size to be allocated to the Cortex-M process stack. This stack is
+# the stack used by the main() thread.
+ifeq ($(USE_PROCESS_STACKSIZE),)
+  USE_PROCESS_STACKSIZE = 0x200
+endif
+
+# Stack size to the allocated to the Cortex-M main/exceptions stack. This
+# stack is used for processing interrupts and exceptions.
+ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
+  USE_EXCEPTIONS_STACKSIZE = 0x400
+endif
+
+#
+# Architecture or project specific options
+##############################################################################
+
+##############################################################################
+# Project, sources and paths
+#
+
+# Imported source files and paths
+CHIBIOS = $(TMK_DIR)/tool/chibios/chibios
+# Startup files.
+include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
+# HAL-OSAL files (optional).
+include $(CHIBIOS)/os/hal/hal.mk
+include $(CHIBIOS)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/platform.mk
+ifneq ("$(wildcard $(TARGET_DIR)/boards/$(BOARD))","")
+       include $(TARGET_DIR)/boards/$(BOARD)/board.mk
+else
+       include $(CHIBIOS)/os/hal/boards/$(BOARD)/board.mk
+endif
+include $(CHIBIOS)/os/hal/osal/rt/osal.mk
+# RTOS files (optional).
+include $(CHIBIOS)/os/rt/rt.mk
+include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
+# Other files (optional).
+
+# Define linker script file here
+ifneq ("$(wildcard $(TARGET_DIR)/ld/$(MCU_LDSCRIPT).ld)","")
+LDSCRIPT = $(TARGET_DIR)/ld/$(MCU_LDSCRIPT).ld
+else
+LDSCRIPT = $(STARTUPLD)/$(MCU_LDSCRIPT).ld
+endif
+
+# C sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CSRC = $(STARTUPSRC) \
+       $(KERNSRC) \
+       $(PORTSRC) \
+       $(OSALSRC) \
+       $(HALSRC) \
+       $(PLATFORMSRC) \
+       $(BOARDSRC) \
+       $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
+       $(TMK_DIR)/protocol/chibios/usb_main.c \
+       $(TMK_DIR)/protocol/chibios/main.c \
+       $(SRC)
+
+# C++ sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CPPSRC =
+
+# C sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACSRC =
+
+# C++ sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACPPSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCPPSRC =
+
+# List ASM source files here
+ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
+
+INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
+         $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
+         $(CHIBIOS)/os/hal/lib/streams $(CHIBIOS)/os/various \
+         $(TMK_DIR) $(COMMON_DIR) $(TMK_DIR)/protocol/chibios \
+         $(TMK_DIR)/protocol $(TARGET_DIR)
+
+#
+# Project, sources and paths
+##############################################################################
+
+##############################################################################
+# Compiler settings
+#
+
+#TRGT = arm-elf-
+TRGT = arm-none-eabi-
+CC   = $(TRGT)gcc
+CPPC = $(TRGT)g++
+# Enable loading with g++ only if you need C++ runtime support.
+# NOTE: You can use C++ even without C++ support if you are careful. C++
+#       runtime support makes code size explode.
+LD   = $(TRGT)gcc
+#LD   = $(TRGT)g++
+CP   = $(TRGT)objcopy
+AS   = $(TRGT)gcc -x assembler-with-cpp
+AR   = $(TRGT)ar
+OD   = $(TRGT)objdump
+SZ   = $(TRGT)size
+HEX  = $(CP) -O ihex
+BIN  = $(CP) -O binary
+
+# ARM-specific options here
+AOPT =
+
+# THUMB-specific options here
+TOPT = -mthumb -DTHUMB
+
+# Define C warning options here
+CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes -Wno-missing-field-initializers
+
+# Define C++ warning options here
+CPPWARN = -Wall -Wextra -Wundef
+
+#
+# Compiler settings
+##############################################################################
+
+##############################################################################
+# Start of user section
+#
+
+# List all user C define here, like -D_DEBUG=1
+## Select which interfaces to include here!
+UDEFS = $(OPT_DEFS)
+
+# Define ASM defines here
+UADEFS = $(OPT_DEFS)
+# bootloader definitions may be used in the startup .s file
+ifneq ("$(wildcard $(TARGET_DIR)/bootloader_defs.h)","")
+    UADEFS += -include $(TARGET_DIR)/bootloader_defs.h
+    UDEFS += -include $(TARGET_DIR)/bootloader_defs.h
+else ifneq ("$(wildcard $(TARGET_DIR)/boards/$(BOARD)/bootloader_defs.h)","")
+    UADEFS += -include $(TARGET_DIR)/boards/$(BOARD)/bootloader_defs.h
+    UDEFS += -include $(TARGET_DIR)/boards/$(BOARD)/bootloader_defs.h
+endif
+
+# List all user directories here
+UINCDIR =
+
+# List the user directory to look for the libraries here
+ULIBDIR =
+
+# List all user libraries here
+ULIBS =
+
+#
+# End of user defines
+##############################################################################
+
+RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC
+include $(RULESPATH)/rules.mk
diff --git a/tool/chibios/common.mk b/tool/chibios/common.mk
new file mode 100644 (file)
index 0000000..7e3cccc
--- /dev/null
@@ -0,0 +1,85 @@
+COMMON_DIR = $(TMK_DIR)/common
+SRC += $(COMMON_DIR)/host.c \
+       $(COMMON_DIR)/keyboard.c \
+       $(COMMON_DIR)/action.c \
+       $(COMMON_DIR)/action_tapping.c \
+       $(COMMON_DIR)/action_macro.c \
+       $(COMMON_DIR)/action_layer.c \
+       $(COMMON_DIR)/action_util.c \
+       $(COMMON_DIR)/keymap.c \
+       $(COMMON_DIR)/print.c \
+       $(COMMON_DIR)/debug.c \
+       $(COMMON_DIR)/util.c \
+       $(COMMON_DIR)/chibios/suspend.c \
+       $(COMMON_DIR)/chibios/printf.c \
+       $(COMMON_DIR)/chibios/timer.c \
+       $(COMMON_DIR)/chibios/bootloader.c
+
+
+# Option modules
+ifdef BOOTMAGIC_ENABLE
+    SRC += $(COMMON_DIR)/bootmagic.c
+    SRC += $(COMMON_DIR)/chibios/eeconfig.c
+    OPT_DEFS += -DBOOTMAGIC_ENABLE
+endif
+
+ifdef MOUSEKEY_ENABLE
+    SRC += $(COMMON_DIR)/mousekey.c
+    OPT_DEFS += -DMOUSEKEY_ENABLE
+    OPT_DEFS += -DMOUSE_ENABLE
+endif
+
+ifdef EXTRAKEY_ENABLE
+    OPT_DEFS += -DEXTRAKEY_ENABLE
+endif
+
+ifdef CONSOLE_ENABLE
+    OPT_DEFS += -DCONSOLE_ENABLE
+else
+    OPT_DEFS += -DNO_PRINT
+    OPT_DEFS += -DNO_DEBUG
+endif
+
+ifdef COMMAND_ENABLE
+    SRC += $(COMMON_DIR)/command.c
+    OPT_DEFS += -DCOMMAND_ENABLE
+endif
+
+ifdef NKRO_ENABLE
+    OPT_DEFS += -DNKRO_ENABLE
+endif
+
+ifdef USB_6KRO_ENABLE
+    OPT_DEFS += -DUSB_6KRO_ENABLE
+endif
+
+ifdef SLEEP_LED_ENABLE
+    SRC += $(COMMON_DIR)/chibios/sleep_led.c
+    OPT_DEFS += -DSLEEP_LED_ENABLE
+    OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
+endif
+
+ifdef BACKLIGHT_ENABLE
+    SRC += $(COMMON_DIR)/backlight.c
+    OPT_DEFS += -DBACKLIGHT_ENABLE
+endif
+
+ifdef KEYMAP_SECTION_ENABLE
+    OPT_DEFS += -DKEYMAP_SECTION_ENABLE
+
+    ifeq ($(strip $(MCU)),atmega32u2)
+       EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
+    else ifeq ($(strip $(MCU)),atmega32u4)
+       EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
+    else
+       EXTRALDFLAGS = $(error no ldscript for keymap section)
+    endif
+endif
+
+# Version string
+OPT_DEFS += -DVERSION=$(shell (git describe --always --dirty || echo 'unknown') 2> /dev/null)
+
+# Bootloader address
+ifdef BOOTLOADER_ADDRESS
+    OPT_DEFS += -DBOOTLOADER_ADDRESS=$(BOOTLOADER_ADDRESS)
+endif
index 77bf7c3e498fe95c12111aabaee6805cf5d2c9a9..a0aa87172cc9dc7dde4a89edb88c31c17d08eae1 100644 (file)
@@ -63,7 +63,7 @@ endif
 
 ifdef SLEEP_LED_ENABLE
     $(error Not Supported)
-    SRC += common/sleep_led.c
+    SRC += common/mbed/sleep_led.c
     OPT_DEFS += -DSLEEP_LED_ENABLE
     OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
 endif
Imprint / Impressum