aboutsummaryrefslogtreecommitdiff
path: root/tmk_core
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core')
-rw-r--r--tmk_core/avr.mk185
-rw-r--r--tmk_core/chibios.mk154
-rw-r--r--tmk_core/common.mk36
-rw-r--r--tmk_core/common/action_tapping.c2
-rw-r--r--tmk_core/common/avr/sleep_led.c (renamed from tmk_core/common/sleep_led.c)0
-rw-r--r--tmk_core/common/bootmagic.c7
-rw-r--r--tmk_core/common/chibios/bootloader.c47
-rw-r--r--tmk_core/common/chibios/eeprom.c588
-rw-r--r--tmk_core/common/chibios/printf.c240
-rw-r--r--tmk_core/common/chibios/printf.h111
-rw-r--r--tmk_core/common/chibios/sleep_led.c226
-rw-r--r--tmk_core/common/chibios/suspend.c65
-rw-r--r--tmk_core/common/chibios/timer.c27
-rw-r--r--tmk_core/common/command.c23
-rw-r--r--tmk_core/common/eeconfig.c (renamed from tmk_core/common/avr/eeconfig.c)2
-rw-r--r--tmk_core/common/eeprom.h22
-rw-r--r--tmk_core/common/magic.c4
-rw-r--r--tmk_core/common/print.c8
-rw-r--r--tmk_core/common/print.h10
-rw-r--r--tmk_core/common/progmem.h4
-rw-r--r--tmk_core/common/report.h5
-rw-r--r--tmk_core/common/wait.h8
-rw-r--r--tmk_core/protocol/chibios.mk10
-rw-r--r--tmk_core/protocol/chibios/README.md55
-rw-r--r--tmk_core/protocol/chibios/main.c147
-rw-r--r--tmk_core/protocol/chibios/usb_main.c1372
-rw-r--r--tmk_core/protocol/chibios/usb_main.h139
-rw-r--r--tmk_core/readme.md16
-rw-r--r--tmk_core/rules.mk220
-rw-r--r--tmk_core/tool/chibios/.gitignore2
-rw-r--r--tmk_core/tool/chibios/ch-bootloader-jump.patch116
31 files changed, 3607 insertions, 244 deletions
diff --git a/tmk_core/avr.mk b/tmk_core/avr.mk
new file mode 100644
index 000000000..72be5e6da
--- /dev/null
+++ b/tmk_core/avr.mk
@@ -0,0 +1,185 @@
1# Hey Emacs, this is a -*- makefile -*-
2##############################################################################
3# Compiler settings
4#
5CC = avr-gcc
6OBJCOPY = avr-objcopy
7OBJDUMP = avr-objdump
8SIZE = avr-size
9AR = avr-ar rcs
10NM = avr-nm
11HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature
12EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
13
14
15
16COMPILEFLAGS += -funsigned-char
17COMPILEFLAGS += -funsigned-bitfields
18COMPILEFLAGS += -ffunction-sections
19COMPILEFLAGS += -fdata-sections
20COMPILEFLAGS += -fpack-struct
21COMPILEFLAGS += -fshort-enums
22
23CFLAGS += $(COMPILEFLAGS)
24CFLAGS += -fno-inline-small-functions
25CFLAGS += -fno-strict-aliasing
26
27CPPFLAGS += $(COMPILEFLAGS)
28CPPFLAGS += -fno-exceptions
29
30LDFLAGS +=-Wl,--gc-sections
31
32OPT_DEFS += -DF_CPU=$(F_CPU)UL
33
34MCUFLAGS = -mmcu=$(MCU)
35
36# List any extra directories to look for libraries here.
37# Each directory must be seperated by a space.
38# Use forward slashes for directory separators.
39# For a directory that has spaces, enclose it in quotes.
40EXTRALIBDIRS =
41
42
43#---------------- External Memory Options ----------------
44
45# 64 KB of external RAM, starting after internal RAM (ATmega128!),
46# used for variables (.data/.bss) and heap (malloc()).
47#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
48
49# 64 KB of external RAM, starting after internal RAM (ATmega128!),
50# only used for heap (malloc()).
51#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
52
53EXTMEMOPTS =
54
55#---------------- Debugging Options ----------------
56
57# Debugging format.
58# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
59# AVR Studio 4.10 requires dwarf-2.
60# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
61DEBUG = dwarf-2
62
63# For simulavr only - target MCU frequency.
64DEBUG_MFREQ = $(F_CPU)
65
66# Set the DEBUG_UI to either gdb or insight.
67# DEBUG_UI = gdb
68DEBUG_UI = insight
69
70# Set the debugging back-end to either avarice, simulavr.
71DEBUG_BACKEND = avarice
72#DEBUG_BACKEND = simulavr
73
74# GDB Init Filename.
75GDBINIT_FILE = __avr_gdbinit
76
77# When using avarice settings for the JTAG
78JTAG_DEV = /dev/com1
79
80# Debugging port used to communicate between GDB / avarice / simulavr.
81DEBUG_PORT = 4242
82
83# Debugging host used to communicate between GDB / avarice / simulavr, normally
84# just set to localhost unless doing some sort of crazy debugging when
85# avarice is running on a different computer.
86DEBUG_HOST = localhost
87
88#============================================================================
89# Autodecct teensy loader
90ifneq (, $(shell which teensy-loader-cli 2>/dev/null))
91 TEENSY_LOADER_CLI = teensy-loader-cli
92else
93 TEENSY_LOADER_CLI = teensy_loader_cli
94endif
95
96# Program the device.
97program: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep
98 $(PROGRAM_CMD)
99
100teensy: $(BUILD_DIR)/$(TARGET).hex
101 $(TEENSY_LOADER_CLI) -mmcu=$(MCU) -w -v $(BUILD_DIR)/$(TARGET).hex
102
103flip: $(BUILD_DIR)/$(TARGET).hex
104 batchisp -hardware usb -device $(MCU) -operation erase f
105 batchisp -hardware usb -device $(MCU) -operation loadbuffer $(BUILD_DIR)/$(TARGET).hex program
106 batchisp -hardware usb -device $(MCU) -operation start reset 0
107
108dfu: $(BUILD_DIR)/$(TARGET).hex sizeafter
109ifneq (, $(findstring 0.7, $(shell dfu-programmer --version 2>&1)))
110 dfu-programmer $(MCU) erase --force
111else
112 dfu-programmer $(MCU) erase
113endif
114 dfu-programmer $(MCU) flash $(BUILD_DIR)/$(TARGET).hex
115 dfu-programmer $(MCU) reset
116
117dfu-start:
118 dfu-programmer $(MCU) reset
119 dfu-programmer $(MCU) start
120
121flip-ee: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep
122 $(COPY) $(BUILD_DIR)/$(TARGET).eep $(BUILD_DIR)/$(TARGET)eep.hex
123 batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase
124 batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(BUILD_DIR)/$(TARGET)eep.hex program
125 batchisp -hardware usb -device $(MCU) -operation start reset 0
126 $(REMOVE) $(BUILD_DIR)/$(TARGET)eep.hex
127
128dfu-ee: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep
129ifneq (, $(findstring 0.7, $(shell dfu-programmer --version 2>&1)))
130 dfu-programmer $(MCU) flash --eeprom $(BUILD_DIR)/$(TARGET).eep
131else
132 dfu-programmer $(MCU) flash-eeprom $(BUILD_DIR)/$(TARGET).eep
133endif
134 dfu-programmer $(MCU) reset
135
136
137# Generate avr-gdb config/init file which does the following:
138# define the reset signal, load the target file, connect to target, and set
139# a breakpoint at main().
140gdb-config:
141 @$(REMOVE) $(GDBINIT_FILE)
142 @echo define reset >> $(GDBINIT_FILE)
143 @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
144 @echo end >> $(GDBINIT_FILE)
145 @echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE)
146 @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
147ifeq ($(DEBUG_BACKEND),simulavr)
148 @echo load >> $(GDBINIT_FILE)
149endif
150 @echo break main >> $(GDBINIT_FILE)
151
152debug: gdb-config $(BUILD_DIR)/$(TARGET).elf
153ifeq ($(DEBUG_BACKEND), avarice)
154 @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
155 @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
156 $(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
157 @$(WINSHELL) /c pause
158
159else
160 @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
161 $(DEBUG_MFREQ) --port $(DEBUG_PORT)
162endif
163 @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
164
165
166
167
168# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
169COFFCONVERT = $(OBJCOPY) --debugging
170COFFCONVERT += --change-section-address .data-0x800000
171COFFCONVERT += --change-section-address .bss-0x800000
172COFFCONVERT += --change-section-address .noinit-0x800000
173COFFCONVERT += --change-section-address .eeprom-0x810000
174
175
176
177coff: $(BUILD_DIR)/$(TARGET).elf
178 @$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof
179 $(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof
180
181
182extcoff: $(BUILD_DIR)/$(TARGET).elf
183 @$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof
184 $(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof
185
diff --git a/tmk_core/chibios.mk b/tmk_core/chibios.mk
new file mode 100644
index 000000000..0abb933a8
--- /dev/null
+++ b/tmk_core/chibios.mk
@@ -0,0 +1,154 @@
1# Hey Emacs, this is a -*- makefile -*-
2##############################################################################
3# Architecture or project specific options
4#
5
6# Stack size to be allocated to the Cortex-M process stack. This stack is
7# the stack used by the main() thread.
8ifeq ($(USE_PROCESS_STACKSIZE),)
9 USE_PROCESS_STACKSIZE = 0x200
10endif
11
12# Stack size to the allocated to the Cortex-M main/exceptions stack. This
13# stack is used for processing interrupts and exceptions.
14ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
15 USE_EXCEPTIONS_STACKSIZE = 0x400
16endif
17
18#
19# Architecture or project specific options
20##############################################################################
21
22##############################################################################
23# Project, sources and paths
24#
25
26# Imported source files and paths
27CHIBIOS = $(TOP_DIR)/lib/chibios
28CHIBIOS_CONTRIB = $(TOP_DIR)/lib/chibios-contrib
29# Startup files. Try a few different locations, for compability with old versions and
30# for things hardware in the contrib repository
31STARTUP_MK = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
32ifeq ("$(wildcard $(STARTUP_MK))","")
33 STARTUP_MK = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
34 ifeq ("$(wildcard $(STARTUP_MK))","")
35 STARTUP_MK = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
36 endif
37endif
38include $(STARTUP_MK)
39# HAL-OSAL files (optional).
40include $(CHIBIOS)/os/hal/hal.mk
41
42PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/platform.mk
43ifeq ("$(wildcard $(PLATFORM_MK))","")
44PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/platform.mk
45endif
46include $(PLATFORM_MK)
47
48
49BOARD_MK = $(KEYBOARD_PATH)/boards/$(BOARD)/board.mk
50ifeq ("$(wildcard $(BOARD_MK))","")
51 BOARD_MK = $(CHIBIOS)/os/hal/boards/$(BOARD)/board.mk
52 ifeq ("$(wildcard $(BOARD_MK))","")
53 BOARD_MK = $(CHIBIOS_CONTRIB)/os/hal/boards/$(BOARD)/board.mk
54 endif
55endif
56include $(BOARD_MK)
57include $(CHIBIOS)/os/hal/osal/rt/osal.mk
58# RTOS files (optional).
59include $(CHIBIOS)/os/rt/rt.mk
60# Compability with old version
61PORT_V = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
62ifeq ("$(wildcard $(PORT_V))","")
63PORT_V = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
64endif
65include $(PORT_V)
66# Other files (optional).
67include $(CHIBIOS)/os/hal/lib/streams/streams.mk
68
69RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC
70ifeq ("$(wildcard $(RULESPATH)/rules.mk)","")
71RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
72endif
73
74# Define linker script file here
75ifneq ("$(wildcard $(KEYBOARD_PATH)/ld/$(MCU_LDSCRIPT).ld)","")
76LDSCRIPT = $(KEYBOARD_PATH)/ld/$(MCU_LDSCRIPT).ld
77else
78LDSCRIPT = $(STARTUPLD)/$(MCU_LDSCRIPT).ld
79endif
80
81CHIBISRC = $(STARTUPSRC) \
82 $(KERNSRC) \
83 $(PORTSRC) \
84 $(OSALSRC) \
85 $(HALSRC) \
86 $(PLATFORMSRC) \
87 $(BOARDSRC) \
88 $(STREAMSSRC) \
89 $(STARTUPASM) \
90 $(PORTASM) \
91 $(OSALASM)
92
93SRC += $(patsubst $(TOP_DIR)/%,%,$(CHIBISRC))
94
95EXTRAINCDIRS += $(CHIBIOS)/os/license \
96 $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
97 $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
98 $(STREAMSINC) $(CHIBIOS)/os/various
99
100#
101# Project, sources and paths
102##############################################################################
103
104
105##############################################################################
106# Compiler settings
107#
108CC = arm-none-eabi-gcc
109OBJCOPY = arm-none-eabi-objcopy
110OBJDUMP = arm-none-eabi-objdump
111SIZE = arm-none-eabi-size
112AR = arm-none-eabi-ar
113NM = arm-none-eabi-nm
114HEX = $(OBJCOPY) -O $(FORMAT)
115EEP =
116
117THUMBFLAGS = -DTHUMB_PRESENT -mno-thumb-interwork -DTHUMB_NO_INTERWORKING -mthumb -DTHUMB
118
119COMPILEFLAGS += -fomit-frame-pointer
120COMPILEFLAGS += -falign-functions=16
121COMPILEFLAGS += -ffunction-sections
122COMPILEFLAGS += -fdata-sections
123COMPILEFLAGS += -fno-common
124COMPILEFLAGS += $(THUMBFLAGS)
125
126CFLAGS += $(COMPILEFLAGS)
127
128ASFLAGS += $(THUMBFLAGS)
129
130CPPFLAGS += $(COMPILEFLAGS)
131CPPFLAGS += -fno-rtti
132
133LDFLAGS +=-Wl,--gc-sections
134LDFLAGS += -mno-thumb-interwork -mthumb
135LDSYMBOLS =,--defsym=__process_stack_size__=$(USE_PROCESS_STACKSIZE)
136LDSYMBOLS :=$(LDSYMBOLS),--defsym=__main_stack_size__=$(USE_EXCEPTIONS_STACKSIZE)
137LDFLAGS += -Wl,--script=$(LDSCRIPT)$(LDSYMBOLS)
138
139OPT_DEFS += -DPROTOCOL_CHIBIOS
140
141MCUFLAGS = -mcpu=$(MCU)
142
143DEBUG = gdb
144
145# Define ASM defines here
146# bootloader definitions may be used in the startup .s file
147ifneq ("$(wildcard $(KEYBOARD_PATH)/bootloader_defs.h)","")
148 OPT_DEFS += -include $(KEYBOARD_PATH)/bootloader_defs.h
149else ifneq ("$(wildcard $(KEYBOARD_PATH)/boards/$(BOARD)/bootloader_defs.h)","")
150 OPT_DEFS += -include $(KEYBOARD_PATH)/boards/$(BOARD)/bootloader_defs.h
151endif
152
153# List any extra directories to look for libraries here.
154EXTRALIBDIRS = $(RULESPATH)/ld \ No newline at end of file
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index f2a22e4f8..d71fba9bc 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -1,4 +1,10 @@
1COMMON_DIR = common 1COMMON_DIR = common
2ifeq ($(PLATFORM),AVR)
3 PLATFORM_COMMON_DIR = $(COMMON_DIR)/avr
4else ifeq ($(PLATFORM),CHIBIOS)
5 PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios
6endif
7
2SRC += $(COMMON_DIR)/host.c \ 8SRC += $(COMMON_DIR)/host.c \
3 $(COMMON_DIR)/keyboard.c \ 9 $(COMMON_DIR)/keyboard.c \
4 $(COMMON_DIR)/action.c \ 10 $(COMMON_DIR)/action.c \
@@ -9,21 +15,29 @@ SRC += $(COMMON_DIR)/host.c \
9 $(COMMON_DIR)/print.c \ 15 $(COMMON_DIR)/print.c \
10 $(COMMON_DIR)/debug.c \ 16 $(COMMON_DIR)/debug.c \
11 $(COMMON_DIR)/util.c \ 17 $(COMMON_DIR)/util.c \
12 $(COMMON_DIR)/avr/suspend.c \ 18 $(COMMON_DIR)/eeconfig.c \
13 $(COMMON_DIR)/avr/xprintf.S \ 19 $(PLATFORM_COMMON_DIR)/suspend.c \
14 $(COMMON_DIR)/avr/timer.c \ 20 $(PLATFORM_COMMON_DIR)/timer.c \
15 $(COMMON_DIR)/avr/bootloader.c 21 $(PLATFORM_COMMON_DIR)/bootloader.c \
22
23ifeq ($(PLATFORM),AVR)
24 SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
25endif
26
27ifeq ($(PLATFORM),CHIBIOS)
28 SRC += $(PLATFORM_COMMON_DIR)/printf.c
29 SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
30endif
31
16 32
17 33
18# Option modules 34# Option modules
19ifeq ($(strip $(BOOTMAGIC_ENABLE)), yes) 35ifeq ($(strip $(BOOTMAGIC_ENABLE)), yes)
20 OPT_DEFS += -DBOOTMAGIC_ENABLE 36 OPT_DEFS += -DBOOTMAGIC_ENABLE
21 SRC += $(COMMON_DIR)/bootmagic.c 37 SRC += $(COMMON_DIR)/bootmagic.c
22 SRC += $(COMMON_DIR)/avr/eeconfig.c
23else 38else
24 OPT_DEFS += -DMAGIC_ENABLE 39 OPT_DEFS += -DMAGIC_ENABLE
25 SRC += $(COMMON_DIR)/magic.c 40 SRC += $(COMMON_DIR)/magic.c
26 SRC += $(COMMON_DIR)/avr/eeconfig.c
27endif 41endif
28 42
29ifeq ($(strip $(MOUSEKEY_ENABLE)), yes) 43ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
@@ -57,14 +71,13 @@ ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
57endif 71endif
58 72
59ifeq ($(strip $(SLEEP_LED_ENABLE)), yes) 73ifeq ($(strip $(SLEEP_LED_ENABLE)), yes)
60 SRC += $(COMMON_DIR)/sleep_led.c 74 SRC += $(PLATFORM_COMMON_DIR)/sleep_led.c
61 OPT_DEFS += -DSLEEP_LED_ENABLE 75 OPT_DEFS += -DSLEEP_LED_ENABLE
62 OPT_DEFS += -DNO_SUSPEND_POWER_DOWN 76 OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
63endif 77endif
64 78
65ifeq ($(strip $(BACKLIGHT_ENABLE)), yes) 79ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
66 SRC += $(COMMON_DIR)/backlight.c 80 SRC += $(COMMON_DIR)/backlight.c
67 SRC += $(COMMON_DIR)/avr/eeconfig.c
68 OPT_DEFS += -DBACKLIGHT_ENABLE 81 OPT_DEFS += -DBACKLIGHT_ENABLE
69endif 82endif
70 83
@@ -87,6 +100,13 @@ endif
87# Version string 100# Version string
88OPT_DEFS += -DVERSION=$(shell (git describe --always --dirty || echo 'unknown') 2> /dev/null) 101OPT_DEFS += -DVERSION=$(shell (git describe --always --dirty || echo 'unknown') 2> /dev/null)
89 102
103# Bootloader address
104ifdef STM32_BOOTLOADER_ADDRESS
105 OPT_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
106endif
90 107
91# Search Path 108# Search Path
92VPATH += $(TMK_PATH)/$(COMMON_DIR) 109VPATH += $(TMK_PATH)/$(COMMON_DIR)
110ifeq ($(PLATFORM),CHIBIOS)
111VPATH += $(TMK_PATH)/$(COMMON_DIR)/chibios
112endif \ No newline at end of file
diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c
index ff78d7f2a..e16e11be7 100644
--- a/tmk_core/common/action_tapping.c
+++ b/tmk_core/common/action_tapping.c
@@ -257,7 +257,7 @@ bool process_tapping(keyrecord_t *keyp)
257 return true; 257 return true;
258 } 258 }
259 } else { 259 } else {
260 if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n"); 260 if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n") {};
261 process_record(keyp); 261 process_record(keyp);
262 return true; 262 return true;
263 } 263 }
diff --git a/tmk_core/common/sleep_led.c b/tmk_core/common/avr/sleep_led.c
index dab3eb0f3..dab3eb0f3 100644
--- a/tmk_core/common/sleep_led.c
+++ b/tmk_core/common/avr/sleep_led.c
diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c
index 30e8a0f20..90275a18b 100644
--- a/tmk_core/common/bootmagic.c
+++ b/tmk_core/common/bootmagic.c
@@ -1,6 +1,6 @@
1#include <stdint.h> 1#include <stdint.h>
2#include <stdbool.h> 2#include <stdbool.h>
3#include <util/delay.h> 3#include "wait.h"
4#include "matrix.h" 4#include "matrix.h"
5#include "bootloader.h" 5#include "bootloader.h"
6#include "debug.h" 6#include "debug.h"
@@ -10,6 +10,7 @@
10#include "eeconfig.h" 10#include "eeconfig.h"
11#include "bootmagic.h" 11#include "bootmagic.h"
12 12
13keymap_config_t keymap_config;
13 14
14void bootmagic(void) 15void bootmagic(void)
15{ 16{
@@ -19,9 +20,9 @@ void bootmagic(void)
19 } 20 }
20 21
21 /* do scans in case of bounce */ 22 /* do scans in case of bounce */
22 print("boogmagic scan: ... "); 23 print("bootmagic scan: ... ");
23 uint8_t scan = 100; 24 uint8_t scan = 100;
24 while (scan--) { matrix_scan(); _delay_ms(10); } 25 while (scan--) { matrix_scan(); wait_ms(10); }
25 print("done.\n"); 26 print("done.\n");
26 27
27 /* bootmagic skip */ 28 /* bootmagic skip */
diff --git a/tmk_core/common/chibios/bootloader.c b/tmk_core/common/chibios/bootloader.c
new file mode 100644
index 000000000..8a533ab6f
--- /dev/null
+++ b/tmk_core/common/chibios/bootloader.c
@@ -0,0 +1,47 @@
1#include "bootloader.h"
2
3#include "ch.h"
4#include "hal.h"
5
6#ifdef STM32_BOOTLOADER_ADDRESS
7/* STM32 */
8
9#if defined(STM32F0XX)
10/* This code should be checked whether it runs correctly on platforms */
11#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
12extern uint32_t __ram0_end__;
13
14void bootloader_jump(void) {
15 *((unsigned long *)(SYMVAL(__ram0_end__) - 4)) = 0xDEADBEEF; // set magic flag => reset handler will jump into boot loader
16 NVIC_SystemReset();
17}
18
19#else /* defined(STM32F0XX) */
20#error Check that the bootloader code works on your platform and add it to bootloader.c!
21#endif /* defined(STM32F0XX) */
22
23#elif defined(KL2x) || defined(K20x) /* STM32_BOOTLOADER_ADDRESS */
24/* Kinetis */
25
26#if defined(KIIBOHD_BOOTLOADER)
27/* Kiibohd Bootloader (MCHCK and Infinity KB) */
28#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
29const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
30void bootloader_jump(void) {
31 __builtin_memcpy((void *)VBAT, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
32 // request reset
33 SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
34}
35
36#else /* defined(KIIBOHD_BOOTLOADER) */
37/* Default for Kinetis - expecting an ARM Teensy */
38void bootloader_jump(void) {
39 chThdSleepMilliseconds(100);
40 __BKPT(0);
41}
42#endif /* defined(KIIBOHD_BOOTLOADER) */
43
44#else /* neither STM32 nor KINETIS */
45__attribute__((weak))
46void bootloader_jump(void) {}
47#endif \ No newline at end of file
diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom.c
new file mode 100644
index 000000000..5ff8ee86f
--- /dev/null
+++ b/tmk_core/common/chibios/eeprom.c
@@ -0,0 +1,588 @@
1#include "ch.h"
2#include "hal.h"
3
4#include "eeconfig.h"
5
6/*************************************/
7/* Hardware backend */
8/* */
9/* Code from PJRC/Teensyduino */
10/*************************************/
11
12/* Teensyduino Core Library
13 * http://www.pjrc.com/teensy/
14 * Copyright (c) 2013 PJRC.COM, LLC.
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
23 *
24 * 1. The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
26 *
27 * 2. If the Software is incorporated into a build system that allows
28 * selection among a list of target devices, then similar target
29 * devices manufactured by PJRC.COM must be included in the list of
30 * target devices and selectable in the same manner.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
36 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
37 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 * SOFTWARE.
40 */
41
42
43#if defined(K20x) /* chip selection */
44/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
45
46// The EEPROM is really RAM with a hardware-based backup system to
47// flash memory. Selecting a smaller size EEPROM allows more wear
48// leveling, for higher write endurance. If you edit this file,
49// set this to the smallest size your application can use. Also,
50// due to Freescale's implementation, writing 16 or 32 bit words
51// (aligned to 2 or 4 byte boundaries) has twice the endurance
52// compared to writing 8 bit bytes.
53//
54#define EEPROM_SIZE 32
55
56// Writing unaligned 16 or 32 bit data is handled automatically when
57// this is defined, but at a cost of extra code size. Without this,
58// any unaligned write will cause a hard fault exception! If you're
59// absolutely sure all 16 and 32 bit writes will be aligned, you can
60// remove the extra unnecessary code.
61//
62#define HANDLE_UNALIGNED_WRITES
63
64// Minimum EEPROM Endurance
65// ------------------------
66#if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
67 #define EEESIZE 0x33
68#elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
69 #define EEESIZE 0x34
70#elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
71 #define EEESIZE 0x35
72#elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
73 #define EEESIZE 0x36
74#elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
75 #define EEESIZE 0x37
76#elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
77 #define EEESIZE 0x38
78#elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
79 #define EEESIZE 0x39
80#endif
81
82void eeprom_initialize(void)
83{
84 uint32_t count=0;
85 uint16_t do_flash_cmd[] = {
86 0xf06f, 0x037f, 0x7003, 0x7803,
87 0xf013, 0x0f80, 0xd0fb, 0x4770};
88 uint8_t status;
89
90 if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
91 // FlexRAM is configured as traditional RAM
92 // We need to reconfigure for EEPROM usage
93 FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
94 FTFL->FCCOB4 = EEESIZE; // EEPROM Size
95 FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
96 __disable_irq();
97 // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
98 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
99 __enable_irq();
100 status = FTFL->FSTAT;
101 if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
102 FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
103 return; // error
104 }
105 }
106 // wait for eeprom to become ready (is this really necessary?)
107 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
108 if (++count > 20000) break;
109 }
110}
111
112#define FlexRAM ((uint8_t *)0x14000000)
113
114uint8_t eeprom_read_byte(const uint8_t *addr)
115{
116 uint32_t offset = (uint32_t)addr;
117 if (offset >= EEPROM_SIZE) return 0;
118 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
119 return FlexRAM[offset];
120}
121
122uint16_t eeprom_read_word(const uint16_t *addr)
123{
124 uint32_t offset = (uint32_t)addr;
125 if (offset >= EEPROM_SIZE-1) return 0;
126 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
127 return *(uint16_t *)(&FlexRAM[offset]);
128}
129
130uint32_t eeprom_read_dword(const uint32_t *addr)
131{
132 uint32_t offset = (uint32_t)addr;
133 if (offset >= EEPROM_SIZE-3) return 0;
134 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
135 return *(uint32_t *)(&FlexRAM[offset]);
136}
137
138void eeprom_read_block(void *buf, const void *addr, uint32_t len)
139{
140 uint32_t offset = (uint32_t)addr;
141 uint8_t *dest = (uint8_t *)buf;
142 uint32_t end = offset + len;
143
144 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
145 if (end > EEPROM_SIZE) end = EEPROM_SIZE;
146 while (offset < end) {
147 *dest++ = FlexRAM[offset++];
148 }
149}
150
151int eeprom_is_ready(void)
152{
153 return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
154}
155
156static void flexram_wait(void)
157{
158 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
159 // TODO: timeout
160 }
161}
162
163void eeprom_write_byte(uint8_t *addr, uint8_t value)
164{
165 uint32_t offset = (uint32_t)addr;
166
167 if (offset >= EEPROM_SIZE) return;
168 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
169 if (FlexRAM[offset] != value) {
170 FlexRAM[offset] = value;
171 flexram_wait();
172 }
173}
174
175void eeprom_write_word(uint16_t *addr, uint16_t value)
176{
177 uint32_t offset = (uint32_t)addr;
178
179 if (offset >= EEPROM_SIZE-1) return;
180 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
181#ifdef HANDLE_UNALIGNED_WRITES
182 if ((offset & 1) == 0) {
183#endif
184 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
185 *(uint16_t *)(&FlexRAM[offset]) = value;
186 flexram_wait();
187 }
188#ifdef HANDLE_UNALIGNED_WRITES
189 } else {
190 if (FlexRAM[offset] != value) {
191 FlexRAM[offset] = value;
192 flexram_wait();
193 }
194 if (FlexRAM[offset + 1] != (value >> 8)) {
195 FlexRAM[offset + 1] = value >> 8;
196 flexram_wait();
197 }
198 }
199#endif
200}
201
202void eeprom_write_dword(uint32_t *addr, uint32_t value)
203{
204 uint32_t offset = (uint32_t)addr;
205
206 if (offset >= EEPROM_SIZE-3) return;
207 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
208#ifdef HANDLE_UNALIGNED_WRITES
209 switch (offset & 3) {
210 case 0:
211#endif
212 if (*(uint32_t *)(&FlexRAM[offset]) != value) {
213 *(uint32_t *)(&FlexRAM[offset]) = value;
214 flexram_wait();
215 }
216 return;
217#ifdef HANDLE_UNALIGNED_WRITES
218 case 2:
219 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
220 *(uint16_t *)(&FlexRAM[offset]) = value;
221 flexram_wait();
222 }
223 if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
224 *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
225 flexram_wait();
226 }
227 return;
228 default:
229 if (FlexRAM[offset] != value) {
230 FlexRAM[offset] = value;
231 flexram_wait();
232 }
233 if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
234 *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
235 flexram_wait();
236 }
237 if (FlexRAM[offset + 3] != (value >> 24)) {
238 FlexRAM[offset + 3] = value >> 24;
239 flexram_wait();
240 }
241 }
242#endif
243}
244
245void eeprom_write_block(const void *buf, void *addr, uint32_t len)
246{
247 uint32_t offset = (uint32_t)addr;
248 const uint8_t *src = (const uint8_t *)buf;
249
250 if (offset >= EEPROM_SIZE) return;
251 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
252 if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
253 if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
254 while (len > 0) {
255 uint32_t lsb = offset & 3;
256 if (lsb == 0 && len >= 4) {
257 // write aligned 32 bits
258 uint32_t val32;
259 val32 = *src++;
260 val32 |= (*src++ << 8);
261 val32 |= (*src++ << 16);
262 val32 |= (*src++ << 24);
263 if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
264 *(uint32_t *)(&FlexRAM[offset]) = val32;
265 flexram_wait();
266 }
267 offset += 4;
268 len -= 4;
269 } else if ((lsb == 0 || lsb == 2) && len >= 2) {
270 // write aligned 16 bits
271 uint16_t val16;
272 val16 = *src++;
273 val16 |= (*src++ << 8);
274 if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
275 *(uint16_t *)(&FlexRAM[offset]) = val16;
276 flexram_wait();
277 }
278 offset += 2;
279 len -= 2;
280 } else {
281 // write 8 bits
282 uint8_t val8 = *src++;
283 if (FlexRAM[offset] != val8) {
284 FlexRAM[offset] = val8;
285 flexram_wait();
286 }
287 offset++;
288 len--;
289 }
290 }
291}
292
293/*
294void do_flash_cmd(volatile uint8_t *fstat)
295{
296 *fstat = 0x80;
297 while ((*fstat & 0x80) == 0) ; // wait
298}
29900000000 <do_flash_cmd>:
300 0: f06f 037f mvn.w r3, #127 ; 0x7f
301 4: 7003 strb r3, [r0, #0]
302 6: 7803 ldrb r3, [r0, #0]
303 8: f013 0f80 tst.w r3, #128 ; 0x80
304 c: d0fb beq.n 6 <do_flash_cmd+0x6>
305 e: 4770 bx lr
306*/
307
308#elif defined(KL2x) /* chip selection */
309/* Teensy LC (emulated) */
310
311#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
312
313extern uint32_t __eeprom_workarea_start__;
314extern uint32_t __eeprom_workarea_end__;
315
316#define EEPROM_SIZE 128
317
318static uint32_t flashend = 0;
319
320void eeprom_initialize(void)
321{
322 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
323
324 do {
325 if (*p++ == 0xFFFF) {
326 flashend = (uint32_t)(p - 2);
327 return;
328 }
329 } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
330 flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
331}
332
333uint8_t eeprom_read_byte(const uint8_t *addr)
334{
335 uint32_t offset = (uint32_t)addr;
336 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
337 const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
338 uint16_t val;
339 uint8_t data=0xFF;
340
341 if (!end) {
342 eeprom_initialize();
343 end = (const uint16_t *)((uint32_t)flashend);
344 }
345 if (offset < EEPROM_SIZE) {
346 while (p <= end) {
347 val = *p++;
348 if ((val & 255) == offset) data = val >> 8;
349 }
350 }
351 return data;
352}
353
354static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
355{
356 // with great power comes great responsibility....
357 uint32_t stat;
358 *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
359 *(uint32_t *)&(FTFA->FCCOB7) = data;
360 __disable_irq();
361 (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
362 __enable_irq();
363 stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
364 if (stat) {
365 FTFA->FSTAT = stat;
366 }
367 MCM->PLACR |= MCM_PLACR_CFCC;
368}
369
370void eeprom_write_byte(uint8_t *addr, uint8_t data)
371{
372 uint32_t offset = (uint32_t)addr;
373 const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
374 uint32_t i, val, flashaddr;
375 uint16_t do_flash_cmd[] = {
376 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
377 uint8_t buf[EEPROM_SIZE];
378
379 if (offset >= EEPROM_SIZE) return;
380 if (!end) {
381 eeprom_initialize();
382 end = (const uint16_t *)((uint32_t)flashend);
383 }
384 if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
385 val = (data << 8) | offset;
386 flashaddr = (uint32_t)end;
387 flashend = flashaddr;
388 if ((flashaddr & 2) == 0) {
389 val |= 0xFFFF0000;
390 } else {
391 val <<= 16;
392 val |= 0x0000FFFF;
393 }
394 flash_write(do_flash_cmd, flashaddr, val);
395 } else {
396 for (i=0; i < EEPROM_SIZE; i++) {
397 buf[i] = 0xFF;
398 }
399 val = 0;
400 for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
401 val = *p;
402 if ((val & 255) < EEPROM_SIZE) {
403 buf[val & 255] = val >> 8;
404 }
405 }
406 buf[offset] = data;
407 for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
408 *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
409 __disable_irq();
410 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
411 __enable_irq();
412 val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
413 if (val) FTFA->FSTAT = val;
414 MCM->PLACR |= MCM_PLACR_CFCC;
415 }
416 flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
417 for (i=0; i < EEPROM_SIZE; i++) {
418 if (buf[i] == 0xFF) continue;
419 if ((flashaddr & 2) == 0) {
420 val = (buf[i] << 8) | i;
421 } else {
422 val = val | (buf[i] << 24) | (i << 16);
423 flash_write(do_flash_cmd, flashaddr, val);
424 }
425 flashaddr += 2;
426 }
427 flashend = flashaddr;
428 if ((flashaddr & 2)) {
429 val |= 0xFFFF0000;
430 flash_write(do_flash_cmd, flashaddr, val);
431 }
432 }
433}
434
435/*
436void do_flash_cmd(volatile uint8_t *fstat)
437{
438 *fstat = 0x80;
439 while ((*fstat & 0x80) == 0) ; // wait
440}
44100000000 <do_flash_cmd>:
442 0: 2380 movs r3, #128 ; 0x80
443 2: 7003 strb r3, [r0, #0]
444 4: 7803 ldrb r3, [r0, #0]
445 6: b25b sxtb r3, r3
446 8: 2b00 cmp r3, #0
447 a: dafb bge.n 4 <do_flash_cmd+0x4>
448 c: 4770 bx lr
449*/
450
451
452uint16_t eeprom_read_word(const uint16_t *addr)
453{
454 const uint8_t *p = (const uint8_t *)addr;
455 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
456}
457
458uint32_t eeprom_read_dword(const uint32_t *addr)
459{
460 const uint8_t *p = (const uint8_t *)addr;
461 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
462 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
463}
464
465void eeprom_read_block(void *buf, const void *addr, uint32_t len)
466{
467 const uint8_t *p = (const uint8_t *)addr;
468 uint8_t *dest = (uint8_t *)buf;
469 while (len--) {
470 *dest++ = eeprom_read_byte(p++);
471 }
472}
473
474int eeprom_is_ready(void)
475{
476 return 1;
477}
478
479void eeprom_write_word(uint16_t *addr, uint16_t value)
480{
481 uint8_t *p = (uint8_t *)addr;
482 eeprom_write_byte(p++, value);
483 eeprom_write_byte(p, value >> 8);
484}
485
486void eeprom_write_dword(uint32_t *addr, uint32_t value)
487{
488 uint8_t *p = (uint8_t *)addr;
489 eeprom_write_byte(p++, value);
490 eeprom_write_byte(p++, value >> 8);
491 eeprom_write_byte(p++, value >> 16);
492 eeprom_write_byte(p, value >> 24);
493}
494
495void eeprom_write_block(const void *buf, void *addr, uint32_t len)
496{
497 uint8_t *p = (uint8_t *)addr;
498 const uint8_t *src = (const uint8_t *)buf;
499 while (len--) {
500 eeprom_write_byte(p++, *src++);
501 }
502}
503
504#else
505// No EEPROM supported, so emulate it
506
507#define EEPROM_SIZE 32
508static uint8_t buffer[EEPROM_SIZE];
509
510uint8_t eeprom_read_byte(const uint8_t *addr) {
511 uint32_t offset = (uint32_t)addr;
512 return buffer[offset];
513}
514
515void eeprom_write_byte(uint8_t *addr, uint8_t value) {
516 uint32_t offset = (uint32_t)addr;
517 buffer[offset] = value;
518}
519
520uint16_t eeprom_read_word(const uint16_t *addr) {
521 const uint8_t *p = (const uint8_t *)addr;
522 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
523}
524
525uint32_t eeprom_read_dword(const uint32_t *addr) {
526 const uint8_t *p = (const uint8_t *)addr;
527 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
528 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
529}
530
531void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
532 const uint8_t *p = (const uint8_t *)addr;
533 uint8_t *dest = (uint8_t *)buf;
534 while (len--) {
535 *dest++ = eeprom_read_byte(p++);
536 }
537}
538
539void eeprom_write_word(uint16_t *addr, uint16_t value) {
540 uint8_t *p = (uint8_t *)addr;
541 eeprom_write_byte(p++, value);
542 eeprom_write_byte(p, value >> 8);
543}
544
545void eeprom_write_dword(uint32_t *addr, uint32_t value) {
546 uint8_t *p = (uint8_t *)addr;
547 eeprom_write_byte(p++, value);
548 eeprom_write_byte(p++, value >> 8);
549 eeprom_write_byte(p++, value >> 16);
550 eeprom_write_byte(p, value >> 24);
551}
552
553void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
554 uint8_t *p = (uint8_t *)addr;
555 const uint8_t *src = (const uint8_t *)buf;
556 while (len--) {
557 eeprom_write_byte(p++, *src++);
558 }
559}
560
561#endif /* chip selection */
562// The update functions just calls write for now, but could probably be optimized
563
564void eeprom_update_byte(uint8_t *addr, uint8_t value) {
565 eeprom_write_byte(addr, value);
566}
567
568void eeprom_update_word(uint16_t *addr, uint16_t value) {
569 uint8_t *p = (uint8_t *)addr;
570 eeprom_write_byte(p++, value);
571 eeprom_write_byte(p, value >> 8);
572}
573
574void eeprom_update_dword(uint32_t *addr, uint32_t value) {
575 uint8_t *p = (uint8_t *)addr;
576 eeprom_write_byte(p++, value);
577 eeprom_write_byte(p++, value >> 8);
578 eeprom_write_byte(p++, value >> 16);
579 eeprom_write_byte(p, value >> 24);
580}
581
582void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
583 uint8_t *p = (uint8_t *)addr;
584 const uint8_t *src = (const uint8_t *)buf;
585 while (len--) {
586 eeprom_write_byte(p++, *src++);
587 }
588}
diff --git a/tmk_core/common/chibios/printf.c b/tmk_core/common/chibios/printf.c
new file mode 100644
index 000000000..72e3d4f8c
--- /dev/null
+++ b/tmk_core/common/chibios/printf.c
@@ -0,0 +1,240 @@
1/*
2 * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
3 * and: http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
4 */
5
6/*
7File: printf.c
8
9Copyright (C) 2004 Kustaa Nyholm
10
11This library is free software; you can redistribute it and/or
12modify it under the terms of the GNU Lesser General Public
13License as published by the Free Software Foundation; either
14version 2.1 of the License, or (at your option) any later version.
15
16This library is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public
22License along with this library; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25*/
26
27#include "printf.h"
28
29typedef void (*putcf) (void*,char);
30static putcf stdout_putf;
31static void* stdout_putp;
32
33// this adds cca 400 bytes
34#define PRINTF_LONG_SUPPORT
35
36#ifdef PRINTF_LONG_SUPPORT
37
38static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
39 {
40 int n=0;
41 unsigned int d=1;
42 while (num/d >= base)
43 d*=base;
44 while (d!=0) {
45 int dgt = num / d;
46 num%=d;
47 d/=base;
48 if (n || dgt>0|| d==0) {
49 *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
50 ++n;
51 }
52 }
53 *bf=0;
54 }
55
56static void li2a (long num, char * bf)
57 {
58 if (num<0) {
59 num=-num;
60 *bf++ = '-';
61 }
62 uli2a(num,10,0,bf);
63 }
64
65#endif
66
67static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
68 {
69 int n=0;
70 unsigned int d=1;
71 while (num/d >= base)
72 d*=base;
73 while (d!=0) {
74 int dgt = num / d;
75 num%= d;
76 d/=base;
77 if (n || dgt>0 || d==0) {
78 *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
79 ++n;
80 }
81 }
82 *bf=0;
83 }
84
85static void i2a (int num, char * bf)
86 {
87 if (num<0) {
88 num=-num;
89 *bf++ = '-';
90 }
91 ui2a(num,10,0,bf);
92 }
93
94static int a2d(char ch)
95 {
96 if (ch>='0' && ch<='9')
97 return ch-'0';
98 else if (ch>='a' && ch<='f')
99 return ch-'a'+10;
100 else if (ch>='A' && ch<='F')
101 return ch-'A'+10;
102 else return -1;
103 }
104
105static char a2i(char ch, char** src,int base,int* nump)
106 {
107 char* p= *src;
108 int num=0;
109 int digit;
110 while ((digit=a2d(ch))>=0) {
111 if (digit>base) break;
112 num=num*base+digit;
113 ch=*p++;
114 }
115 *src=p;
116 *nump=num;
117 return ch;
118 }
119
120static void putchw(void* putp,putcf putf,int n, char z, char* bf)
121 {
122 char fc=z? '0' : ' ';
123 char ch;
124 char* p=bf;
125 while (*p++ && n > 0)
126 n--;
127 while (n-- > 0)
128 putf(putp,fc);
129 while ((ch= *bf++))
130 putf(putp,ch);
131 }
132
133void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
134 {
135 char bf[12];
136
137 char ch;
138
139
140 while ((ch=*(fmt++))) {
141 if (ch!='%')
142 putf(putp,ch);
143 else {
144 char lz=0;
145#ifdef PRINTF_LONG_SUPPORT
146 char lng=0;
147#endif
148 int w=0;
149 ch=*(fmt++);
150 if (ch=='0') {
151 ch=*(fmt++);
152 lz=1;
153 }
154 if (ch>='0' && ch<='9') {
155 ch=a2i(ch,&fmt,10,&w);
156 }
157#ifdef PRINTF_LONG_SUPPORT
158 if (ch=='l') {
159 ch=*(fmt++);
160 lng=1;
161 }
162#endif
163 switch (ch) {
164 case 0:
165 goto abort;
166 case 'u' : {
167#ifdef PRINTF_LONG_SUPPORT
168 if (lng)
169 uli2a(va_arg(va, unsigned long int),10,0,bf);
170 else
171#endif
172 ui2a(va_arg(va, unsigned int),10,0,bf);
173 putchw(putp,putf,w,lz,bf);
174 break;
175 }
176 case 'd' : {
177#ifdef PRINTF_LONG_SUPPORT
178 if (lng)
179 li2a(va_arg(va, unsigned long int),bf);
180 else
181#endif
182 i2a(va_arg(va, int),bf);
183 putchw(putp,putf,w,lz,bf);
184 break;
185 }
186 case 'x': case 'X' :
187#ifdef PRINTF_LONG_SUPPORT
188 if (lng)
189 uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
190 else
191#endif
192 ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
193 putchw(putp,putf,w,lz,bf);
194 break;
195 case 'c' :
196 putf(putp,(char)(va_arg(va, int)));
197 break;
198 case 's' :
199 putchw(putp,putf,w,0,va_arg(va, char*));
200 break;
201 case '%' :
202 putf(putp,ch);
203 default:
204 break;
205 }
206 }
207 }
208 abort:;
209 }
210
211
212void init_printf(void* putp,void (*putf) (void*,char))
213 {
214 stdout_putf=putf;
215 stdout_putp=putp;
216 }
217
218void tfp_printf(char *fmt, ...)
219 {
220 va_list va;
221 va_start(va,fmt);
222 tfp_format(stdout_putp,stdout_putf,fmt,va);
223 va_end(va);
224 }
225
226static void putcp(void* p,char c)
227 {
228 *(*((char**)p))++ = c;
229 }
230
231
232
233void tfp_sprintf(char* s,char *fmt, ...)
234 {
235 va_list va;
236 va_start(va,fmt);
237 tfp_format(&s,putcp,fmt,va);
238 putcp(&s,0);
239 va_end(va);
240 }
diff --git a/tmk_core/common/chibios/printf.h b/tmk_core/common/chibios/printf.h
new file mode 100644
index 000000000..678a100c6
--- /dev/null
+++ b/tmk_core/common/chibios/printf.h
@@ -0,0 +1,111 @@
1/*
2 * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
3 * and: http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
4 */
5
6/*
7File: printf.h
8
9Copyright (C) 2004 Kustaa Nyholm
10
11This library is free software; you can redistribute it and/or
12modify it under the terms of the GNU Lesser General Public
13License as published by the Free Software Foundation; either
14version 2.1 of the License, or (at your option) any later version.
15
16This library is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19See the GNU Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public
22License along with this library; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25This library is realy just two files: 'printf.h' and 'printf.c'.
26
27They provide a simple and small (+200 loc) printf functionality to
28be used in embedded systems.
29
30I've found them so usefull in debugging that I do not bother with a
31debugger at all.
32
33They are distributed in source form, so to use them, just compile them
34into your project.
35
36Two printf variants are provided: printf and sprintf.
37
38The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
39
40Zero padding and field width are also supported.
41
42If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
43long specifier is also
44supported. Note that this will pull in some long math routines (pun intended!)
45and thus make your executable noticably longer.
46
47The memory foot print of course depends on the target cpu, compiler and
48compiler options, but a rough guestimate (based on a H8S target) is about
491.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
50Not too bad. Your milage may vary. By hacking the source code you can
51get rid of some hunred bytes, I'm sure, but personally I feel the balance of
52functionality and flexibility versus code size is close to optimal for
53many embedded systems.
54
55To use the printf you need to supply your own character output function,
56something like :
57
58 void putc ( void* p, char c)
59 {
60 while (!SERIAL_PORT_EMPTY) ;
61 SERIAL_PORT_TX_REGISTER = c;
62 }
63
64Before you can call printf you need to initialize it to use your
65character output function with something like:
66
67 init_printf(NULL,putc);
68
69Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
70the NULL (or any pointer) you pass into the 'init_printf' will eventually be
71passed to your 'putc' routine. This allows you to pass some storage space (or
72anything realy) to the character output function, if necessary.
73This is not often needed but it was implemented like that because it made
74implementing the sprintf function so neat (look at the source code).
75
76The code is re-entrant, except for the 'init_printf' function, so it
77is safe to call it from interupts too, although this may result in mixed output.
78If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
79
80The printf and sprintf functions are actually macros that translate to
81'tfp_printf' and 'tfp_sprintf'. This makes it possible
82to use them along with 'stdio.h' printf's in a single source file.
83You just need to undef the names before you include the 'stdio.h'.
84Note that these are not function like macros, so if you have variables
85or struct members with these names, things will explode in your face.
86Without variadic macros this is the best we can do to wrap these
87fucnction. If it is a problem just give up the macros and use the
88functions directly or rename them.
89
90For further details see source code.
91
92regs Kusti, 23.10.2004
93*/
94
95
96#ifndef __TFP_PRINTF__
97#define __TFP_PRINTF__
98
99#include <stdarg.h>
100
101void init_printf(void* putp,void (*putf) (void*,char));
102
103void tfp_printf(char *fmt, ...);
104void tfp_sprintf(char* s,char *fmt, ...);
105
106void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
107
108#define printf tfp_printf
109#define sprintf tfp_sprintf
110
111#endif
diff --git a/tmk_core/common/chibios/sleep_led.c b/tmk_core/common/chibios/sleep_led.c
new file mode 100644
index 000000000..4c35cfcba
--- /dev/null
+++ b/tmk_core/common/chibios/sleep_led.c
@@ -0,0 +1,226 @@
1#include "ch.h"
2#include "hal.h"
3
4#include "led.h"
5#include "sleep_led.h"
6
7/* All right, we go the "software" way: timer, toggle LED in interrupt.
8 * Based on hasu's code for AVRs.
9 * Use LP timer on Kinetises, TIM14 on STM32F0.
10 */
11
12#if defined(KL2x) || defined(K20x)
13
14/* Use Low Power Timer (LPTMR) */
15#define TIMER_INTERRUPT_VECTOR KINETIS_LPTMR0_IRQ_VECTOR
16#define RESET_COUNTER LPTMR0->CSR |= LPTMRx_CSR_TCF
17
18#elif defined(STM32F0XX)
19
20/* Use TIM14 manually */
21#define TIMER_INTERRUPT_VECTOR STM32_TIM14_HANDLER
22#define RESET_COUNTER STM32_TIM14->SR &= ~STM32_TIM_SR_UIF
23
24#endif
25
26#if defined(KL2x) || defined(K20x) || defined(STM32F0XX) /* common parts for timers/interrupts */
27
28/* Breathing Sleep LED brighness(PWM On period) table
29 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
30 *
31 * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
32 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
33 */
34static const uint8_t breathing_table[64] = {
350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
3615, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
37255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
3815, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
39};
40
41/* interrupt handler */
42OSAL_IRQ_HANDLER(TIMER_INTERRUPT_VECTOR) {
43 OSAL_IRQ_PROLOGUE();
44
45 /* Software PWM
46 * timer:1111 1111 1111 1111
47 * \_____/\/ \_______/____ count(0-255)
48 * \ \______________ duration of step(4)
49 * \__________________ index of step table(0-63)
50 */
51
52 // this works for cca 65536 irqs/sec
53 static union {
54 uint16_t row;
55 struct {
56 uint8_t count:8;
57 uint8_t duration:2;
58 uint8_t index:6;
59 } pwm;
60 } timer = { .row = 0 };
61
62 timer.row++;
63
64 // LED on
65 if (timer.pwm.count == 0) {
66 led_set(1<<USB_LED_CAPS_LOCK);
67 }
68 // LED off
69 if (timer.pwm.count == breathing_table[timer.pwm.index]) {
70 led_set(0);
71 }
72
73 /* Reset the counter */
74 RESET_COUNTER;
75
76 OSAL_IRQ_EPILOGUE();
77}
78
79#endif /* common parts for known platforms */
80
81
82#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
83
84/* LPTMR clock options */
85#define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
86#define LPTMR_CLOCK_LPO 1 /* 1kHz clock */
87#define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
88#define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
89
90/* Work around inconsistencies in Freescale naming */
91#if !defined(SIM_SCGC5_LPTMR)
92#define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
93#endif
94
95/* Initialise the timer */
96void sleep_led_init(void) {
97 /* Make sure the clock to the LPTMR is enabled */
98 SIM->SCGC5 |= SIM_SCGC5_LPTMR;
99 /* Reset LPTMR settings */
100 LPTMR0->CSR = 0;
101 /* Set the compare value */
102 LPTMR0->CMR = 0; // trigger on counter value (i.e. every time)
103
104 /* Set up clock source and prescaler */
105 /* Software PWM
106 * ______ ______ __
107 * | ON |___OFF___| ON |___OFF___| ....
108 * |<-------------->|<-------------->|<- ....
109 * PWM period PWM period
110 *
111 * R interrupts/period[resolution]
112 * F periods/second[frequency]
113 * R * F interrupts/second
114 */
115
116 /* === OPTION 1 === */
117 #if 0
118 // 1kHz LPO
119 // No prescaler => 1024 irqs/sec
120 // Note: this is too slow for a smooth breathe
121 LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
122 #endif /* OPTION 1 */
123
124 /* === OPTION 2 === */
125 #if 1
126 // nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
127 MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
128 #if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
129 MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
130 #endif /* KL27 */
131 MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
132 // to work in stop mode, also MCG_C1_IREFSTEN
133 // Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
134 // => approx F=61, R=256, duration = 4
135 LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(6);
136 #endif /* OPTION 2 */
137
138 /* === OPTION 3 === */
139 #if 0
140 // OSC output (external crystal), usually 8MHz or 16MHz
141 OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
142 // to work in stop mode, also OSC_CR_EREFSTEN
143 // Divide by 2^N
144 LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
145 #endif /* OPTION 3 */
146 /* === END OPTIONS === */
147
148 /* Interrupt on TCF set (compare flag) */
149 nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
150 LPTMR0->CSR |= LPTMRx_CSR_TIE;
151}
152
153void sleep_led_enable(void) {
154 /* Enable the timer */
155 LPTMR0->CSR |= LPTMRx_CSR_TEN;
156}
157
158void sleep_led_disable(void) {
159 /* Disable the timer */
160 LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
161}
162
163void sleep_led_toggle(void) {
164 /* Toggle the timer */
165 LPTMR0->CSR ^= LPTMRx_CSR_TEN;
166}
167
168#elif defined(STM32F0XX) /* platform selection: STM32F0XX */
169
170/* Initialise the timer */
171void sleep_led_init(void) {
172 /* enable clock */
173 rccEnableTIM14(FALSE); /* low power enable = FALSE */
174 rccResetTIM14();
175
176 /* prescale */
177 /* Assuming 48MHz internal clock */
178 /* getting cca 65484 irqs/sec */
179 STM32_TIM14->PSC = 733;
180
181 /* auto-reload */
182 /* 0 => interrupt every time */
183 STM32_TIM14->ARR = 3;
184
185 /* enable counter update event interrupt */
186 STM32_TIM14->DIER |= STM32_TIM_DIER_UIE;
187
188 /* register interrupt vector */
189 nvicEnableVector(STM32_TIM14_NUMBER, 2); /* vector, priority */
190}
191
192void sleep_led_enable(void) {
193 /* Enable the timer */
194 STM32_TIM14->CR1 = STM32_TIM_CR1_CEN | STM32_TIM_CR1_URS;
195 /* URS => update event only on overflow; setting UG bit disabled */
196}
197
198void sleep_led_disable(void) {
199 /* Disable the timer */
200 STM32_TIM14->CR1 = 0;
201}
202
203void sleep_led_toggle(void) {
204 /* Toggle the timer */
205 STM32_TIM14->CR1 ^= STM32_TIM_CR1_CEN;
206}
207
208
209#else /* platform selection: not on familiar chips */
210
211void sleep_led_init(void) {
212}
213
214void sleep_led_enable(void) {
215 led_set(1<<USB_LED_CAPS_LOCK);
216}
217
218void sleep_led_disable(void) {
219 led_set(0);
220}
221
222void sleep_led_toggle(void) {
223 // not implemented
224}
225
226#endif /* platform selection */ \ No newline at end of file
diff --git a/tmk_core/common/chibios/suspend.c b/tmk_core/common/chibios/suspend.c
new file mode 100644
index 000000000..6ca16034f
--- /dev/null
+++ b/tmk_core/common/chibios/suspend.c
@@ -0,0 +1,65 @@
1/* TODO */
2
3#include "ch.h"
4#include "hal.h"
5
6#include "matrix.h"
7#include "action.h"
8#include "action_util.h"
9#include "mousekey.h"
10#include "host.h"
11#include "backlight.h"
12#include "suspend.h"
13
14void suspend_idle(uint8_t time) {
15 // TODO: this is not used anywhere - what units is 'time' in?
16 chThdSleepMilliseconds(time);
17}
18
19void suspend_power_down(void) {
20 // TODO: figure out what to power down and how
21 // shouldn't power down TPM/FTM if we want a breathing LED
22 // also shouldn't power down USB
23
24 // on AVR, this enables the watchdog for 15ms (max), and goes to
25 // SLEEP_MODE_PWR_DOWN
26
27 chThdSleepMilliseconds(17);
28}
29
30__attribute__ ((weak)) void matrix_power_up(void) {}
31__attribute__ ((weak)) void matrix_power_down(void) {}
32bool suspend_wakeup_condition(void)
33{
34 matrix_power_up();
35 matrix_scan();
36 matrix_power_down();
37 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
38 if (matrix_get_row(r)) return true;
39 }
40 return false;
41}
42
43// run immediately after wakeup
44void suspend_wakeup_init(void)
45{
46 // clear keyboard state
47 // need to do it manually, because we're running from ISR
48 // and clear_keyboard() calls print
49 // so only clear the variables in memory
50 // the reports will be sent from main.c afterwards
51 // or if the PC asks for GET_REPORT
52 clear_mods();
53 clear_weak_mods();
54 clear_keys();
55#ifdef MOUSEKEY_ENABLE
56 mousekey_clear();
57#endif /* MOUSEKEY_ENABLE */
58#ifdef EXTRAKEY_ENABLE
59 host_system_send(0);
60 host_consumer_send(0);
61#endif /* EXTRAKEY_ENABLE */
62#ifdef BACKLIGHT_ENABLE
63 backlight_init();
64#endif /* BACKLIGHT_ENABLE */
65}
diff --git a/tmk_core/common/chibios/timer.c b/tmk_core/common/chibios/timer.c
new file mode 100644
index 000000000..3de4cc368
--- /dev/null
+++ b/tmk_core/common/chibios/timer.c
@@ -0,0 +1,27 @@
1#include "ch.h"
2
3#include "timer.h"
4
5void timer_init(void) {}
6
7void timer_clear(void) {}
8
9uint16_t timer_read(void)
10{
11 return (uint16_t)ST2MS(chVTGetSystemTime());
12}
13
14uint32_t timer_read32(void)
15{
16 return ST2MS(chVTGetSystemTime());
17}
18
19uint16_t timer_elapsed(uint16_t last)
20{
21 return (uint16_t)(ST2MS(chVTTimeElapsedSinceX(MS2ST(last))));
22}
23
24uint32_t timer_elapsed32(uint32_t last)
25{
26 return ST2MS(chVTTimeElapsedSinceX(MS2ST(last)));
27}
diff --git a/tmk_core/common/command.c b/tmk_core/common/command.c
index 187a2b949..084c9fe15 100644
--- a/tmk_core/common/command.c
+++ b/tmk_core/common/command.c
@@ -16,7 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/ 16*/
17#include <stdint.h> 17#include <stdint.h>
18#include <stdbool.h> 18#include <stdbool.h>
19#include <util/delay.h> 19#include "wait.h"
20#include "keycode.h" 20#include "keycode.h"
21#include "host.h" 21#include "host.h"
22#include "keymap.h" 22#include "keymap.h"
@@ -103,12 +103,14 @@ bool command_proc(uint8_t code)
103bool command_extra(uint8_t code) __attribute__ ((weak)); 103bool command_extra(uint8_t code) __attribute__ ((weak));
104bool command_extra(uint8_t code) 104bool command_extra(uint8_t code)
105{ 105{
106 (void)code;
106 return false; 107 return false;
107} 108}
108 109
109bool command_console_extra(uint8_t code) __attribute__ ((weak)); 110bool command_console_extra(uint8_t code) __attribute__ ((weak));
110bool command_console_extra(uint8_t code) 111bool command_console_extra(uint8_t code)
111{ 112{
113 (void)code;
112 return false; 114 return false;
113} 115}
114 116
@@ -217,8 +219,11 @@ static void print_version(void)
217 " " STR(BOOTLOADER_SIZE) "\n"); 219 " " STR(BOOTLOADER_SIZE) "\n");
218 220
219 print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__) 221 print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
222#if defined(__AVR__)
220 " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__ 223 " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
221 " AVR_ARCH: avr" STR(__AVR_ARCH__) "\n"); 224 " AVR_ARCH: avr" STR(__AVR_ARCH__)
225#endif
226 "\n");
222 227
223 return; 228 return;
224} 229}
@@ -234,7 +239,7 @@ static void print_status(void)
234#ifdef NKRO_ENABLE 239#ifdef NKRO_ENABLE
235 print_val_hex8(keyboard_nkro); 240 print_val_hex8(keyboard_nkro);
236#endif 241#endif
237 print_val_hex32(timer_count); 242 print_val_hex32(timer_read32());
238 243
239#ifdef PROTOCOL_PJRC 244#ifdef PROTOCOL_PJRC
240 print_val_hex8(UDCON); 245 print_val_hex8(UDCON);
@@ -360,7 +365,7 @@ static bool command_common(uint8_t code)
360 stop_all_notes(); 365 stop_all_notes();
361 shutdown_user(); 366 shutdown_user();
362 #else 367 #else
363 _delay_ms(1000); 368 wait_ms(1000);
364 #endif 369 #endif
365 bootloader_jump(); // not return 370 bootloader_jump(); // not return
366 break; 371 break;
@@ -430,10 +435,11 @@ static bool command_common(uint8_t code)
430 case MAGIC_KC(MAGIC_KEY_NKRO): 435 case MAGIC_KC(MAGIC_KEY_NKRO):
431 clear_keyboard(); // clear to prevent stuck keys 436 clear_keyboard(); // clear to prevent stuck keys
432 keyboard_nkro = !keyboard_nkro; 437 keyboard_nkro = !keyboard_nkro;
433 if (keyboard_nkro) 438 if (keyboard_nkro) {
434 print("NKRO: on\n"); 439 print("NKRO: on\n");
435 else 440 } else {
436 print("NKRO: off\n"); 441 print("NKRO: off\n");
442 }
437 break; 443 break;
438#endif 444#endif
439 445
@@ -750,10 +756,11 @@ static bool mousekey_console(uint8_t code)
750 print("?"); 756 print("?");
751 return false; 757 return false;
752 } 758 }
753 if (mousekey_param) 759 if (mousekey_param) {
754 xprintf("M%d> ", mousekey_param); 760 xprintf("M%d> ", mousekey_param);
755 else 761 } else {
756 print("M>" ); 762 print("M>" );
763 }
757 return true; 764 return true;
758} 765}
759#endif 766#endif
diff --git a/tmk_core/common/avr/eeconfig.c b/tmk_core/common/eeconfig.c
index 656938fb3..140d2b85b 100644
--- a/tmk_core/common/avr/eeconfig.c
+++ b/tmk_core/common/eeconfig.c
@@ -1,6 +1,6 @@
1#include <stdint.h> 1#include <stdint.h>
2#include <stdbool.h> 2#include <stdbool.h>
3#include <avr/eeprom.h> 3#include "eeprom.h"
4#include "eeconfig.h" 4#include "eeconfig.h"
5 5
6void eeconfig_init(void) 6void eeconfig_init(void)
diff --git a/tmk_core/common/eeprom.h b/tmk_core/common/eeprom.h
new file mode 100644
index 000000000..2cc2ccee3
--- /dev/null
+++ b/tmk_core/common/eeprom.h
@@ -0,0 +1,22 @@
1#ifndef TMK_CORE_COMMON_EEPROM_H_
2#define TMK_CORE_COMMON_EEPROM_H_
3
4#if defined(__AVR__)
5#include <avr/eeprom.h>
6#else
7uint8_t eeprom_read_byte (const uint8_t *__p);
8uint16_t eeprom_read_word (const uint16_t *__p);
9uint32_t eeprom_read_dword (const uint32_t *__p);
10void eeprom_read_block (void *__dst, const void *__src, uint32_t __n);
11void eeprom_write_byte (uint8_t *__p, uint8_t __value);
12void eeprom_write_word (uint16_t *__p, uint16_t __value);
13void eeprom_write_dword (uint32_t *__p, uint32_t __value);
14void eeprom_write_block (const void *__src, void *__dst, uint32_t __n);
15void eeprom_update_byte (uint8_t *__p, uint8_t __value);
16void eeprom_update_word (uint16_t *__p, uint16_t __value);
17void eeprom_update_dword (uint32_t *__p, uint32_t __value);
18void eeprom_update_block (const void *__src, void *__dst, uint32_t __n);
19#endif
20
21
22#endif /* TMK_CORE_COMMON_EEPROM_H_ */
diff --git a/tmk_core/common/magic.c b/tmk_core/common/magic.c
index f21d1346c..194e4cc02 100644
--- a/tmk_core/common/magic.c
+++ b/tmk_core/common/magic.c
@@ -1,6 +1,8 @@
1#include <stdint.h> 1#include <stdint.h>
2#include <stdbool.h> 2#include <stdbool.h>
3#if defined(__AVR__)
3#include <util/delay.h> 4#include <util/delay.h>
5#endif
4#include "matrix.h" 6#include "matrix.h"
5#include "bootloader.h" 7#include "bootloader.h"
6#include "debug.h" 8#include "debug.h"
@@ -33,4 +35,4 @@ void magic(void)
33 default_layer = eeconfig_read_default_layer(); 35 default_layer = eeconfig_read_default_layer();
34 default_layer_set((uint32_t)default_layer); 36 default_layer_set((uint32_t)default_layer);
35 37
36} \ No newline at end of file 38}
diff --git a/tmk_core/common/print.c b/tmk_core/common/print.c
index ca94e1e5d..00489557f 100644
--- a/tmk_core/common/print.c
+++ b/tmk_core/common/print.c
@@ -38,11 +38,15 @@ void print_set_sendchar(int8_t (*sendchar_func)(uint8_t))
38 xdev_out(sendchar_func); 38 xdev_out(sendchar_func);
39} 39}
40 40
41#elif defined(__arm__) 41#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
42
43// don't need anything extra
44
45#elif defined(__arm__) /* __AVR__ */
42 46
43// TODO 47// TODO
44//void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { } 48//void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { }
45 49
46#endif 50#endif /* __AVR__ */
47 51
48#endif 52#endif
diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h
index 4f3dde65a..0368bcd4a 100644
--- a/tmk_core/common/print.h
+++ b/tmk_core/common/print.h
@@ -47,7 +47,15 @@ extern "C"
47/* function pointer of sendchar to be used by print utility */ 47/* function pointer of sendchar to be used by print utility */
48void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); 48void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
49 49
50#elif defined(__arm__) 50#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
51
52#include "chibios/printf.h"
53
54#define print(s) printf(s)
55#define println(s) printf(s "\r\n")
56#define xprintf printf
57
58#elif defined(__arm__) /* __AVR__ */
51 59
52#include "mbed/xprintf.h" 60#include "mbed/xprintf.h"
53 61
diff --git a/tmk_core/common/progmem.h b/tmk_core/common/progmem.h
index 199b1bedf..5b2765625 100644
--- a/tmk_core/common/progmem.h
+++ b/tmk_core/common/progmem.h
@@ -5,8 +5,8 @@
5# include <avr/pgmspace.h> 5# include <avr/pgmspace.h>
6#elif defined(__arm__) 6#elif defined(__arm__)
7# define PROGMEM 7# define PROGMEM
8# define pgm_read_byte(p) *(p) 8# define pgm_read_byte(p) *((unsigned char*)p)
9# define pgm_read_word(p) *(p) 9# define pgm_read_word(p) *((uint16_t*)p)
10#endif 10#endif
11 11
12#endif 12#endif
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index f6c0a315d..0c799eca3 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -84,6 +84,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
84# define KEYBOARD_REPORT_SIZE NKRO_EPSIZE 84# define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
85# define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) 85# define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
86# define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) 86# define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
87#elif defined(PROTOCOL_CHIBIOS) && defined(NKRO_ENABLE)
88# include "protocol/chibios/usb_main.h"
89# define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
90# define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
91# define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
87 92
88#else 93#else
89# define KEYBOARD_REPORT_SIZE 8 94# define KEYBOARD_REPORT_SIZE 8
diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h
index 40d00b0c7..82727be01 100644
--- a/tmk_core/common/wait.h
+++ b/tmk_core/common/wait.h
@@ -9,9 +9,13 @@ extern "C" {
9# include <util/delay.h> 9# include <util/delay.h>
10# define wait_ms(ms) _delay_ms(ms) 10# define wait_ms(ms) _delay_ms(ms)
11# define wait_us(us) _delay_us(us) 11# define wait_us(us) _delay_us(us)
12#elif defined(__arm__) 12#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
13# include "ch.h"
14# define wait_ms(ms) chThdSleepMilliseconds(ms)
15# define wait_us(us) chThdSleepMicroseconds(us)
16#elif defined(__arm__) /* __AVR__ */
13# include "wait_api.h" 17# include "wait_api.h"
14#endif 18#endif /* __AVR__ */
15 19
16#ifdef __cplusplus 20#ifdef __cplusplus
17} 21}
diff --git a/tmk_core/protocol/chibios.mk b/tmk_core/protocol/chibios.mk
new file mode 100644
index 000000000..3f4e0a71f
--- /dev/null
+++ b/tmk_core/protocol/chibios.mk
@@ -0,0 +1,10 @@
1PROTOCOL_DIR = protocol
2CHIBIOS_DIR = $(PROTOCOL_DIR)/chibios
3
4
5SRC += $(CHIBIOS_DIR)/usb_main.c
6SRC += $(CHIBIOS_DIR)/main.c
7
8VPATH += $(TMK_PATH)/$(PROTOCOL_DIR)
9VPATH += $(TMK_PATH)/$(CHIBIOS_DIR)
10
diff --git a/tmk_core/protocol/chibios/README.md b/tmk_core/protocol/chibios/README.md
new file mode 100644
index 000000000..63e6641f8
--- /dev/null
+++ b/tmk_core/protocol/chibios/README.md
@@ -0,0 +1,55 @@
1## TMK running on top of ChibiOS
2
3This code can be used to run TMK keyboard logic on top of [ChibiOS], meaning that you can run TMK on whatever [ChibiOS] supports. The notable examples are ARM-based Teensies (3.x and LC) and on the boards with STM32 MCUs.
4
5### Usage
6
7- To use, [get a zip of chibios](https://github.com/ChibiOS/ChibiOS/archive/a7df9a891067621e8e1a5c2a2c0ceada82403afe.zip) and unpack/rename it to `tmk_core/tool/chibios/chibios`; or you can just clone [the repo](https://github.com/ChibiOS/ChibiOS) there. For Freescale/NXP Kinetis support (meaning ARM Teensies and the Infinity keyboard), you'll also need [a zip of chibios-contrib](https://github.com/ChibiOS/ChibiOS-Contrib/archive/e1311c4db6cd366cf760673f769e925741ac0ad3.zip), unpacked/renamed to `tmk_core/tool/chibios/chibios-contrib`. Likewise, for git-savvy people, just clone [the repo](https://github.com/ChibiOS/ChibiOS-Contrib) there.
8- Note: the abovementioned directories are the defaults. You can have the two chibios repositories wherever you want, just define their location in `CHIBIOS` and `CHIBIOS_CONTRIB` variables in your `Makefile`.
9- You will also need to install an ARM toolchain, for instance from [here](https://launchpad.net/gcc-arm-embedded). On linux, this is usually also present as a package for your distribution (as `gcc-arm` or something similar). On OS X, you can use [homebrew](http://brew.sh/) with an appropriate tap.
10
11### Notes
12
13- Some comments about ChibiOS syntax and the most commonly used GPIO functions are, as well as an example for ARM Teensies, is [here](https://github.com/tmk/tmk_keyboard/blob/master/keyboard/teensy_lc_onekey/instructions.md).
14- 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.
15- For debugging, it is sometimes useful disable gcc optimisations, you can do that by adding `-O0` to `OPT_DEFS` in your `Makefile`.
16- 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.
17- 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.
18- 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`. An additional startup code is also needed; the best way to deal with this is to define custom board files. (Example forthcoming.) In any case, there are no problems for Teensies.
19
20
21### Immediate todo
22
23- power saving for suspend
24
25### Not tested, but possibly working
26
27- backlight
28
29### Missing / not working (TMK vs ChibiOS bits)
30
31- 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).
32
33### Tried with
34
35- Infinity, WhiteFox keyboards
36- all ARM-based Teensies
37- some STM32-based boards (e.g. ST-F072RB-DISCOVERY board, STM32F042 breakout board, Maple Mini (STM32F103-based))
38
39## ChibiOS-supported MCUs
40
41- Pretty much all STM32 chips.
42- K20x and KL2x Freescale/NXP chips (i.e. Teensy 3.x/LC, mchck, FRDM-KL2{5,6}Z, FRDM-K20D50M), via the [ChibiOS-Contrib](https://github.com/ChibiOS/ChibiOS-Contrib) repository.
43- There is also support for AVR8, but the USB stack is not implemented for them yet (some news on that front recently though), and also the kernel itself takes about 1k of RAM. I think people managed to get ChibiOS running on atmega32[8p/u4] though.
44- There is also support for Nordic NRF51822 (the chip in Adafruit's Bluefruit bluetooth-low-energy boards), but be aware that that chip does *not* have USB, and the BLE softdevice (i.e. Bluetooth) is not supported directly at the moment.
45
46## STM32-based keyboard design considerations
47
48- STM32F0x2 chips can do crystal-less USB, but they still need a 3.3V voltage regulator.
49- The BOOT0 pin should be tied to GND.
50- 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.
51- There is a working example of a STM32F042-based keyboard: [firmware here](https://github.com/flabbergast/flabber_kbs/tree/master/kb45p) and [hardware (kicad) here](https://github.com/flabbergast/kicad/tree/master/kb45p). You can check this example firmware for custom board files, and a more complicated matrix than just one key.
52
53
54
55[ChibiOS]: http://chibios.org
diff --git a/tmk_core/protocol/chibios/main.c b/tmk_core/protocol/chibios/main.c
new file mode 100644
index 000000000..54bb6a8f5
--- /dev/null
+++ b/tmk_core/protocol/chibios/main.c
@@ -0,0 +1,147 @@
1/*
2 * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
3 *
4 * Based on the following work:
5 * - Guillaume Duc's raw hid example (MIT License)
6 * https://github.com/guiduc/usb-hid-chibios-example
7 * - PJRC Teensy examples (MIT License)
8 * https://www.pjrc.com/teensy/usb_keyboard.html
9 * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
10 * https://github.com/tmk/tmk_keyboard/
11 * - ChibiOS demo code (Apache 2.0 License)
12 * http://www.chibios.org
13 *
14 * Since some GPL'd code is used, this work is licensed under
15 * GPL v2 or later.
16 */
17
18#include "ch.h"
19#include "hal.h"
20
21#include "usb_main.h"
22
23/* TMK includes */
24#include "report.h"
25#include "host.h"
26#include "host_driver.h"
27#include "keyboard.h"
28#include "action.h"
29#include "action_util.h"
30#include "mousekey.h"
31#include "led.h"
32#include "sendchar.h"
33#include "debug.h"
34#include "printf.h"
35#ifdef SLEEP_LED_ENABLE
36#include "sleep_led.h"
37#endif
38#include "suspend.h"
39
40
41/* -------------------------
42 * TMK host driver defs
43 * -------------------------
44 */
45
46/* declarations */
47uint8_t keyboard_leds(void);
48void send_keyboard(report_keyboard_t *report);
49void send_mouse(report_mouse_t *report);
50void send_system(uint16_t data);
51void send_consumer(uint16_t data);
52
53/* host struct */
54host_driver_t chibios_driver = {
55 keyboard_leds,
56 send_keyboard,
57 send_mouse,
58 send_system,
59 send_consumer
60};
61
62
63/* TESTING
64 * Amber LED blinker thread, times are in milliseconds.
65 */
66/* set this variable to non-zero anywhere to blink once */
67// uint8_t blinkLed = 0;
68// static THD_WORKING_AREA(waBlinkerThread, 128);
69// static THD_FUNCTION(blinkerThread, arg) {
70// (void)arg;
71// chRegSetThreadName("blinkOrange");
72// while(true) {
73// if(blinkLed) {
74// blinkLed = 0;
75// palSetPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
76// chThdSleepMilliseconds(100);
77// palClearPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
78// }
79// chThdSleepMilliseconds(100);
80// }
81// }
82
83
84
85/* Main thread
86 */
87int main(void) {
88 /* ChibiOS/RT init */
89 halInit();
90 chSysInit();
91
92 // TESTING
93 // chThdCreateStatic(waBlinkerThread, sizeof(waBlinkerThread), NORMALPRIO, blinkerThread, NULL);
94
95 /* Init USB */
96 init_usb_driver(&USB_DRIVER);
97
98 /* init printf */
99 init_printf(NULL,sendchar_pf);
100
101 /* Wait until the USB is active */
102 while(USB_DRIVER.state != USB_ACTIVE)
103 chThdSleepMilliseconds(50);
104
105 /* Do need to wait here!
106 * Otherwise the next print might start a transfer on console EP
107 * before the USB is completely ready, which sometimes causes
108 * HardFaults.
109 */
110 chThdSleepMilliseconds(50);
111
112 print("USB configured.\n");
113
114 /* init TMK modules */
115 keyboard_init();
116 host_set_driver(&chibios_driver);
117
118#ifdef SLEEP_LED_ENABLE
119 sleep_led_init();
120#endif
121
122 print("Keyboard start.\n");
123
124 /* Main loop */
125 while(true) {
126
127 if(USB_DRIVER.state == USB_SUSPENDED) {
128 print("[s]");
129 while(USB_DRIVER.state == USB_SUSPENDED) {
130 /* Do this in the suspended state */
131 suspend_power_down(); // on AVR this deep sleeps for 15ms
132 /* Remote wakeup */
133 if((USB_DRIVER.status & 2) && suspend_wakeup_condition()) {
134 send_remote_wakeup(&USB_DRIVER);
135 }
136 }
137 /* Woken up */
138 // variables has been already cleared by the wakeup hook
139 send_keyboard_report();
140#ifdef MOUSEKEY_ENABLE
141 mousekey_send();
142#endif /* MOUSEKEY_ENABLE */
143 }
144
145 keyboard_task();
146 }
147}
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
new file mode 100644
index 000000000..e2c9d9bf1
--- /dev/null
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -0,0 +1,1372 @@
1/*
2 * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
3 *
4 * Based on the following work:
5 * - Guillaume Duc's raw hid example (MIT License)
6 * https://github.com/guiduc/usb-hid-chibios-example
7 * - PJRC Teensy examples (MIT License)
8 * https://www.pjrc.com/teensy/usb_keyboard.html
9 * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
10 * https://github.com/tmk/tmk_keyboard/
11 * - ChibiOS demo code (Apache 2.0 License)
12 * http://www.chibios.org
13 *
14 * Since some GPL'd code is used, this work is licensed under
15 * GPL v2 or later.
16 */
17
18#include "ch.h"
19#include "hal.h"
20
21#include "usb_main.h"
22
23#include "host.h"
24#include "debug.h"
25#include "suspend.h"
26#ifdef SLEEP_LED_ENABLE
27#include "sleep_led.h"
28#include "led.h"
29#endif
30
31/* ---------------------------------------------------------
32 * Global interface variables and declarations
33 * ---------------------------------------------------------
34 */
35
36uint8_t keyboard_idle __attribute__((aligned(2))) = 0;
37uint8_t keyboard_protocol __attribute__((aligned(2))) = 1;
38uint16_t keyboard_led_stats __attribute__((aligned(2))) = 0;
39volatile uint16_t keyboard_idle_count = 0;
40static virtual_timer_t keyboard_idle_timer;
41static void keyboard_idle_timer_cb(void *arg);
42#ifdef NKRO_ENABLE
43extern bool keyboard_nkro;
44#endif /* NKRO_ENABLE */
45
46report_keyboard_t keyboard_report_sent = {{0}};
47#ifdef MOUSE_ENABLE
48report_mouse_t mouse_report_blank = {0};
49#endif /* MOUSE_ENABLE */
50#ifdef EXTRAKEY_ENABLE
51uint8_t extra_report_blank[3] = {0};
52#endif /* EXTRAKEY_ENABLE */
53
54#ifdef CONSOLE_ENABLE
55/* The emission buffers queue */
56output_buffers_queue_t console_buf_queue;
57static uint8_t console_queue_buffer[BQ_BUFFER_SIZE(CONSOLE_QUEUE_CAPACITY, CONSOLE_EPSIZE)];
58
59static virtual_timer_t console_flush_timer;
60void console_queue_onotify(io_buffers_queue_t *bqp);
61static void console_flush_cb(void *arg);
62#endif /* CONSOLE_ENABLE */
63
64/* ---------------------------------------------------------
65 * Descriptors and USB driver objects
66 * ---------------------------------------------------------
67 */
68
69/* HID specific constants */
70#define USB_DESCRIPTOR_HID 0x21
71#define USB_DESCRIPTOR_HID_REPORT 0x22
72#define HID_GET_REPORT 0x01
73#define HID_GET_IDLE 0x02
74#define HID_GET_PROTOCOL 0x03
75#define HID_SET_REPORT 0x09
76#define HID_SET_IDLE 0x0A
77#define HID_SET_PROTOCOL 0x0B
78
79/* USB Device Descriptor */
80static const uint8_t usb_device_descriptor_data[] = {
81 USB_DESC_DEVICE(0x0200, // bcdUSB (1.1)
82 0, // bDeviceClass (defined in later in interface)
83 0, // bDeviceSubClass
84 0, // bDeviceProtocol
85 64, // bMaxPacketSize (64 bytes) (the driver didn't work with 32)
86 VENDOR_ID, // idVendor
87 PRODUCT_ID, // idProduct
88 DEVICE_VER, // bcdDevice
89 1, // iManufacturer
90 2, // iProduct
91 3, // iSerialNumber
92 1) // bNumConfigurations
93};
94
95/* Device Descriptor wrapper */
96static const USBDescriptor usb_device_descriptor = {
97 sizeof usb_device_descriptor_data,
98 usb_device_descriptor_data
99};
100
101/*
102 * HID Report Descriptor
103 *
104 * See "Device Class Definition for Human Interface Devices (HID)"
105 * (http://www.usb.org/developers/hidpage/HID1_11.pdf) for the
106 * detailed descrition of all the fields
107 */
108
109/* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */
110static const uint8_t keyboard_hid_report_desc_data[] = {
111 0x05, 0x01, // Usage Page (Generic Desktop),
112 0x09, 0x06, // Usage (Keyboard),
113 0xA1, 0x01, // Collection (Application),
114 0x75, 0x01, // Report Size (1),
115 0x95, 0x08, // Report Count (8),
116 0x05, 0x07, // Usage Page (Key Codes),
117 0x19, 0xE0, // Usage Minimum (224),
118 0x29, 0xE7, // Usage Maximum (231),
119 0x15, 0x00, // Logical Minimum (0),
120 0x25, 0x01, // Logical Maximum (1),
121 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
122 0x95, 0x01, // Report Count (1),
123 0x75, 0x08, // Report Size (8),
124 0x81, 0x03, // Input (Constant), ;Reserved byte
125 0x95, 0x05, // Report Count (5),
126 0x75, 0x01, // Report Size (1),
127 0x05, 0x08, // Usage Page (LEDs),
128 0x19, 0x01, // Usage Minimum (1),
129 0x29, 0x05, // Usage Maximum (5),
130 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
131 0x95, 0x01, // Report Count (1),
132 0x75, 0x03, // Report Size (3),
133 0x91, 0x03, // Output (Constant), ;LED report padding
134 0x95, KBD_REPORT_KEYS, // Report Count (),
135 0x75, 0x08, // Report Size (8),
136 0x15, 0x00, // Logical Minimum (0),
137 0x25, 0xFF, // Logical Maximum(255),
138 0x05, 0x07, // Usage Page (Key Codes),
139 0x19, 0x00, // Usage Minimum (0),
140 0x29, 0xFF, // Usage Maximum (255),
141 0x81, 0x00, // Input (Data, Array),
142 0xc0 // End Collection
143};
144/* wrapper */
145static const USBDescriptor keyboard_hid_report_descriptor = {
146 sizeof keyboard_hid_report_desc_data,
147 keyboard_hid_report_desc_data
148};
149
150#ifdef NKRO_ENABLE
151static const uint8_t nkro_hid_report_desc_data[] = {
152 0x05, 0x01, // Usage Page (Generic Desktop),
153 0x09, 0x06, // Usage (Keyboard),
154 0xA1, 0x01, // Collection (Application),
155 // bitmap of modifiers
156 0x75, 0x01, // Report Size (1),
157 0x95, 0x08, // Report Count (8),
158 0x05, 0x07, // Usage Page (Key Codes),
159 0x19, 0xE0, // Usage Minimum (224),
160 0x29, 0xE7, // Usage Maximum (231),
161 0x15, 0x00, // Logical Minimum (0),
162 0x25, 0x01, // Logical Maximum (1),
163 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
164 // LED output report
165 0x95, 0x05, // Report Count (5),
166 0x75, 0x01, // Report Size (1),
167 0x05, 0x08, // Usage Page (LEDs),
168 0x19, 0x01, // Usage Minimum (1),
169 0x29, 0x05, // Usage Maximum (5),
170 0x91, 0x02, // Output (Data, Variable, Absolute),
171 0x95, 0x01, // Report Count (1),
172 0x75, 0x03, // Report Size (3),
173 0x91, 0x03, // Output (Constant),
174 // bitmap of keys
175 0x95, NKRO_REPORT_KEYS * 8, // Report Count (),
176 0x75, 0x01, // Report Size (1),
177 0x15, 0x00, // Logical Minimum (0),
178 0x25, 0x01, // Logical Maximum(1),
179 0x05, 0x07, // Usage Page (Key Codes),
180 0x19, 0x00, // Usage Minimum (0),
181 0x29, NKRO_REPORT_KEYS * 8 - 1, // Usage Maximum (),
182 0x81, 0x02, // Input (Data, Variable, Absolute),
183 0xc0 // End Collection
184};
185/* wrapper */
186static const USBDescriptor nkro_hid_report_descriptor = {
187 sizeof nkro_hid_report_desc_data,
188 nkro_hid_report_desc_data
189};
190#endif /* NKRO_ENABLE */
191
192#ifdef MOUSE_ENABLE
193/* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
194 * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
195 * http://www.keil.com/forum/15671/
196 * http://www.microsoft.com/whdc/device/input/wheel.mspx */
197static const uint8_t mouse_hid_report_desc_data[] = {
198 /* mouse */
199 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
200 0x09, 0x02, // USAGE (Mouse)
201 0xa1, 0x01, // COLLECTION (Application)
202 //0x85, REPORT_ID_MOUSE, // REPORT_ID (1)
203 0x09, 0x01, // USAGE (Pointer)
204 0xa1, 0x00, // COLLECTION (Physical)
205 // ---------------------------- Buttons
206 0x05, 0x09, // USAGE_PAGE (Button)
207 0x19, 0x01, // USAGE_MINIMUM (Button 1)
208 0x29, 0x05, // USAGE_MAXIMUM (Button 5)
209 0x15, 0x00, // LOGICAL_MINIMUM (0)
210 0x25, 0x01, // LOGICAL_MAXIMUM (1)
211 0x75, 0x01, // REPORT_SIZE (1)
212 0x95, 0x05, // REPORT_COUNT (5)
213 0x81, 0x02, // INPUT (Data,Var,Abs)
214 0x75, 0x03, // REPORT_SIZE (3)
215 0x95, 0x01, // REPORT_COUNT (1)
216 0x81, 0x03, // INPUT (Cnst,Var,Abs)
217 // ---------------------------- X,Y position
218 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
219 0x09, 0x30, // USAGE (X)
220 0x09, 0x31, // USAGE (Y)
221 0x15, 0x81, // LOGICAL_MINIMUM (-127)
222 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
223 0x75, 0x08, // REPORT_SIZE (8)
224 0x95, 0x02, // REPORT_COUNT (2)
225 0x81, 0x06, // INPUT (Data,Var,Rel)
226 // ---------------------------- Vertical wheel
227 0x09, 0x38, // USAGE (Wheel)
228 0x15, 0x81, // LOGICAL_MINIMUM (-127)
229 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
230 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
231 0x45, 0x00, // PHYSICAL_MAXIMUM (0)
232 0x75, 0x08, // REPORT_SIZE (8)
233 0x95, 0x01, // REPORT_COUNT (1)
234 0x81, 0x06, // INPUT (Data,Var,Rel)
235 // ---------------------------- Horizontal wheel
236 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
237 0x0a, 0x38, 0x02, // USAGE (AC Pan)
238 0x15, 0x81, // LOGICAL_MINIMUM (-127)
239 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
240 0x75, 0x08, // REPORT_SIZE (8)
241 0x95, 0x01, // REPORT_COUNT (1)
242 0x81, 0x06, // INPUT (Data,Var,Rel)
243 0xc0, // END_COLLECTION
244 0xc0, // END_COLLECTION
245};
246/* wrapper */
247static const USBDescriptor mouse_hid_report_descriptor = {
248 sizeof mouse_hid_report_desc_data,
249 mouse_hid_report_desc_data
250};
251#endif /* MOUSE_ENABLE */
252
253#ifdef CONSOLE_ENABLE
254static const uint8_t console_hid_report_desc_data[] = {
255 0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
256 0x09, 0x74, // Usage 0x74
257 0xA1, 0x53, // Collection 0x53
258 0x75, 0x08, // report size = 8 bits
259 0x15, 0x00, // logical minimum = 0
260 0x26, 0xFF, 0x00, // logical maximum = 255
261 0x95, CONSOLE_EPSIZE, // report count
262 0x09, 0x75, // usage
263 0x81, 0x02, // Input (array)
264 0xC0 // end collection
265};
266/* wrapper */
267static const USBDescriptor console_hid_report_descriptor = {
268 sizeof console_hid_report_desc_data,
269 console_hid_report_desc_data
270};
271#endif /* CONSOLE_ENABLE */
272
273#ifdef EXTRAKEY_ENABLE
274/* audio controls & system controls
275 * http://www.microsoft.com/whdc/archive/w2kbd.mspx */
276static const uint8_t extra_hid_report_desc_data[] = {
277 /* system control */
278 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
279 0x09, 0x80, // USAGE (System Control)
280 0xa1, 0x01, // COLLECTION (Application)
281 0x85, REPORT_ID_SYSTEM, // REPORT_ID (2)
282 0x15, 0x01, // LOGICAL_MINIMUM (0x1)
283 0x25, 0xb7, // LOGICAL_MAXIMUM (0xb7)
284 0x19, 0x01, // USAGE_MINIMUM (0x1)
285 0x29, 0xb7, // USAGE_MAXIMUM (0xb7)
286 0x75, 0x10, // REPORT_SIZE (16)
287 0x95, 0x01, // REPORT_COUNT (1)
288 0x81, 0x00, // INPUT (Data,Array,Abs)
289 0xc0, // END_COLLECTION
290 /* consumer */
291 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
292 0x09, 0x01, // USAGE (Consumer Control)
293 0xa1, 0x01, // COLLECTION (Application)
294 0x85, REPORT_ID_CONSUMER, // REPORT_ID (3)
295 0x15, 0x01, // LOGICAL_MINIMUM (0x1)
296 0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c)
297 0x19, 0x01, // USAGE_MINIMUM (0x1)
298 0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c)
299 0x75, 0x10, // REPORT_SIZE (16)
300 0x95, 0x01, // REPORT_COUNT (1)
301 0x81, 0x00, // INPUT (Data,Array,Abs)
302 0xc0, // END_COLLECTION
303};
304/* wrapper */
305static const USBDescriptor extra_hid_report_descriptor = {
306 sizeof extra_hid_report_desc_data,
307 extra_hid_report_desc_data
308};
309#endif /* EXTRAKEY_ENABLE */
310
311
312/*
313 * Configuration Descriptor tree for a HID device
314 *
315 * The HID Specifications version 1.11 require the following order:
316 * - Configuration Descriptor
317 * - Interface Descriptor
318 * - HID Descriptor
319 * - Endpoints Descriptors
320 */
321#define KBD_HID_DESC_NUM 0
322#define KBD_HID_DESC_OFFSET (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9)
323
324#ifdef MOUSE_ENABLE
325# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1)
326# define MOUSE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9)
327#else /* MOUSE_ENABLE */
328# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0)
329#endif /* MOUSE_ENABLE */
330
331#ifdef CONSOLE_ENABLE
332#define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1)
333#define CONSOLE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9)
334#else /* CONSOLE_ENABLE */
335# define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 0)
336#endif /* CONSOLE_ENABLE */
337
338#ifdef EXTRAKEY_ENABLE
339# define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 1)
340# define EXTRA_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
341#else /* EXTRAKEY_ENABLE */
342# define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 0)
343#endif /* EXTRAKEY_ENABLE */
344
345#ifdef NKRO_ENABLE
346# define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1)
347# define NKRO_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
348#else /* NKRO_ENABLE */
349# define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0)
350#endif /* NKRO_ENABLE */
351
352#define NUM_INTERFACES (NKRO_HID_DESC_NUM + 1)
353#define CONFIG1_DESC_SIZE (9 + (9 + 9 + 7) * NUM_INTERFACES)
354
355static const uint8_t hid_configuration_descriptor_data[] = {
356 /* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */
357 USB_DESC_CONFIGURATION(CONFIG1_DESC_SIZE, // wTotalLength
358 NUM_INTERFACES, // bNumInterfaces
359 1, // bConfigurationValue
360 0, // iConfiguration
361 0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP)
362 50), // bMaxPower (50mA)
363
364 /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
365 USB_DESC_INTERFACE(KBD_INTERFACE, // bInterfaceNumber
366 0, // bAlternateSetting
367 1, // bNumEndpoints
368 0x03, // bInterfaceClass: HID
369 0x01, // bInterfaceSubClass: Boot
370 0x01, // bInterfaceProtocol: Keyboard
371 0), // iInterface
372
373 /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
374 USB_DESC_BYTE(9), // bLength
375 USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
376 USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
377 USB_DESC_BYTE(0), // bCountryCode
378 USB_DESC_BYTE(1), // bNumDescriptors
379 USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
380 USB_DESC_WORD(sizeof(keyboard_hid_report_desc_data)), // wDescriptorLength
381
382 /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
383 USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80, // bEndpointAddress
384 0x03, // bmAttributes (Interrupt)
385 KBD_EPSIZE,// wMaxPacketSize
386 10), // bInterval
387
388 #ifdef MOUSE_ENABLE
389 /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
390 USB_DESC_INTERFACE(MOUSE_INTERFACE, // bInterfaceNumber
391 0, // bAlternateSetting
392 1, // bNumEndpoints
393 0x03, // bInterfaceClass (0x03 = HID)
394 // ThinkPad T23 BIOS doesn't work with boot mouse.
395 0x00, // bInterfaceSubClass (0x01 = Boot)
396 0x00, // bInterfaceProtocol (0x02 = Mouse)
397 /*
398 0x01, // bInterfaceSubClass (0x01 = Boot)
399 0x02, // bInterfaceProtocol (0x02 = Mouse)
400 */
401 0), // iInterface
402
403 /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
404 USB_DESC_BYTE(9), // bLength
405 USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
406 USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
407 USB_DESC_BYTE(0), // bCountryCode
408 USB_DESC_BYTE(1), // bNumDescriptors
409 USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
410 USB_DESC_WORD(sizeof(mouse_hid_report_desc_data)), // wDescriptorLength
411
412 /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
413 USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80, // bEndpointAddress
414 0x03, // bmAttributes (Interrupt)
415 MOUSE_EPSIZE, // wMaxPacketSize
416 1), // bInterval
417 #endif /* MOUSE_ENABLE */
418
419 #ifdef CONSOLE_ENABLE
420 /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
421 USB_DESC_INTERFACE(CONSOLE_INTERFACE, // bInterfaceNumber
422 0, // bAlternateSetting
423 1, // bNumEndpoints
424 0x03, // bInterfaceClass: HID
425 0x00, // bInterfaceSubClass: None
426 0x00, // bInterfaceProtocol: None
427 0), // iInterface
428
429 /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
430 USB_DESC_BYTE(9), // bLength
431 USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
432 USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
433 USB_DESC_BYTE(0), // bCountryCode
434 USB_DESC_BYTE(1), // bNumDescriptors
435 USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
436 USB_DESC_WORD(sizeof(console_hid_report_desc_data)), // wDescriptorLength
437
438 /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
439 USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80, // bEndpointAddress
440 0x03, // bmAttributes (Interrupt)
441 CONSOLE_EPSIZE, // wMaxPacketSize
442 1), // bInterval
443 #endif /* CONSOLE_ENABLE */
444
445 #ifdef EXTRAKEY_ENABLE
446 /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
447 USB_DESC_INTERFACE(EXTRA_INTERFACE, // bInterfaceNumber
448 0, // bAlternateSetting
449 1, // bNumEndpoints
450 0x03, // bInterfaceClass: HID
451 0x00, // bInterfaceSubClass: None
452 0x00, // bInterfaceProtocol: None
453 0), // iInterface
454
455 /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
456 USB_DESC_BYTE(9), // bLength
457 USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
458 USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
459 USB_DESC_BYTE(0), // bCountryCode
460 USB_DESC_BYTE(1), // bNumDescriptors
461 USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
462 USB_DESC_WORD(sizeof(extra_hid_report_desc_data)), // wDescriptorLength
463
464 /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
465 USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80, // bEndpointAddress
466 0x03, // bmAttributes (Interrupt)
467 EXTRA_EPSIZE, // wMaxPacketSize
468 10), // bInterval
469 #endif /* EXTRAKEY_ENABLE */
470
471 #ifdef NKRO_ENABLE
472 /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
473 USB_DESC_INTERFACE(NKRO_INTERFACE, // bInterfaceNumber
474 0, // bAlternateSetting
475 1, // bNumEndpoints
476 0x03, // bInterfaceClass: HID
477 0x00, // bInterfaceSubClass: None
478 0x00, // bInterfaceProtocol: None
479 0), // iInterface
480
481 /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
482 USB_DESC_BYTE(9), // bLength
483 USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
484 USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
485 USB_DESC_BYTE(0), // bCountryCode
486 USB_DESC_BYTE(1), // bNumDescriptors
487 USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
488 USB_DESC_WORD(sizeof(nkro_hid_report_desc_data)), // wDescriptorLength
489
490 /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
491 USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80, // bEndpointAddress
492 0x03, // bmAttributes (Interrupt)
493 NKRO_EPSIZE, // wMaxPacketSize
494 1), // bInterval
495 #endif /* NKRO_ENABLE */
496};
497
498/* Configuration Descriptor wrapper */
499static const USBDescriptor hid_configuration_descriptor = {
500 sizeof hid_configuration_descriptor_data,
501 hid_configuration_descriptor_data
502};
503
504/* wrappers */
505#define HID_DESCRIPTOR_SIZE 9
506static const USBDescriptor keyboard_hid_descriptor = {
507 HID_DESCRIPTOR_SIZE,
508 &hid_configuration_descriptor_data[KBD_HID_DESC_OFFSET]
509};
510#ifdef MOUSE_ENABLE
511static const USBDescriptor mouse_hid_descriptor = {
512 HID_DESCRIPTOR_SIZE,
513 &hid_configuration_descriptor_data[MOUSE_HID_DESC_OFFSET]
514};
515#endif /* MOUSE_ENABLE */
516#ifdef CONSOLE_ENABLE
517static const USBDescriptor console_hid_descriptor = {
518 HID_DESCRIPTOR_SIZE,
519 &hid_configuration_descriptor_data[CONSOLE_HID_DESC_OFFSET]
520};
521#endif /* CONSOLE_ENABLE */
522#ifdef EXTRAKEY_ENABLE
523static const USBDescriptor extra_hid_descriptor = {
524 HID_DESCRIPTOR_SIZE,
525 &hid_configuration_descriptor_data[EXTRA_HID_DESC_OFFSET]
526};
527#endif /* EXTRAKEY_ENABLE */
528#ifdef NKRO_ENABLE
529static const USBDescriptor nkro_hid_descriptor = {
530 HID_DESCRIPTOR_SIZE,
531 &hid_configuration_descriptor_data[NKRO_HID_DESC_OFFSET]
532};
533#endif /* NKRO_ENABLE */
534
535
536/* U.S. English language identifier */
537static const uint8_t usb_string_langid[] = {
538 USB_DESC_BYTE(4), // bLength
539 USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
540 USB_DESC_WORD(0x0409) // wLANGID (U.S. English)
541};
542
543/* ugly ugly hack */
544#define PP_NARG(...) \
545 PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
546#define PP_NARG_(...) \
547 PP_ARG_N(__VA_ARGS__)
548#define PP_ARG_N( \
549 _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
550 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
551 _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
552 _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
553 _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
554 _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
555 _61,_62,_63,N,...) N
556#define PP_RSEQ_N() \
557 63,62,61,60, \
558 59,58,57,56,55,54,53,52,51,50, \
559 49,48,47,46,45,44,43,42,41,40, \
560 39,38,37,36,35,34,33,32,31,30, \
561 29,28,27,26,25,24,23,22,21,20, \
562 19,18,17,16,15,14,13,12,11,10, \
563 9,8,7,6,5,4,3,2,1,0
564
565/* Vendor string = manufacturer */
566static const uint8_t usb_string_vendor[] = {
567 USB_DESC_BYTE(PP_NARG(USBSTR_MANUFACTURER)+2), // bLength
568 USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
569 USBSTR_MANUFACTURER
570};
571
572/* Device Description string = product */
573static const uint8_t usb_string_description[] = {
574 USB_DESC_BYTE(PP_NARG(USBSTR_PRODUCT)+2), // bLength
575 USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
576 USBSTR_PRODUCT
577};
578
579/* Serial Number string (will be filled by the function init_usb_serial_string) */
580static uint8_t usb_string_serial[] = {
581 USB_DESC_BYTE(22), // bLength
582 USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
583 '0', 0, 'x', 0, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'B', 0, 'E', 0, 'E', 0, 'F', 0
584};
585
586/* Strings wrappers array */
587static const USBDescriptor usb_strings[] = {
588 { sizeof usb_string_langid, usb_string_langid }
589 ,
590 { sizeof usb_string_vendor, usb_string_vendor }
591 ,
592 { sizeof usb_string_description, usb_string_description }
593 ,
594 { sizeof usb_string_serial, usb_string_serial }
595};
596
597/*
598 * Handles the GET_DESCRIPTOR callback
599 *
600 * Returns the proper descriptor
601 */
602static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) {
603 (void)usbp;
604 (void)lang;
605 switch(dtype) {
606 /* Generic descriptors */
607 case USB_DESCRIPTOR_DEVICE: /* Device Descriptor */
608 return &usb_device_descriptor;
609
610 case USB_DESCRIPTOR_CONFIGURATION: /* Configuration Descriptor */
611 return &hid_configuration_descriptor;
612
613 case USB_DESCRIPTOR_STRING: /* Strings */
614 if(dindex < 4)
615 return &usb_strings[dindex];
616 break;
617
618 /* HID specific descriptors */
619 case USB_DESCRIPTOR_HID: /* HID Descriptors */
620 switch(lang) { /* yea, poor label, it's actually wIndex from the setup packet */
621 case KBD_INTERFACE:
622 return &keyboard_hid_descriptor;
623
624#ifdef MOUSE_ENABLE
625 case MOUSE_INTERFACE:
626 return &mouse_hid_descriptor;
627#endif /* MOUSE_ENABLE */
628#ifdef CONSOLE_ENABLE
629 case CONSOLE_INTERFACE:
630 return &console_hid_descriptor;
631#endif /* CONSOLE_ENABLE */
632#ifdef EXTRAKEY_ENABLE
633 case EXTRA_INTERFACE:
634 return &extra_hid_descriptor;
635#endif /* EXTRAKEY_ENABLE */
636#ifdef NKRO_ENABLE
637 case NKRO_INTERFACE:
638 return &nkro_hid_descriptor;
639#endif /* NKRO_ENABLE */
640 }
641
642 case USB_DESCRIPTOR_HID_REPORT: /* HID Report Descriptor */
643 switch(lang) {
644 case KBD_INTERFACE:
645 return &keyboard_hid_report_descriptor;
646
647#ifdef MOUSE_ENABLE
648 case MOUSE_INTERFACE:
649 return &mouse_hid_report_descriptor;
650#endif /* MOUSE_ENABLE */
651#ifdef CONSOLE_ENABLE
652 case CONSOLE_INTERFACE:
653 return &console_hid_report_descriptor;
654#endif /* CONSOLE_ENABLE */
655#ifdef EXTRAKEY_ENABLE
656 case EXTRA_INTERFACE:
657 return &extra_hid_report_descriptor;
658#endif /* EXTRAKEY_ENABLE */
659#ifdef NKRO_ENABLE
660 case NKRO_INTERFACE:
661 return &nkro_hid_report_descriptor;
662#endif /* NKRO_ENABLE */
663 }
664 }
665 return NULL;
666}
667
668/* keyboard endpoint state structure */
669static USBInEndpointState kbd_ep_state;
670/* keyboard endpoint initialization structure (IN) */
671static const USBEndpointConfig kbd_ep_config = {
672 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
673 NULL, /* SETUP packet notification callback */
674 kbd_in_cb, /* IN notification callback */
675 NULL, /* OUT notification callback */
676 KBD_EPSIZE, /* IN maximum packet size */
677 0, /* OUT maximum packet size */
678 &kbd_ep_state, /* IN Endpoint state */
679 NULL, /* OUT endpoint state */
680 2, /* IN multiplier */
681 NULL /* SETUP buffer (not a SETUP endpoint) */
682};
683
684#ifdef MOUSE_ENABLE
685/* mouse endpoint state structure */
686static USBInEndpointState mouse_ep_state;
687
688/* mouse endpoint initialization structure (IN) */
689static const USBEndpointConfig mouse_ep_config = {
690 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
691 NULL, /* SETUP packet notification callback */
692 mouse_in_cb, /* IN notification callback */
693 NULL, /* OUT notification callback */
694 MOUSE_EPSIZE, /* IN maximum packet size */
695 0, /* OUT maximum packet size */
696 &mouse_ep_state, /* IN Endpoint state */
697 NULL, /* OUT endpoint state */
698 2, /* IN multiplier */
699 NULL /* SETUP buffer (not a SETUP endpoint) */
700};
701#endif /* MOUSE_ENABLE */
702
703#ifdef CONSOLE_ENABLE
704/* console endpoint state structure */
705static USBInEndpointState console_ep_state;
706
707/* console endpoint initialization structure (IN) */
708static const USBEndpointConfig console_ep_config = {
709 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
710 NULL, /* SETUP packet notification callback */
711 console_in_cb, /* IN notification callback */
712 NULL, /* OUT notification callback */
713 CONSOLE_EPSIZE, /* IN maximum packet size */
714 0, /* OUT maximum packet size */
715 &console_ep_state, /* IN Endpoint state */
716 NULL, /* OUT endpoint state */
717 2, /* IN multiplier */
718 NULL /* SETUP buffer (not a SETUP endpoint) */
719};
720#endif /* CONSOLE_ENABLE */
721
722#ifdef EXTRAKEY_ENABLE
723/* extrakey endpoint state structure */
724static USBInEndpointState extra_ep_state;
725
726/* extrakey endpoint initialization structure (IN) */
727static const USBEndpointConfig extra_ep_config = {
728 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
729 NULL, /* SETUP packet notification callback */
730 extra_in_cb, /* IN notification callback */
731 NULL, /* OUT notification callback */
732 EXTRA_EPSIZE, /* IN maximum packet size */
733 0, /* OUT maximum packet size */
734 &extra_ep_state, /* IN Endpoint state */
735 NULL, /* OUT endpoint state */
736 2, /* IN multiplier */
737 NULL /* SETUP buffer (not a SETUP endpoint) */
738};
739#endif /* EXTRAKEY_ENABLE */
740
741#ifdef NKRO_ENABLE
742/* nkro endpoint state structure */
743static USBInEndpointState nkro_ep_state;
744
745/* nkro endpoint initialization structure (IN) */
746static const USBEndpointConfig nkro_ep_config = {
747 USB_EP_MODE_TYPE_INTR, /* Interrupt EP */
748 NULL, /* SETUP packet notification callback */
749 nkro_in_cb, /* IN notification callback */
750 NULL, /* OUT notification callback */
751 NKRO_EPSIZE, /* IN maximum packet size */
752 0, /* OUT maximum packet size */
753 &nkro_ep_state, /* IN Endpoint state */
754 NULL, /* OUT endpoint state */
755 2, /* IN multiplier */
756 NULL /* SETUP buffer (not a SETUP endpoint) */
757};
758#endif /* NKRO_ENABLE */
759
760/* ---------------------------------------------------------
761 * USB driver functions
762 * ---------------------------------------------------------
763 */
764
765/* Handles the USB driver global events
766 * TODO: maybe disable some things when connection is lost? */
767static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
768 switch(event) {
769 case USB_EVENT_RESET:
770 //TODO: from ISR! print("[R]");
771 return;
772
773 case USB_EVENT_ADDRESS:
774 return;
775
776 case USB_EVENT_CONFIGURED:
777 osalSysLockFromISR();
778 /* Enable the endpoints specified into the configuration. */
779 usbInitEndpointI(usbp, KBD_ENDPOINT, &kbd_ep_config);
780#ifdef MOUSE_ENABLE
781 usbInitEndpointI(usbp, MOUSE_ENDPOINT, &mouse_ep_config);
782#endif /* MOUSE_ENABLE */
783#ifdef CONSOLE_ENABLE
784 usbInitEndpointI(usbp, CONSOLE_ENDPOINT, &console_ep_config);
785 /* don't need to start the flush timer, it starts from console_in_cb automatically */
786#endif /* CONSOLE_ENABLE */
787#ifdef EXTRAKEY_ENABLE
788 usbInitEndpointI(usbp, EXTRA_ENDPOINT, &extra_ep_config);
789#endif /* EXTRAKEY_ENABLE */
790#ifdef NKRO_ENABLE
791 usbInitEndpointI(usbp, NKRO_ENDPOINT, &nkro_ep_config);
792#endif /* NKRO_ENABLE */
793 osalSysUnlockFromISR();
794 return;
795
796 case USB_EVENT_SUSPEND:
797 //TODO: from ISR! print("[S]");
798#ifdef SLEEP_LED_ENABLE
799 sleep_led_enable();
800#endif /* SLEEP_LED_ENABLE */
801 return;
802
803 case USB_EVENT_WAKEUP:
804 //TODO: from ISR! print("[W]");
805 suspend_wakeup_init();
806#ifdef SLEEP_LED_ENABLE
807 sleep_led_disable();
808 // NOTE: converters may not accept this
809 led_set(host_keyboard_leds());
810#endif /* SLEEP_LED_ENABLE */
811 return;
812
813 case USB_EVENT_STALLED:
814 return;
815 }
816}
817
818/* Function used locally in os/hal/src/usb.c for getting descriptors
819 * need it here for HID descriptor */
820static uint16_t get_hword(uint8_t *p) {
821 uint16_t hw;
822
823 hw = (uint16_t)*p++;
824 hw |= (uint16_t)*p << 8U;
825 return hw;
826}
827
828/*
829 * Appendix G: HID Request Support Requirements
830 *
831 * The following table enumerates the requests that need to be supported by various types of HID class devices.
832 * Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
833 * ------------------------------------------------------------------------------------------
834 * Boot Mouse Required Optional Optional Optional Required Required
835 * Non-Boot Mouse Required Optional Optional Optional Optional Optional
836 * Boot Keyboard Required Optional Required Required Required Required
837 * Non-Boot Keybrd Required Optional Required Required Optional Optional
838 * Other Device Required Optional Optional Optional Optional Optional
839 */
840
841/* Callback for SETUP request on the endpoint 0 (control) */
842static bool usb_request_hook_cb(USBDriver *usbp) {
843 const USBDescriptor *dp;
844
845 /* usbp->setup fields:
846 * 0: bmRequestType (bitmask)
847 * 1: bRequest
848 * 2,3: (LSB,MSB) wValue
849 * 4,5: (LSB,MSB) wIndex
850 * 6,7: (LSB,MSB) wLength (number of bytes to transfer if there is a data phase) */
851
852 /* Handle HID class specific requests */
853 if(((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) &&
854 ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) {
855 switch(usbp->setup[0] & USB_RTYPE_DIR_MASK) {
856 case USB_RTYPE_DIR_DEV2HOST:
857 switch(usbp->setup[1]) { /* bRequest */
858 case HID_GET_REPORT:
859 switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0?) */
860 case KBD_INTERFACE:
861#ifdef NKRO_ENABLE
862 case NKRO_INTERFACE:
863#endif /* NKRO_ENABLE */
864 usbSetupTransfer(usbp, (uint8_t *)&keyboard_report_sent, sizeof(keyboard_report_sent), NULL);
865 return TRUE;
866 break;
867
868#ifdef MOUSE_ENABLE
869 case MOUSE_INTERFACE:
870 usbSetupTransfer(usbp, (uint8_t *)&mouse_report_blank, sizeof(mouse_report_blank), NULL);
871 return TRUE;
872 break;
873#endif /* MOUSE_ENABLE */
874
875#ifdef CONSOLE_ENABLE
876 case CONSOLE_INTERFACE:
877 usbSetupTransfer(usbp, console_queue_buffer, CONSOLE_EPSIZE, NULL);
878 return TRUE;
879 break;
880#endif /* CONSOLE_ENABLE */
881
882#ifdef EXTRAKEY_ENABLE
883 case EXTRA_INTERFACE:
884 if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
885 switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */
886 case REPORT_ID_SYSTEM:
887 extra_report_blank[0] = REPORT_ID_SYSTEM;
888 usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
889 return TRUE;
890 break;
891 case REPORT_ID_CONSUMER:
892 extra_report_blank[0] = REPORT_ID_CONSUMER;
893 usbSetupTransfer(usbp, (uint8_t *)extra_report_blank, sizeof(extra_report_blank), NULL);
894 return TRUE;
895 break;
896 default:
897 return FALSE;
898 }
899 } else {
900 return FALSE;
901 }
902 break;
903#endif /* EXTRAKEY_ENABLE */
904
905 default:
906 usbSetupTransfer(usbp, NULL, 0, NULL);
907 return TRUE;
908 break;
909 }
910 break;
911
912 case HID_GET_PROTOCOL:
913 if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */
914 usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL);
915 return TRUE;
916 }
917 break;
918
919 case HID_GET_IDLE:
920 usbSetupTransfer(usbp, &keyboard_idle, 1, NULL);
921 return TRUE;
922 break;
923 }
924 break;
925
926 case USB_RTYPE_DIR_HOST2DEV:
927 switch(usbp->setup[1]) { /* bRequest */
928 case HID_SET_REPORT:
929 switch(usbp->setup[4]) { /* LSB(wIndex) (check MSB==0 and wLength==1?) */
930 case KBD_INTERFACE:
931#ifdef NKRO_ENABLE
932 case NKRO_INTERFACE:
933#endif /* NKRO_ENABLE */
934 /* keyboard_led_stats = <read byte from next OUT report>
935 * keyboard_led_stats needs be word (or dword), otherwise we get an exception on F0 */
936 usbSetupTransfer(usbp, (uint8_t *)&keyboard_led_stats, 1, NULL);
937 return TRUE;
938 break;
939 }
940 break;
941
942 case HID_SET_PROTOCOL:
943 if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) { /* wIndex */
944 keyboard_protocol = ((usbp->setup[2]) != 0x00); /* LSB(wValue) */
945#ifdef NKRO_ENABLE
946 keyboard_nkro = !!keyboard_protocol;
947 if(!keyboard_nkro && keyboard_idle) {
948#else /* NKRO_ENABLE */
949 if(keyboard_idle) {
950#endif /* NKRO_ENABLE */
951 /* arm the idle timer if boot protocol & idle */
952 osalSysLockFromISR();
953 chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
954 osalSysUnlockFromISR();
955 }
956 }
957 usbSetupTransfer(usbp, NULL, 0, NULL);
958 return TRUE;
959 break;
960
961 case HID_SET_IDLE:
962 keyboard_idle = usbp->setup[3]; /* MSB(wValue) */
963 /* arm the timer */
964#ifdef NKRO_ENABLE
965 if(!keyboard_nkro && keyboard_idle) {
966#else /* NKRO_ENABLE */
967 if(keyboard_idle) {
968#endif /* NKRO_ENABLE */
969 osalSysLockFromISR();
970 chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
971 osalSysUnlockFromISR();
972 }
973 usbSetupTransfer(usbp, NULL, 0, NULL);
974 return TRUE;
975 break;
976 }
977 break;
978 }
979 }
980
981 /* Handle the Get_Descriptor Request for HID class (not handled by the default hook) */
982 if((usbp->setup[0] == 0x81) && (usbp->setup[1] == USB_REQ_GET_DESCRIPTOR)) {
983 dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], get_hword(&usbp->setup[4]));
984 if(dp == NULL)
985 return FALSE;
986 usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
987 return TRUE;
988 }
989
990 return FALSE;
991}
992
993/* Start-of-frame callback */
994static void usb_sof_cb(USBDriver *usbp) {
995 kbd_sof_cb(usbp);
996}
997
998
999/* USB driver configuration */
1000static const USBConfig usbcfg = {
1001 usb_event_cb, /* USB events callback */
1002 usb_get_descriptor_cb, /* Device GET_DESCRIPTOR request callback */
1003 usb_request_hook_cb, /* Requests hook callback */
1004 usb_sof_cb /* Start Of Frame callback */
1005};
1006
1007/*
1008 * Initialize the USB driver
1009 */
1010void init_usb_driver(USBDriver *usbp) {
1011 /*
1012 * Activates the USB driver and then the USB bus pull-up on D+.
1013 * Note, a delay is inserted in order to not have to disconnect the cable
1014 * after a reset.
1015 */
1016 usbDisconnectBus(usbp);
1017 chThdSleepMilliseconds(1500);
1018 usbStart(usbp, &usbcfg);
1019 usbConnectBus(usbp);
1020
1021 chVTObjectInit(&keyboard_idle_timer);
1022#ifdef CONSOLE_ENABLE
1023 obqObjectInit(&console_buf_queue, console_queue_buffer, CONSOLE_EPSIZE, CONSOLE_QUEUE_CAPACITY, console_queue_onotify, (void*)usbp);
1024 chVTObjectInit(&console_flush_timer);
1025#endif
1026}
1027
1028/*
1029 * Send remote wakeup packet
1030 * Note: should not be called from ISR
1031 */
1032void send_remote_wakeup(USBDriver *usbp) {
1033 (void)usbp;
1034#if defined(K20x) || defined(KL2x)
1035#if KINETIS_USB_USE_USB0
1036 USB0->CTL |= USBx_CTL_RESUME;
1037 chThdSleepMilliseconds(15);
1038 USB0->CTL &= ~USBx_CTL_RESUME;
1039#endif /* KINETIS_USB_USE_USB0 */
1040#elif defined(STM32F0XX) || defined(STM32F1XX) /* K20x || KL2x */
1041 STM32_USB->CNTR |= CNTR_RESUME;
1042 chThdSleepMilliseconds(15);
1043 STM32_USB->CNTR &= ~CNTR_RESUME;
1044#else /* STM32F0XX || STM32F1XX */
1045#warning Sending remote wakeup packet not implemented for your platform.
1046#endif /* K20x || KL2x */
1047}
1048
1049/* ---------------------------------------------------------
1050 * Keyboard functions
1051 * ---------------------------------------------------------
1052 */
1053
1054/* keyboard IN callback hander (a kbd report has made it IN) */
1055void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
1056 /* STUB */
1057 (void)usbp;
1058 (void)ep;
1059}
1060
1061#ifdef NKRO_ENABLE
1062/* nkro IN callback hander (a nkro report has made it IN) */
1063void nkro_in_cb(USBDriver *usbp, usbep_t ep) {
1064 /* STUB */
1065 (void)usbp;
1066 (void)ep;
1067}
1068#endif /* NKRO_ENABLE */
1069
1070/* start-of-frame handler
1071 * TODO: i guess it would be better to re-implement using timers,
1072 * so that this is not going to have to be checked every 1ms */
1073void kbd_sof_cb(USBDriver *usbp) {
1074 (void)usbp;
1075}
1076
1077/* Idle requests timer code
1078 * callback (called from ISR, unlocked state) */
1079static void keyboard_idle_timer_cb(void *arg) {
1080 USBDriver *usbp = (USBDriver *)arg;
1081
1082 osalSysLockFromISR();
1083
1084 /* check that the states of things are as they're supposed to */
1085 if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
1086 /* do not rearm the timer, should be enabled on IDLE request */
1087 osalSysUnlockFromISR();
1088 return;
1089 }
1090
1091#ifdef NKRO_ENABLE
1092 if(!keyboard_nkro && keyboard_idle) {
1093#else /* NKRO_ENABLE */
1094 if(keyboard_idle) {
1095#endif /* NKRO_ENABLE */
1096 /* TODO: are we sure we want the KBD_ENDPOINT? */
1097 if(!usbGetTransmitStatusI(usbp, KBD_ENDPOINT)) {
1098 usbStartTransmitI(usbp, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, KBD_EPSIZE);
1099 }
1100 /* rearm the timer */
1101 chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
1102 }
1103
1104 /* do not rearm the timer if the condition above fails
1105 * it should be enabled again on either IDLE or SET_PROTOCOL requests */
1106 osalSysUnlockFromISR();
1107}
1108
1109/* LED status */
1110uint8_t keyboard_leds(void) {
1111 return (uint8_t)(keyboard_led_stats & 0xFF);
1112}
1113
1114/* prepare and start sending a report IN
1115 * not callable from ISR or locked state */
1116void send_keyboard(report_keyboard_t *report) {
1117 osalSysLock();
1118 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1119 osalSysUnlock();
1120 return;
1121 }
1122 osalSysUnlock();
1123
1124#ifdef NKRO_ENABLE
1125 if(keyboard_nkro) { /* NKRO protocol */
1126 /* need to wait until the previous packet has made it through */
1127 /* can rewrite this using the synchronous API, then would wait
1128 * until *after* the packet has been transmitted. I think
1129 * this is more efficient */
1130 /* busy wait, should be short and not very common */
1131 osalSysLock();
1132 if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_ENDPOINT)) {
1133 /* Need to either suspend, or loop and call unlock/lock during
1134 * every iteration - otherwise the system will remain locked,
1135 * no interrupts served, so USB not going through as well.
1136 * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
1137 osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_ENDPOINT]->in_state->thread);
1138 }
1139 usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
1140 osalSysUnlock();
1141 } else
1142#endif /* NKRO_ENABLE */
1143 { /* boot protocol */
1144 /* need to wait until the previous packet has made it through */
1145 /* busy wait, should be short and not very common */
1146 osalSysLock();
1147 if(usbGetTransmitStatusI(&USB_DRIVER, KBD_ENDPOINT)) {
1148 /* Need to either suspend, or loop and call unlock/lock during
1149 * every iteration - otherwise the system will remain locked,
1150 * no interrupts served, so USB not going through as well.
1151 * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
1152 osalThreadSuspendS(&(&USB_DRIVER)->epc[KBD_ENDPOINT]->in_state->thread);
1153 }
1154 usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE);
1155 osalSysUnlock();
1156 }
1157 keyboard_report_sent = *report;
1158}
1159
1160/* ---------------------------------------------------------
1161 * Mouse functions
1162 * ---------------------------------------------------------
1163 */
1164
1165#ifdef MOUSE_ENABLE
1166
1167/* mouse IN callback hander (a mouse report has made it IN) */
1168void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
1169 (void)usbp;
1170 (void)ep;
1171}
1172
1173void send_mouse(report_mouse_t *report) {
1174 osalSysLock();
1175 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1176 osalSysUnlock();
1177 return;
1178 }
1179 osalSysUnlock();
1180
1181 /* TODO: LUFA manually waits for the endpoint to become ready
1182 * for about 10ms for mouse, kbd, system; 1ms for nkro
1183 * is this really needed?
1184 */
1185
1186 osalSysLock();
1187 usbStartTransmitI(&USB_DRIVER, MOUSE_ENDPOINT, (uint8_t *)report, sizeof(report_mouse_t));
1188 osalSysUnlock();
1189}
1190
1191#else /* MOUSE_ENABLE */
1192void send_mouse(report_mouse_t *report) {
1193 (void)report;
1194}
1195#endif /* MOUSE_ENABLE */
1196
1197/* ---------------------------------------------------------
1198 * Extrakey functions
1199 * ---------------------------------------------------------
1200 */
1201
1202#ifdef EXTRAKEY_ENABLE
1203
1204/* extrakey IN callback hander */
1205void extra_in_cb(USBDriver *usbp, usbep_t ep) {
1206 /* STUB */
1207 (void)usbp;
1208 (void)ep;
1209}
1210
1211static void send_extra_report(uint8_t report_id, uint16_t data) {
1212 osalSysLock();
1213 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1214 osalSysUnlock();
1215 return;
1216 }
1217
1218 report_extra_t report = {
1219 .report_id = report_id,
1220 .usage = data
1221 };
1222
1223 usbStartTransmitI(&USB_DRIVER, EXTRA_ENDPOINT, (uint8_t *)&report, sizeof(report_extra_t));
1224 osalSysUnlock();
1225}
1226
1227void send_system(uint16_t data) {
1228 send_extra_report(REPORT_ID_SYSTEM, data);
1229}
1230
1231void send_consumer(uint16_t data) {
1232 send_extra_report(REPORT_ID_CONSUMER, data);
1233}
1234
1235#else /* EXTRAKEY_ENABLE */
1236void send_system(uint16_t data) {
1237 (void)data;
1238}
1239void send_consumer(uint16_t data) {
1240 (void)data;
1241}
1242#endif /* EXTRAKEY_ENABLE */
1243
1244/* ---------------------------------------------------------
1245 * Console functions
1246 * ---------------------------------------------------------
1247 */
1248
1249#ifdef CONSOLE_ENABLE
1250
1251/* console IN callback hander */
1252void console_in_cb(USBDriver *usbp, usbep_t ep) {
1253 (void)ep; /* should have ep == CONSOLE_ENDPOINT, so use that to save time/space */
1254 uint8_t *buf;
1255 size_t n;
1256
1257 osalSysLockFromISR();
1258
1259 /* rearm the timer */
1260 chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1261
1262 /* Freeing the buffer just transmitted, if it was not a zero size packet.*/
1263 if (usbp->epc[CONSOLE_ENDPOINT]->in_state->txsize > 0U) {
1264 obqReleaseEmptyBufferI(&console_buf_queue);
1265 }
1266
1267 /* Checking if there is a buffer ready for transmission.*/
1268 buf = obqGetFullBufferI(&console_buf_queue, &n);
1269
1270 if (buf != NULL) {
1271 /* The endpoint cannot be busy, we are in the context of the callback,
1272 so it is safe to transmit without a check.*/
1273 /* Should have n == CONSOLE_EPSIZE; check it? */
1274 usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
1275 } else {
1276 /* Nothing to transmit.*/
1277 }
1278
1279 osalSysUnlockFromISR();
1280}
1281
1282/* Callback when data is inserted into the output queue
1283 * Called from a locked state */
1284void console_queue_onotify(io_buffers_queue_t *bqp) {
1285 size_t n;
1286 USBDriver *usbp = bqGetLinkX(bqp);
1287
1288 if(usbGetDriverStateI(usbp) != USB_ACTIVE)
1289 return;
1290
1291 /* Checking if there is already a transaction ongoing on the endpoint.*/
1292 if (!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) {
1293 /* Trying to get a full buffer.*/
1294 uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n);
1295 if (buf != NULL) {
1296 /* Buffer found, starting a new transaction.*/
1297 /* Should have n == CONSOLE_EPSIZE; check this? */
1298 usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
1299 }
1300 }
1301}
1302
1303/* Flush timer code
1304 * callback (called from ISR, unlocked state) */
1305static void console_flush_cb(void *arg) {
1306 USBDriver *usbp = (USBDriver *)arg;
1307 osalSysLockFromISR();
1308
1309 /* check that the states of things are as they're supposed to */
1310 if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
1311 /* rearm the timer */
1312 chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1313 osalSysUnlockFromISR();
1314 return;
1315 }
1316
1317 /* If there is already a transaction ongoing then another one cannot be
1318 started.*/
1319 if (usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) {
1320 /* rearm the timer */
1321 chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1322 osalSysUnlockFromISR();
1323 return;
1324 }
1325
1326 /* Checking if there only a buffer partially filled, if so then it is
1327 enforced in the queue and transmitted.*/
1328 if(obqTryFlushI(&console_buf_queue)) {
1329 size_t n,i;
1330 uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n);
1331
1332 osalDbgAssert(buf != NULL, "queue is empty");
1333
1334 /* zero the rest of the buffer (buf should point to allocated space) */
1335 for(i=n; i<CONSOLE_EPSIZE; i++)
1336 buf[i]=0;
1337 usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
1338 }
1339
1340 /* rearm the timer */
1341 chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
1342 osalSysUnlockFromISR();
1343}
1344
1345
1346int8_t sendchar(uint8_t c) {
1347 osalSysLock();
1348 if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
1349 osalSysUnlock();
1350 return 0;
1351 }
1352 osalSysUnlock();
1353 /* Timeout after 100us if the queue is full.
1354 * Increase this timeout if too much stuff is getting
1355 * dropped (i.e. the buffer is getting full too fast
1356 * for USB/HIDRAW to dequeue). Another possibility
1357 * for fixing this kind of thing is to increase
1358 * CONSOLE_QUEUE_CAPACITY. */
1359 return(obqPutTimeout(&console_buf_queue, c, US2ST(100)));
1360}
1361
1362#else /* CONSOLE_ENABLE */
1363int8_t sendchar(uint8_t c) {
1364 (void)c;
1365 return 0;
1366}
1367#endif /* CONSOLE_ENABLE */
1368
1369void sendchar_pf(void *p, char c) {
1370 (void)p;
1371 sendchar((uint8_t)c);
1372}
diff --git a/tmk_core/protocol/chibios/usb_main.h b/tmk_core/protocol/chibios/usb_main.h
new file mode 100644
index 000000000..30d8fcaef
--- /dev/null
+++ b/tmk_core/protocol/chibios/usb_main.h
@@ -0,0 +1,139 @@
1/*
2 * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
3 *
4 * Based on the following work:
5 * - Guillaume Duc's raw hid example (MIT License)
6 * https://github.com/guiduc/usb-hid-chibios-example
7 * - PJRC Teensy examples (MIT License)
8 * https://www.pjrc.com/teensy/usb_keyboard.html
9 * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
10 * https://github.com/tmk/tmk_keyboard/
11 * - ChibiOS demo code (Apache 2.0 License)
12 * http://www.chibios.org
13 *
14 * Since some GPL'd code is used, this work is licensed under
15 * GPL v2 or later.
16 */
17
18
19#ifndef _USB_MAIN_H_
20#define _USB_MAIN_H_
21
22// TESTING
23// extern uint8_t blinkLed;
24
25#include "ch.h"
26#include "hal.h"
27
28/* -------------------------
29 * General USB driver header
30 * -------------------------
31 */
32
33/* The USB driver to use */
34#define USB_DRIVER USBD1
35
36/* Initialize the USB driver and bus */
37void init_usb_driver(USBDriver *usbp);
38
39/* Send remote wakeup packet */
40void send_remote_wakeup(USBDriver *usbp);
41
42/* ---------------
43 * Keyboard header
44 * ---------------
45 */
46
47/* main keyboard (6kro) */
48#define KBD_INTERFACE 0
49#define KBD_ENDPOINT 1
50#define KBD_EPSIZE 8
51#define KBD_REPORT_KEYS (KBD_EPSIZE - 2)
52
53/* secondary keyboard */
54#ifdef NKRO_ENABLE
55#define NKRO_INTERFACE 4
56#define NKRO_ENDPOINT 5
57#define NKRO_EPSIZE 16
58#define NKRO_REPORT_KEYS (NKRO_EPSIZE - 1)
59#endif
60
61/* extern report_keyboard_t keyboard_report_sent; */
62
63/* keyboard IN request callback handler */
64void kbd_in_cb(USBDriver *usbp, usbep_t ep);
65
66/* start-of-frame handler */
67void kbd_sof_cb(USBDriver *usbp);
68
69#ifdef NKRO_ENABLE
70/* nkro IN callback hander */
71void nkro_in_cb(USBDriver *usbp, usbep_t ep);
72#endif /* NKRO_ENABLE */
73
74/* ------------
75 * Mouse header
76 * ------------
77 */
78
79#ifdef MOUSE_ENABLE
80
81#define MOUSE_INTERFACE 1
82#define MOUSE_ENDPOINT 2
83#define MOUSE_EPSIZE 8
84
85/* mouse IN request callback handler */
86void mouse_in_cb(USBDriver *usbp, usbep_t ep);
87#endif /* MOUSE_ENABLE */
88
89/* ---------------
90 * Extrakey header
91 * ---------------
92 */
93
94#ifdef EXTRAKEY_ENABLE
95
96#define EXTRA_INTERFACE 3
97#define EXTRA_ENDPOINT 4
98#define EXTRA_EPSIZE 8
99
100/* extrakey IN request callback handler */
101void extra_in_cb(USBDriver *usbp, usbep_t ep);
102
103/* extra report structure */
104typedef struct {
105 uint8_t report_id;
106 uint16_t usage;
107} __attribute__ ((packed)) report_extra_t;
108#endif /* EXTRAKEY_ENABLE */
109
110/* --------------
111 * Console header
112 * --------------
113 */
114
115#ifdef CONSOLE_ENABLE
116
117#define CONSOLE_INTERFACE 2
118#define CONSOLE_ENDPOINT 3
119#define CONSOLE_EPSIZE 16
120
121/* Number of IN reports that can be stored inside the output queue */
122#define CONSOLE_QUEUE_CAPACITY 4
123
124/* Console flush time */
125#define CONSOLE_FLUSH_MS 50
126
127/* Putchar over the USB console */
128int8_t sendchar(uint8_t c);
129
130/* Flush output (send everything immediately) */
131void console_flush_output(void);
132
133/* console IN request callback handler */
134void console_in_cb(USBDriver *usbp, usbep_t ep);
135#endif /* CONSOLE_ENABLE */
136
137void sendchar_pf(void *p, char c);
138
139#endif /* _USB_MAIN_H_ */
diff --git a/tmk_core/readme.md b/tmk_core/readme.md
index 6b6714a6a..f460d0ed4 100644
--- a/tmk_core/readme.md
+++ b/tmk_core/readme.md
@@ -5,6 +5,16 @@ This is a keyboard firmware library with some useful features for Atmel AVR and
5Source code is available here: <https://github.com/tmk/tmk_keyboard/tree/core> 5Source code is available here: <https://github.com/tmk/tmk_keyboard/tree/core>
6 6
7 7
8Updates
9-------
10#### 2016/02/10
11flabbergast'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.
12
13#### 2015/04/22
14separated with TMK Keyboard Firmware Collection
15
16
17
8Features 18Features
9-------- 19--------
10These features can be used in your keyboard. 20These features can be used in your keyboard.
@@ -27,12 +37,6 @@ These features can be used in your keyboard.
27 37
28 38
29 39
30Updates
31-------
322015/04/22 separated with TMK Keyboard Firmware Collection
33
34
35
36TMK Keyboard Firmware Collection 40TMK Keyboard Firmware Collection
37-------------------------------- 41--------------------------------
38Complete firmwares for various keyboards and protocol converters. 42Complete firmwares for various keyboards and protocol converters.
diff --git a/tmk_core/rules.mk b/tmk_core/rules.mk
index f8f77e892..96eba24d6 100644
--- a/tmk_core/rules.mk
+++ b/tmk_core/rules.mk
@@ -20,26 +20,11 @@
20# Output format. (can be srec, ihex, binary) 20# Output format. (can be srec, ihex, binary)
21FORMAT = ihex 21FORMAT = ihex
22 22
23BUILD_DIR = .build
24
25# Object files directory
26# To put object files in current directory, use a dot (.), do NOT make
27# this an empty or blank macro!
28OBJDIR = $(BUILD_DIR)/obj_$(TARGET)
29
30
31# Optimization level, can be [0, 1, 2, 3, s]. 23# Optimization level, can be [0, 1, 2, 3, s].
32# 0 = turn off optimization. s = optimize for size. 24# 0 = turn off optimization. s = optimize for size.
33# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) 25# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
34OPT = s 26OPT = s
35 27
36
37# Debugging format.
38# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
39# AVR Studio 4.10 requires dwarf-2.
40# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
41DEBUG = dwarf-2
42
43COLOR ?= true 28COLOR ?= true
44 29
45ifeq ($(COLOR),true) 30ifeq ($(COLOR),true)
@@ -87,7 +72,7 @@ BUILD_CMD = LOG=$$($(CMD) 2>&1) ; if [ $$? -gt 0 ]; then $(PRINT_ERROR); elif [
87# Each directory must be seperated by a space. 72# Each directory must be seperated by a space.
88# Use forward slashes for directory separators. 73# Use forward slashes for directory separators.
89# For a directory that has spaces, enclose it in quotes. 74# For a directory that has spaces, enclose it in quotes.
90EXTRAINCDIRS = $(subst :, ,$(VPATH)) 75EXTRAINCDIRS += $(subst :, ,$(VPATH))
91 76
92 77
93# Compiler flag to set the C Standard level. 78# Compiler flag to set the C Standard level.
@@ -99,17 +84,14 @@ CSTANDARD = -std=gnu99
99 84
100 85
101# Place -D or -U options here for C sources 86# Place -D or -U options here for C sources
102CDEFS = -DF_CPU=$(F_CPU)UL
103CDEFS += $(OPT_DEFS) 87CDEFS += $(OPT_DEFS)
104 88
105 89
106# Place -D or -U options here for ASM sources 90# Place -D or -U options here for ASM sources
107ADEFS = -DF_CPU=$(F_CPU)
108ADEFS += $(OPT_DEFS) 91ADEFS += $(OPT_DEFS)
109 92
110 93
111# Place -D or -U options here for C++ sources 94# Place -D or -U options here for C++ sources
112CPPDEFS = -DF_CPU=$(F_CPU)UL
113#CPPDEFS += -D__STDC_LIMIT_MACROS 95#CPPDEFS += -D__STDC_LIMIT_MACROS
114#CPPDEFS += -D__STDC_CONSTANT_MACROS 96#CPPDEFS += -D__STDC_CONSTANT_MACROS
115CPPDEFS += $(OPT_DEFS) 97CPPDEFS += $(OPT_DEFS)
@@ -123,17 +105,9 @@ CPPDEFS += $(OPT_DEFS)
123# -Wall...: warning level 105# -Wall...: warning level
124# -Wa,...: tell GCC to pass this to the assembler. 106# -Wa,...: tell GCC to pass this to the assembler.
125# -adhlns...: create assembler listing 107# -adhlns...: create assembler listing
126CFLAGS = -g$(DEBUG) 108CFLAGS += -g$(DEBUG)
127CFLAGS += $(CDEFS) 109CFLAGS += $(CDEFS)
128CFLAGS += -O$(OPT) 110CFLAGS += -O$(OPT)
129CFLAGS += -funsigned-char
130CFLAGS += -funsigned-bitfields
131CFLAGS += -ffunction-sections
132CFLAGS += -fdata-sections
133CFLAGS += -fno-inline-small-functions
134CFLAGS += -fpack-struct
135CFLAGS += -fshort-enums
136CFLAGS += -fno-strict-aliasing
137# add color 111# add color
138ifeq ($(COLOR),true) 112ifeq ($(COLOR),true)
139ifeq ("$(shell echo "int main(){}" | $(CC) -fdiagnostics-color -x c - -o /dev/null 2>&1)", "") 113ifeq ("$(shell echo "int main(){}" | $(CC) -fdiagnostics-color -x c - -o /dev/null 2>&1)", "")
@@ -162,16 +136,9 @@ endif
162# -Wall...: warning level 136# -Wall...: warning level
163# -Wa,...: tell GCC to pass this to the assembler. 137# -Wa,...: tell GCC to pass this to the assembler.
164# -adhlns...: create assembler listing 138# -adhlns...: create assembler listing
165CPPFLAGS = -g$(DEBUG) 139CPPFLAGS += -g$(DEBUG)
166CPPFLAGS += $(CPPDEFS) 140CPPFLAGS += $(CPPDEFS)
167CPPFLAGS += -O$(OPT) 141CPPFLAGS += -O$(OPT)
168CPPFLAGS += -funsigned-char
169CPPFLAGS += -funsigned-bitfields
170CPPFLAGS += -fpack-struct
171CPPFLAGS += -fshort-enums
172CPPFLAGS += -fno-exceptions
173CPPFLAGS += -ffunction-sections
174CPPFLAGS += -fdata-sections
175# to supress "warning: only initialized variables can be placed into program memory area" 142# to supress "warning: only initialized variables can be placed into program memory area"
176CPPFLAGS += -w 143CPPFLAGS += -w
177CPPFLAGS += -Wall 144CPPFLAGS += -Wall
@@ -198,7 +165,7 @@ endif
198# files -- see avr-libc docs [FIXME: not yet described there] 165# files -- see avr-libc docs [FIXME: not yet described there]
199# -listing-cont-lines: Sets the maximum number of continuation lines of hex 166# -listing-cont-lines: Sets the maximum number of continuation lines of hex
200# dump that will be displayed for a given single line of source input. 167# dump that will be displayed for a given single line of source input.
201ASFLAGS = $(ADEFS) -Wa,-adhlns=$(@:%.o=%.lst),-gstabs,--listing-cont-lines=100 168ASFLAGS += $(ADEFS) -Wa,-adhlns=$(@:%.o=%.lst),-gstabs,--listing-cont-lines=100
202ASFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) 169ASFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
203ifdef CONFIG_H 170ifdef CONFIG_H
204 ASFLAGS += -include $(CONFIG_H) 171 ASFLAGS += -include $(CONFIG_H)
@@ -232,28 +199,6 @@ SCANF_LIB =
232MATH_LIB = -lm 199MATH_LIB = -lm
233 200
234 201
235# List any extra directories to look for libraries here.
236# Each directory must be seperated by a space.
237# Use forward slashes for directory separators.
238# For a directory that has spaces, enclose it in quotes.
239EXTRALIBDIRS =
240
241
242
243#---------------- External Memory Options ----------------
244
245# 64 KB of external RAM, starting after internal RAM (ATmega128!),
246# used for variables (.data/.bss) and heap (malloc()).
247#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
248
249# 64 KB of external RAM, starting after internal RAM (ATmega128!),
250# only used for heap (malloc()).
251#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
252
253EXTMEMOPTS =
254
255
256
257#---------------- Linker Options ---------------- 202#---------------- Linker Options ----------------
258# -Wl,...: tell GCC to pass this to linker. 203# -Wl,...: tell GCC to pass this to linker.
259# -Map: create map file 204# -Map: create map file
@@ -262,9 +207,8 @@ EXTMEMOPTS =
262# Comennt out "--relax" option to avoid a error such: 207# Comennt out "--relax" option to avoid a error such:
263# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12' 208# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
264# 209#
265LDFLAGS = -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref 210LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
266#LDFLAGS += -Wl,--relax 211#LDFLAGS += -Wl,--relax
267LDFLAGS += -Wl,--gc-sections
268LDFLAGS += $(EXTMEMOPTS) 212LDFLAGS += $(EXTMEMOPTS)
269LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) 213LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
270LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) 214LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
@@ -272,59 +216,13 @@ LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
272# You can give EXTRALDFLAGS at 'make' command line. 216# You can give EXTRALDFLAGS at 'make' command line.
273LDFLAGS += $(EXTRALDFLAGS) 217LDFLAGS += $(EXTRALDFLAGS)
274 218
275
276
277#---------------- Debugging Options ----------------
278
279# For simulavr only - target MCU frequency.
280DEBUG_MFREQ = $(F_CPU)
281
282# Set the DEBUG_UI to either gdb or insight.
283# DEBUG_UI = gdb
284DEBUG_UI = insight
285
286# Set the debugging back-end to either avarice, simulavr.
287DEBUG_BACKEND = avarice
288#DEBUG_BACKEND = simulavr
289
290# GDB Init Filename.
291GDBINIT_FILE = __avr_gdbinit
292
293# When using avarice settings for the JTAG
294JTAG_DEV = /dev/com1
295
296# Debugging port used to communicate between GDB / avarice / simulavr.
297DEBUG_PORT = 4242
298
299# Debugging host used to communicate between GDB / avarice / simulavr, normally
300# just set to localhost unless doing some sort of crazy debugging when
301# avarice is running on a different computer.
302DEBUG_HOST = localhost
303
304
305
306#============================================================================
307
308
309# Define programs and commands. 219# Define programs and commands.
310SHELL = sh 220SHELL = sh
311CC = avr-gcc
312OBJCOPY = avr-objcopy
313OBJDUMP = avr-objdump
314SIZE = avr-size
315AR = avr-ar rcs
316NM = avr-nm
317REMOVE = rm -f 221REMOVE = rm -f
318REMOVEDIR = rmdir 222REMOVEDIR = rmdir
319COPY = cp 223COPY = cp
320WINSHELL = cmd 224WINSHELL = cmd
321SECHO = $(SILENT) || echo 225SECHO = $(SILENT) || echo
322# Autodecct teensy loader
323ifneq (, $(shell which teensy-loader-cli 2>/dev/null))
324 TEENSY_LOADER_CLI = teensy-loader-cli
325else
326 TEENSY_LOADER_CLI = teensy_loader_cli
327endif
328 226
329# Define Messages 227# Define Messages
330# English 228# English
@@ -347,8 +245,6 @@ MSG_CLEANING = Cleaning project:
347MSG_CREATING_LIBRARY = Creating library: 245MSG_CREATING_LIBRARY = Creating library:
348 246
349 247
350
351
352# Define all object files. 248# Define all object files.
353OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(patsubst %.cpp,$(OBJDIR)/%.o,$(patsubst %.S,$(OBJDIR)/%.o,$(SRC)))) 249OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(patsubst %.cpp,$(OBJDIR)/%.o,$(patsubst %.S,$(OBJDIR)/%.o,$(SRC))))
354 250
@@ -364,9 +260,9 @@ GENDEPFLAGS = -MMD -MP -MF $(BUILD_DIR)/.dep/$(subst /,_,$@).d
364# Combine all necessary flags and optional flags. 260# Combine all necessary flags and optional flags.
365# Add target processor to flags. 261# Add target processor to flags.
366# You can give extra flags at 'make' command line like: make EXTRAFLAGS=-DFOO=bar 262# You can give extra flags at 'make' command line like: make EXTRAFLAGS=-DFOO=bar
367ALL_CFLAGS = -mmcu=$(MCU) $(CFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS) 263ALL_CFLAGS = $(MCUFLAGS) $(CFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS)
368ALL_CPPFLAGS = -mmcu=$(MCU) -x c++ $(CPPFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS) 264ALL_CPPFLAGS = $(MCUFLAGS) -x c++ $(CPPFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS)
369ALL_ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS) 265ALL_ASFLAGS = $(MCUFLAGS) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS)
370 266
371# Default target. 267# Default target.
372all: 268all:
@@ -432,104 +328,10 @@ sizeafter:
432gccversion : 328gccversion :
433 @$(SILENT) || $(CC) --version 329 @$(SILENT) || $(CC) --version
434 330
435
436
437# Program the device.
438program: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep
439 $(PROGRAM_CMD)
440
441teensy: $(BUILD_DIR)/$(TARGET).hex
442 $(TEENSY_LOADER_CLI) -mmcu=$(MCU) -w -v $(BUILD_DIR)/$(TARGET).hex
443
444flip: $(BUILD_DIR)/$(TARGET).hex
445 batchisp -hardware usb -device $(MCU) -operation erase f
446 batchisp -hardware usb -device $(MCU) -operation loadbuffer $(BUILD_DIR)/$(TARGET).hex program
447 batchisp -hardware usb -device $(MCU) -operation start reset 0
448
449dfu: $(BUILD_DIR)/$(TARGET).hex sizeafter
450ifneq (, $(findstring 0.7, $(shell dfu-programmer --version 2>&1)))
451 dfu-programmer $(MCU) erase --force
452else
453 dfu-programmer $(MCU) erase
454endif
455 dfu-programmer $(MCU) flash $(BUILD_DIR)/$(TARGET).hex
456 dfu-programmer $(MCU) reset
457
458dfu-start:
459 dfu-programmer $(MCU) reset
460 dfu-programmer $(MCU) start
461
462flip-ee: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep
463 $(COPY) $(BUILD_DIR)/$(TARGET).eep $(BUILD_DIR)/$(TARGET)eep.hex
464 batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase
465 batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(BUILD_DIR)/$(TARGET)eep.hex program
466 batchisp -hardware usb -device $(MCU) -operation start reset 0
467 $(REMOVE) $(BUILD_DIR)/$(TARGET)eep.hex
468
469dfu-ee: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep
470ifneq (, $(findstring 0.7, $(shell dfu-programmer --version 2>&1)))
471 dfu-programmer $(MCU) flash --eeprom $(BUILD_DIR)/$(TARGET).eep
472else
473 dfu-programmer $(MCU) flash-eeprom $(BUILD_DIR)/$(TARGET).eep
474endif
475 dfu-programmer $(MCU) reset
476
477
478# Generate avr-gdb config/init file which does the following:
479# define the reset signal, load the target file, connect to target, and set
480# a breakpoint at main().
481gdb-config:
482 @$(REMOVE) $(GDBINIT_FILE)
483 @echo define reset >> $(GDBINIT_FILE)
484 @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
485 @echo end >> $(GDBINIT_FILE)
486 @echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE)
487 @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
488ifeq ($(DEBUG_BACKEND),simulavr)
489 @echo load >> $(GDBINIT_FILE)
490endif
491 @echo break main >> $(GDBINIT_FILE)
492
493debug: gdb-config $(BUILD_DIR)/$(TARGET).elf
494ifeq ($(DEBUG_BACKEND), avarice)
495 @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
496 @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
497 $(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
498 @$(WINSHELL) /c pause
499
500else
501 @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
502 $(DEBUG_MFREQ) --port $(DEBUG_PORT)
503endif
504 @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
505
506
507
508
509# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
510COFFCONVERT = $(OBJCOPY) --debugging
511COFFCONVERT += --change-section-address .data-0x800000
512COFFCONVERT += --change-section-address .bss-0x800000
513COFFCONVERT += --change-section-address .noinit-0x800000
514COFFCONVERT += --change-section-address .eeprom-0x810000
515
516
517
518coff: $(BUILD_DIR)/$(TARGET).elf
519 @$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof
520 $(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof
521
522
523extcoff: $(BUILD_DIR)/$(TARGET).elf
524 @$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof
525 $(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof
526
527
528
529# Create final output files (.hex, .eep) from ELF output file. 331# Create final output files (.hex, .eep) from ELF output file.
530%.hex: %.elf 332%.hex: %.elf
531 @$(SILENT) || printf "$(MSG_FLASH) $@" | $(AWK_CMD) 333 @$(SILENT) || printf "$(MSG_FLASH) $@" | $(AWK_CMD)
532 $(eval CMD=$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@) 334 $(eval CMD=$(HEX) $< $@)
533 @$(BUILD_CMD) 335 @$(BUILD_CMD)
534 @if $(AUTOGEN); then \ 336 @if $(AUTOGEN); then \
535 $(SILENT) || printf "Copying $(TARGET).hex to keymaps/$(KEYMAP)/$(KEYBOARD)_$(KEYMAP).hex\n"; \ 337 $(SILENT) || printf "Copying $(TARGET).hex to keymaps/$(KEYMAP)/$(KEYBOARD)_$(KEYMAP).hex\n"; \
@@ -540,7 +342,7 @@ extcoff: $(BUILD_DIR)/$(TARGET).elf
540 342
541%.eep: %.elf 343%.eep: %.elf
542 @$(SILENT) || printf "$(MSG_EEPROM) $@" | $(AWK_CMD) 344 @$(SILENT) || printf "$(MSG_EEPROM) $@" | $(AWK_CMD)
543 $(eval CMD=$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0) 345 $(eval CMD=$(EEP) $< $@ || exit 0)
544 @$(BUILD_CMD) 346 @$(BUILD_CMD)
545 347
546# Create extended listing file from ELF output file. 348# Create extended listing file from ELF output file.
@@ -622,7 +424,7 @@ show_path:
622 @echo VPATH=$(VPATH) 424 @echo VPATH=$(VPATH)
623 @echo SRC=$(SRC) 425 @echo SRC=$(SRC)
624 426
625SUBDIRS := $(filter-out %/util/ %/doc/ %/keymaps/ %/old_keymap_files/,$(dir $(wildcard $(TOP_DIR)/keyboards/**/*/.))) 427SUBDIRS := $(filter-out %/util/ %/doc/ %/keymaps/ %/old_keymap_files/,$(dir $(wildcard $(TOP_DIR)/keyboards/**/*/Makefile)))
626SUBDIRS := $(SUBDIRS) $(dir $(wildcard $(TOP_DIR)/keyboards/*/.)) 428SUBDIRS := $(SUBDIRS) $(dir $(wildcard $(TOP_DIR)/keyboards/*/.))
627SUBDIRS := $(sort $(SUBDIRS)) 429SUBDIRS := $(sort $(SUBDIRS))
628# $(error $(SUBDIRS)) 430# $(error $(SUBDIRS))
diff --git a/tmk_core/tool/chibios/.gitignore b/tmk_core/tool/chibios/.gitignore
new file mode 100644
index 000000000..88bbafe34
--- /dev/null
+++ b/tmk_core/tool/chibios/.gitignore
@@ -0,0 +1,2 @@
1chibios
2chibios-contrib
diff --git a/tmk_core/tool/chibios/ch-bootloader-jump.patch b/tmk_core/tool/chibios/ch-bootloader-jump.patch
new file mode 100644
index 000000000..d88657621
--- /dev/null
+++ b/tmk_core/tool/chibios/ch-bootloader-jump.patch
@@ -0,0 +1,116 @@
1diff --git a/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s b/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s
2index 51a79bb..42d07bd 100644
3--- a/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s
4+++ b/os/common/ports/ARMCMx/compilers/GCC/crt0_v6m.s
5@@ -105,6 +105,13 @@
6 #define CRT0_CALL_DESTRUCTORS TRUE
7 #endif
8
9+/**
10+ * @brief Magic number for jumping to bootloader.
11+ */
12+#if !defined(MAGIC_BOOTLOADER_NUMBER) || defined(__DOXYGEN__)
13+#define MAGIC_BOOTLOADER_NUMBER 0xDEADBEEF
14+#endif
15+
16 /*===========================================================================*/
17 /* Code section. */
18 /*===========================================================================*/
19@@ -124,6 +131,17 @@
20 .thumb_func
21 .global Reset_Handler
22 Reset_Handler:
23+
24+#ifdef STM32_BOOTLOADER_ADDRESS
25+ /* jump to bootloader code */
26+ ldr r0, =__ram0_end__-4
27+ ldr r1, =MAGIC_BOOTLOADER_NUMBER
28+ ldr r2, [r0, #0]
29+ str r0, [r0, #0] /* erase stored magic */
30+ cmp r2, r1
31+ beq Bootloader_Jump
32+#endif /* STM32_BOOTLOADER_ADDRESS */
33+
34 /* Interrupts are globally masked initially.*/
35 cpsid i
36
37@@ -242,6 +260,21 @@ endfiniloop:
38 ldr r1, =__default_exit
39 bx r1
40
41+#ifdef STM32_BOOTLOADER_ADDRESS
42+/*
43+ * Jump-to-bootloader function.
44+ */
45+
46+ .align 2
47+ .thumb_func
48+Bootloader_Jump:
49+ ldr r0, =STM32_BOOTLOADER_ADDRESS
50+ ldr r1, [r0, #0]
51+ mov sp, r1
52+ ldr r0, [r0, #4]
53+ bx r0
54+#endif /* STM32_BOOTLOADER_ADDRESS */
55+
56 #endif
57
58 /** @} */
59diff --git a/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s b/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s
60index 4812a29..dca9f88 100644
61--- a/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s
62+++ b/os/common/ports/ARMCMx/compilers/GCC/crt0_v7m.s
63@@ -140,6 +140,13 @@
64 #define CRT0_CPACR_INIT 0x00F00000
65 #endif
66
67+/**
68+ * @brief Magic number for jumping to bootloader.
69+ */
70+#if !defined(MAGIC_BOOTLOADER_NUMBER) || defined(__DOXYGEN__)
71+#define MAGIC_BOOTLOADER_NUMBER 0xDEADBEEF
72+#endif
73+
74 /*===========================================================================*/
75 /* Code section. */
76 /*===========================================================================*/
77@@ -164,6 +171,17 @@
78 .thumb_func
79 .global Reset_Handler
80 Reset_Handler:
81+
82+#ifdef STM32_BOOTLOADER_ADDRESS
83+ /* jump to bootloader code */
84+ ldr r0, =__ram0_end__-4
85+ ldr r1, =MAGIC_BOOTLOADER_NUMBER
86+ ldr r2, [r0, #0]
87+ str r0, [r0, #0] /* erase stored magic */
88+ cmp r2, r1
89+ beq Bootloader_Jump
90+#endif /* STM32_BOOTLOADER_ADDRESS */
91+
92 /* Interrupts are globally masked initially.*/
93 cpsid i
94
95@@ -305,6 +323,21 @@ endfiniloop:
96 /* Branching to the defined exit handler.*/
97 b __default_exit
98
99+#ifdef STM32_BOOTLOADER_ADDRESS
100+/*
101+ * Jump-to-bootloader function.
102+ */
103+
104+ .align 2
105+ .thumb_func
106+Bootloader_Jump:
107+ ldr r0, =STM32_BOOTLOADER_ADDRESS
108+ ldr r1, [r0, #0]
109+ mov sp, r1
110+ ldr r0, [r0, #4]
111+ bx r0
112+#endif /* STM32_BOOTLOADER_ADDRESS */
113+
114 #endif /* !defined(__DOXYGEN__) */
115
116 /** @} */