summaryrefslogtreecommitdiffstats
path: root/tmk_core/protocol/chibios
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/protocol/chibios')
-rw-r--r--tmk_core/protocol/chibios/README.md55
-rw-r--r--tmk_core/protocol/chibios/main.c186
-rw-r--r--tmk_core/protocol/chibios/usb_main.c1375
-rw-r--r--tmk_core/protocol/chibios/usb_main.h139
4 files changed, 1755 insertions, 0 deletions
diff --git a/tmk_core/protocol/chibios/README.md b/tmk_core/protocol/chibios/README.md
new file mode 100644
index 0000000000..63e6641f82
--- /dev/null
+++ b/tmk_core/protocol/chibios/README.md
@@ -0,0 +1,55 @@
+## TMK running on top of ChibiOS
+
+This 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.
+
+### Usage
+
+- 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.
+- 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`.
+- 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.
+
+### Notes
+
+- 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).
+- 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.
+- For debugging, it is sometimes useful disable gcc optimisations, you can do that by adding `-O0` to `OPT_DEFS` in your `Makefile`.
+- 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.
+- It is easy to add some code for testing (e.g. blink LED, do stuff on button press, etc...) - just create another thread in `main.c`, it will run independently of the keyboard business.
+- Jumping to (the built-in) bootloaders on STM32 works, but it is not entirely pleasant, since it is very much MCU dependent. So, one needs to dig out the right address to jump to, and either pass it to the compiler in the `Makefile`, or better, define it in `<your_kb>/bootloader_defs.h`. 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.
+
+
+### Immediate todo
+
+- power saving for suspend
+
+### Not tested, but possibly working
+
+- backlight
+
+### Missing / not working (TMK vs ChibiOS bits)
+
+- eeprom / bootmagic for STM32 (will be chip dependent; eeprom needs to be emulated in flash, which means less writes; wear-levelling?) There is a semi-official ST "driver" for eeprom, with wear-levelling, but I think it consumes a lot of RAM (like 2 pages, i.e. 1kB or so).
+
+### Tried with
+
+- Infinity, WhiteFox keyboards
+- all ARM-based Teensies
+- some STM32-based boards (e.g. ST-F072RB-DISCOVERY board, STM32F042 breakout board, Maple Mini (STM32F103-based))
+
+## ChibiOS-supported MCUs
+
+- Pretty much all STM32 chips.
+- 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.
+- 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.
+- 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.
+
+## STM32-based keyboard design considerations
+
+- STM32F0x2 chips can do crystal-less USB, but they still need a 3.3V voltage regulator.
+- The BOOT0 pin should be tied to GND.
+- For a hardware way of accessing the in-built DFU bootloader, in addition to the reset button, put another button between the BOOT0 pin and 3V3.
+- 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.
+
+
+
+[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 0000000000..b0eb9aef81
--- /dev/null
+++ b/tmk_core/protocol/chibios/main.c
@@ -0,0 +1,186 @@
+/*
+ * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
+ *
+ * Based on the following work:
+ * - Guillaume Duc's raw hid example (MIT License)
+ * https://github.com/guiduc/usb-hid-chibios-example
+ * - PJRC Teensy examples (MIT License)
+ * https://www.pjrc.com/teensy/usb_keyboard.html
+ * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
+ * https://github.com/tmk/tmk_keyboard/
+ * - ChibiOS demo code (Apache 2.0 License)
+ * http://www.chibios.org
+ *
+ * Since some GPL'd code is used, this work is licensed under
+ * GPL v2 or later.
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "usb_main.h"
+
+/* TMK includes */
+#include "report.h"
+#include "host.h"
+#include "host_driver.h"
+#include "keyboard.h"
+#include "action.h"
+#include "action_util.h"
+#include "mousekey.h"
+#include "led.h"
+#include "sendchar.h"
+#include "debug.h"
+#include "printf.h"
+#ifdef SLEEP_LED_ENABLE
+#include "sleep_led.h"
+#endif
+#ifdef SERIAL_LINK_ENABLE
+#include "serial_link/system/serial_link.h"
+#endif
+#ifdef VISUALIZER_ENABLE
+#include "visualizer/visualizer.h"
+#endif
+#include "suspend.h"
+
+
+/* -------------------------
+ * TMK host driver defs
+ * -------------------------
+ */
+
+/* declarations */
+uint8_t keyboard_leds(void);
+void send_keyboard(report_keyboard_t *report);
+void send_mouse(report_mouse_t *report);
+void send_system(uint16_t data);
+void send_consumer(uint16_t data);
+
+/* host struct */
+host_driver_t chibios_driver = {
+ keyboard_leds,
+ send_keyboard,
+ send_mouse,
+ send_system,
+ send_consumer
+};
+
+
+/* TESTING
+ * Amber LED blinker thread, times are in milliseconds.
+ */
+/* set this variable to non-zero anywhere to blink once */
+// uint8_t blinkLed = 0;
+// static THD_WORKING_AREA(waBlinkerThread, 128);
+// static THD_FUNCTION(blinkerThread, arg) {
+// (void)arg;
+// chRegSetThreadName("blinkOrange");
+// while(true) {
+// if(blinkLed) {
+// blinkLed = 0;
+// palSetPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
+// chThdSleepMilliseconds(100);
+// palClearPad(TEENSY_PIN13_IOPORT, TEENSY_PIN13);
+// }
+// chThdSleepMilliseconds(100);
+// }
+// }
+
+
+
+/* Main thread
+ */
+int main(void) {
+ /* ChibiOS/RT init */
+ halInit();
+ chSysInit();
+
+ // TESTING
+ // chThdCreateStatic(waBlinkerThread, sizeof(waBlinkerThread), NORMALPRIO, blinkerThread, NULL);
+
+ /* Init USB */
+ init_usb_driver(&USB_DRIVER);
+
+ /* init printf */
+ init_printf(NULL,sendchar_pf);
+
+#ifdef SERIAL_LINK_ENABLE
+ init_serial_link();
+#endif
+
+#ifdef VISUALIZER_ENABLE
+ visualizer_init();
+#endif
+
+
+ host_driver_t* driver = NULL;
+
+ /* Wait until the USB or serial link is active */
+ while (true) {
+ if(USB_DRIVER.state == USB_ACTIVE) {
+ driver = &chibios_driver;
+ break;
+ }
+#ifdef SERIAL_LINK_ENABLE
+ if(is_serial_link_connected()) {
+ driver = get_serial_link_driver();
+ break;
+ }
+ serial_link_update();
+#endif
+ chThdSleepMilliseconds(50);
+ }
+
+ /* Do need to wait here!
+ * Otherwise the next print might start a transfer on console EP
+ * before the USB is completely ready, which sometimes causes
+ * HardFaults.
+ */
+ chThdSleepMilliseconds(50);
+
+ print("USB configured.\n");
+
+ /* init TMK modules */
+ keyboard_init();
+ host_set_driver(driver);
+
+#ifdef SLEEP_LED_ENABLE
+ sleep_led_init();
+#endif
+
+ print("Keyboard start.\n");
+
+ /* Main loop */
+ while(true) {
+
+ if(USB_DRIVER.state == USB_SUSPENDED) {
+ print("[s]");
+#ifdef VISUALIZER_ENABLE
+ visualizer_suspend();
+#endif
+ while(USB_DRIVER.state == USB_SUSPENDED) {
+ /* Do this in the suspended state */
+#ifdef SERIAL_LINK_ENABLE
+ serial_link_update();
+#endif
+ suspend_power_down(); // on AVR this deep sleeps for 15ms
+ /* Remote wakeup */
+ if((USB_DRIVER.status & 2) && suspend_wakeup_condition()) {
+ send_remote_wakeup(&USB_DRIVER);
+ }
+ }
+ /* Woken up */
+ // variables has been already cleared by the wakeup hook
+ send_keyboard_report();
+#ifdef MOUSEKEY_ENABLE
+ mousekey_send();
+#endif /* MOUSEKEY_ENABLE */
+
+#ifdef VISUALIZER_ENABLE
+ visualizer_resume();
+#endif
+ }
+
+ keyboard_task();
+ }
+}
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
new file mode 100644
index 0000000000..d0c72c46c7
--- /dev/null
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -0,0 +1,1375 @@
+/*
+ * (c) 2015 flabberast <s3+flabbergast@sdfeu.org>
+ *
+ * Based on the following work:
+ * - Guillaume Duc's raw hid example (MIT License)
+ * https://github.com/guiduc/usb-hid-chibios-example
+ * - PJRC Teensy examples (MIT License)
+ * https://www.pjrc.com/teensy/usb_keyboard.html
+ * - hasu's TMK keyboard code (GPL v2 and some code Modified BSD)
+ * https://github.com/tmk/tmk_keyboard/
+ * - ChibiOS demo code (Apache 2.0 License)
+ * http://www.chibios.org
+ *
+ * Since some GPL'd code is used, this work is licensed under
+ * GPL v2 or later.
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "usb_main.h"
+
+#include "host.h"
+#include "debug.h"
+#include "suspend.h"
+#ifdef SLEEP_LED_ENABLE
+#include "sleep_led.h"
+#include "led.h"
+#endif
+
+#ifdef NKRO_ENABLE
+ #include "keycode_config.h"
+
+ extern keymap_config_t keymap_config;
+#endif
+
+/* ---------------------------------------------------------
+ * Global interface variables and declarations
+ * ---------------------------------------------------------
+ */
+
+uint8_t keyboard_idle __attribute__((aligned(2))) = 0;
+uint8_t keyboard_protocol __attribute__((aligned(2))) = 1;
+uint16_t keyboard_led_stats __attribute__((aligned(2))) = 0;
+volatile uint16_t keyboard_idle_count = 0;
+static virtual_timer_t keyboard_idle_timer;
+static void keyboard_idle_timer_cb(void *arg);
+
+report_keyboard_t keyboard_report_sent = {{0}};
+#ifdef MOUSE_ENABLE
+report_mouse_t mouse_report_blank = {0};
+#endif /* MOUSE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+uint8_t extra_report_blank[3] = {0};
+#endif /* EXTRAKEY_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+/* The emission buffers queue */
+output_buffers_queue_t console_buf_queue;
+static uint8_t console_queue_buffer[BQ_BUFFER_SIZE(CONSOLE_QUEUE_CAPACITY, CONSOLE_EPSIZE)];
+
+static virtual_timer_t console_flush_timer;
+void console_queue_onotify(io_buffers_queue_t *bqp);
+static void console_flush_cb(void *arg);
+#endif /* CONSOLE_ENABLE */
+
+/* ---------------------------------------------------------
+ * Descriptors and USB driver objects
+ * ---------------------------------------------------------
+ */
+
+/* HID specific constants */
+#define USB_DESCRIPTOR_HID 0x21
+#define USB_DESCRIPTOR_HID_REPORT 0x22
+#define HID_GET_REPORT 0x01
+#define HID_GET_IDLE 0x02
+#define HID_GET_PROTOCOL 0x03
+#define HID_SET_REPORT 0x09
+#define HID_SET_IDLE 0x0A
+#define HID_SET_PROTOCOL 0x0B
+
+/* USB Device Descriptor */
+static const uint8_t usb_device_descriptor_data[] = {
+ USB_DESC_DEVICE(0x0200, // bcdUSB (1.1)
+ 0, // bDeviceClass (defined in later in interface)
+ 0, // bDeviceSubClass
+ 0, // bDeviceProtocol
+ 64, // bMaxPacketSize (64 bytes) (the driver didn't work with 32)
+ VENDOR_ID, // idVendor
+ PRODUCT_ID, // idProduct
+ DEVICE_VER, // bcdDevice
+ 1, // iManufacturer
+ 2, // iProduct
+ 3, // iSerialNumber
+ 1) // bNumConfigurations
+};
+
+/* Device Descriptor wrapper */
+static const USBDescriptor usb_device_descriptor = {
+ sizeof usb_device_descriptor_data,
+ usb_device_descriptor_data
+};
+
+/*
+ * HID Report Descriptor
+ *
+ * See "Device Class Definition for Human Interface Devices (HID)"
+ * (http://www.usb.org/developers/hidpage/HID1_11.pdf) for the
+ * detailed descrition of all the fields
+ */
+
+/* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */
+static const uint8_t keyboard_hid_report_desc_data[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x06, // Usage (Keyboard),
+ 0xA1, 0x01, // Collection (Application),
+ 0x75, 0x01, // Report Size (1),
+ 0x95, 0x08, // Report Count (8),
+ 0x05, 0x07, // Usage Page (Key Codes),
+ 0x19, 0xE0, // Usage Minimum (224),
+ 0x29, 0xE7, // Usage Maximum (231),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x01, // Logical Maximum (1),
+ 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
+ 0x95, 0x01, // Report Count (1),
+ 0x75, 0x08, // Report Size (8),
+ 0x81, 0x03, // Input (Constant), ;Reserved byte
+ 0x95, 0x05, // Report Count (5),
+ 0x75, 0x01, // Report Size (1),
+ 0x05, 0x08, // Usage Page (LEDs),
+ 0x19, 0x01, // Usage Minimum (1),
+ 0x29, 0x05, // Usage Maximum (5),
+ 0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
+ 0x95, 0x01, // Report Count (1),
+ 0x75, 0x03, // Report Size (3),
+ 0x91, 0x03, // Output (Constant), ;LED report padding
+ 0x95, KBD_REPORT_KEYS, // Report Count (),
+ 0x75, 0x08, // Report Size (8),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0xFF, // Logical Maximum(255),
+ 0x05, 0x07, // Usage Page (Key Codes),
+ 0x19, 0x00, // Usage Minimum (0),
+ 0x29, 0xFF, // Usage Maximum (255),
+ 0x81, 0x00, // Input (Data, Array),
+ 0xc0 // End Collection
+};
+/* wrapper */
+static const USBDescriptor keyboard_hid_report_descriptor = {
+ sizeof keyboard_hid_report_desc_data,
+ keyboard_hid_report_desc_data
+};
+
+#ifdef NKRO_ENABLE
+static const uint8_t nkro_hid_report_desc_data[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop),
+ 0x09, 0x06, // Usage (Keyboard),
+ 0xA1, 0x01, // Collection (Application),
+ // bitmap of modifiers
+ 0x75, 0x01, // Report Size (1),
+ 0x95, 0x08, // Report Count (8),
+ 0x05, 0x07, // Usage Page (Key Codes),
+ 0x19, 0xE0, // Usage Minimum (224),
+ 0x29, 0xE7, // Usage Maximum (231),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x01, // Logical Maximum (1),
+ 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
+ // LED output report
+ 0x95, 0x05, // Report Count (5),
+ 0x75, 0x01, // Report Size (1),
+ 0x05, 0x08, // Usage Page (LEDs),
+ 0x19, 0x01, // Usage Minimum (1),
+ 0x29, 0x05, // Usage Maximum (5),
+ 0x91, 0x02, // Output (Data, Variable, Absolute),
+ 0x95, 0x01, // Report Count (1),
+ 0x75, 0x03, // Report Size (3),
+ 0x91, 0x03, // Output (Constant),
+ // bitmap of keys
+ 0x95, NKRO_REPORT_KEYS * 8, // Report Count (),
+ 0x75, 0x01, // Report Size (1),
+ 0x15, 0x00, // Logical Minimum (0),
+ 0x25, 0x01, // Logical Maximum(1),
+ 0x05, 0x07, // Usage Page (Key Codes),
+ 0x19, 0x00, // Usage Minimum (0),
+ 0x29, NKRO_REPORT_KEYS * 8 - 1, // Usage Maximum (),
+ 0x81, 0x02, // Input (Data, Variable, Absolute),
+ 0xc0 // End Collection
+};
+/* wrapper */
+static const USBDescriptor nkro_hid_report_descriptor = {
+ sizeof nkro_hid_report_desc_data,
+ nkro_hid_report_desc_data
+};
+#endif /* NKRO_ENABLE */
+
+#ifdef MOUSE_ENABLE
+/* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
+ * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
+ * http://www.keil.com/forum/15671/
+ * http://www.microsoft.com/whdc/device/input/wheel.mspx */
+static const uint8_t mouse_hid_report_desc_data[] = {
+ /* mouse */
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x02, // USAGE (Mouse)
+ 0xa1, 0x01, // COLLECTION (Application)
+ //0x85, REPORT_ID_MOUSE, // REPORT_ID (1)
+ 0x09, 0x01, // USAGE (Pointer)
+ 0xa1, 0x00, // COLLECTION (Physical)
+ // ---------------------------- Buttons
+ 0x05, 0x09, // USAGE_PAGE (Button)
+ 0x19, 0x01, // USAGE_MINIMUM (Button 1)
+ 0x29, 0x05, // USAGE_MAXIMUM (Button 5)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x95, 0x05, // REPORT_COUNT (5)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0x75, 0x03, // REPORT_SIZE (3)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x03, // INPUT (Cnst,Var,Abs)
+ // ---------------------------- X,Y position
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x30, // USAGE (X)
+ 0x09, 0x31, // USAGE (Y)
+ 0x15, 0x81, // LOGICAL_MINIMUM (-127)
+ 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x95, 0x02, // REPORT_COUNT (2)
+ 0x81, 0x06, // INPUT (Data,Var,Rel)
+ // ---------------------------- Vertical wheel
+ 0x09, 0x38, // USAGE (Wheel)
+ 0x15, 0x81, // LOGICAL_MINIMUM (-127)
+ 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
+ 0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
+ 0x45, 0x00, // PHYSICAL_MAXIMUM (0)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x06, // INPUT (Data,Var,Rel)
+ // ---------------------------- Horizontal wheel
+ 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
+ 0x0a, 0x38, 0x02, // USAGE (AC Pan)
+ 0x15, 0x81, // LOGICAL_MINIMUM (-127)
+ 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x06, // INPUT (Data,Var,Rel)
+ 0xc0, // END_COLLECTION
+ 0xc0, // END_COLLECTION
+};
+/* wrapper */
+static const USBDescriptor mouse_hid_report_descriptor = {
+ sizeof mouse_hid_report_desc_data,
+ mouse_hid_report_desc_data
+};
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+static const uint8_t console_hid_report_desc_data[] = {
+ 0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
+ 0x09, 0x74, // Usage 0x74
+ 0xA1, 0x53, // Collection 0x53
+ 0x75, 0x08, // report size = 8 bits
+ 0x15, 0x00, // logical minimum = 0
+ 0x26, 0xFF, 0x00, // logical maximum = 255
+ 0x95, CONSOLE_EPSIZE, // report count
+ 0x09, 0x75, // usage
+ 0x81, 0x02, // Input (array)
+ 0xC0 // end collection
+};
+/* wrapper */
+static const USBDescriptor console_hid_report_descriptor = {
+ sizeof console_hid_report_desc_data,
+ console_hid_report_desc_data
+};
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+/* audio controls & system controls
+ * http://www.microsoft.com/whdc/archive/w2kbd.mspx */
+static const uint8_t extra_hid_report_desc_data[] = {
+ /* system control */
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x80, // USAGE (System Control)
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x85, REPORT_ID_SYSTEM, // REPORT_ID (2)
+ 0x15, 0x01, // LOGICAL_MINIMUM (0x1)
+ 0x25, 0xb7, // LOGICAL_MAXIMUM (0xb7)
+ 0x19, 0x01, // USAGE_MINIMUM (0x1)
+ 0x29, 0xb7, // USAGE_MAXIMUM (0xb7)
+ 0x75, 0x10, // REPORT_SIZE (16)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x00, // INPUT (Data,Array,Abs)
+ 0xc0, // END_COLLECTION
+ /* consumer */
+ 0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
+ 0x09, 0x01, // USAGE (Consumer Control)
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x85, REPORT_ID_CONSUMER, // REPORT_ID (3)
+ 0x15, 0x01, // LOGICAL_MINIMUM (0x1)
+ 0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c)
+ 0x19, 0x01, // USAGE_MINIMUM (0x1)
+ 0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c)
+ 0x75, 0x10, // REPORT_SIZE (16)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x81, 0x00, // INPUT (Data,Array,Abs)
+ 0xc0, // END_COLLECTION
+};
+/* wrapper */
+static const USBDescriptor extra_hid_report_descriptor = {
+ sizeof extra_hid_report_desc_data,
+ extra_hid_report_desc_data
+};
+#endif /* EXTRAKEY_ENABLE */
+
+
+/*
+ * Configuration Descriptor tree for a HID device
+ *
+ * The HID Specifications version 1.11 require the following order:
+ * - Configuration Descriptor
+ * - Interface Descriptor
+ * - HID Descriptor
+ * - Endpoints Descriptors
+ */
+#define KBD_HID_DESC_NUM 0
+#define KBD_HID_DESC_OFFSET (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9)
+
+#ifdef MOUSE_ENABLE
+# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1)
+# define MOUSE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9)
+#else /* MOUSE_ENABLE */
+# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0)
+#endif /* MOUSE_ENABLE */
+
+#ifdef CONSOLE_ENABLE
+#define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1)
+#define CONSOLE_HID_DESC_OFFSET (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9)
+#else /* CONSOLE_ENABLE */
+# define CONSOLE_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 0)
+#endif /* CONSOLE_ENABLE */
+
+#ifdef EXTRAKEY_ENABLE
+# define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 1)
+# define EXTRA_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
+#else /* EXTRAKEY_ENABLE */
+# define EXTRA_HID_DESC_NUM (CONSOLE_HID_DESC_NUM + 0)
+#endif /* EXTRAKEY_ENABLE */
+
+#ifdef NKRO_ENABLE
+# define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1)
+# define NKRO_HID_DESC_OFFSET (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
+#else /* NKRO_ENABLE */
+# define NKRO_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0)
+#endif /* NKRO_ENABLE */
+
+#define NUM_INTERFACES (NKRO_HID_DESC_NUM + 1)
+#define CONFIG1_DESC_SIZE (9 + (9 + 9 + 7) * NUM_INTERFACES)
+
+static const uint8_t hid_configuration_descriptor_data[] = {
+ /* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */
+ USB_DESC_CONFIGURATION(CONFIG1_DESC_SIZE, // wTotalLength
+ NUM_INTERFACES, // bNumInterfaces
+ 1, // bConfigurationValue
+ 0, // iConfiguration
+ 0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP)
+ 50), // bMaxPower (50mA)
+
+ /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+ USB_DESC_INTERFACE(KBD_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass: HID
+ 0x01, // bInterfaceSubClass: Boot
+ 0x01, // bInterfaceProtocol: Keyboard
+ 0), // iInterface
+
+ /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+ USB_DESC_BYTE(9), // bLength
+ USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
+ USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
+ USB_DESC_BYTE(0), // bCountryCode
+ USB_DESC_BYTE(1), // bNumDescriptors
+ USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
+ USB_DESC_WORD(sizeof(keyboard_hid_report_desc_data)), // wDescriptorLength
+
+ /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+ USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (Interrupt)
+ KBD_EPSIZE,// wMaxPacketSize
+ 10), // bInterval
+
+ #ifdef MOUSE_ENABLE
+ /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+ USB_DESC_INTERFACE(MOUSE_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass (0x03 = HID)
+ // ThinkPad T23 BIOS doesn't work with boot mouse.
+ 0x00, // bInterfaceSubClass (0x01 = Boot)
+ 0x00, // bInterfaceProtocol (0x02 = Mouse)
+ /*
+ 0x01, // bInterfaceSubClass (0x01 = Boot)
+ 0x02, // bInterfaceProtocol (0x02 = Mouse)
+ */
+ 0), // iInterface
+
+ /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+ USB_DESC_BYTE(9), // bLength
+ USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
+ USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
+ USB_DESC_BYTE(0), // bCountryCode
+ USB_DESC_BYTE(1), // bNumDescriptors
+ USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
+ USB_DESC_WORD(sizeof(mouse_hid_report_desc_data)), // wDescriptorLength
+
+ /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+ USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (Interrupt)
+ MOUSE_EPSIZE, // wMaxPacketSize
+ 1), // bInterval
+ #endif /* MOUSE_ENABLE */
+
+ #ifdef CONSOLE_ENABLE
+ /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+ USB_DESC_INTERFACE(CONSOLE_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass: HID
+ 0x00, // bInterfaceSubClass: None
+ 0x00, // bInterfaceProtocol: None
+ 0), // iInterface
+
+ /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+ USB_DESC_BYTE(9), // bLength
+ USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
+ USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
+ USB_DESC_BYTE(0), // bCountryCode
+ USB_DESC_BYTE(1), // bNumDescriptors
+ USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
+ USB_DESC_WORD(sizeof(console_hid_report_desc_data)), // wDescriptorLength
+
+ /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+ USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (Interrupt)
+ CONSOLE_EPSIZE, // wMaxPacketSize
+ 1), // bInterval
+ #endif /* CONSOLE_ENABLE */
+
+ #ifdef EXTRAKEY_ENABLE
+ /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+ USB_DESC_INTERFACE(EXTRA_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass: HID
+ 0x00, // bInterfaceSubClass: None
+ 0x00, // bInterfaceProtocol: None
+ 0), // iInterface
+
+ /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+ USB_DESC_BYTE(9), // bLength
+ USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
+ USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
+ USB_DESC_BYTE(0), // bCountryCode
+ USB_DESC_BYTE(1), // bNumDescriptors
+ USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
+ USB_DESC_WORD(sizeof(extra_hid_report_desc_data)), // wDescriptorLength
+
+ /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+ USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (Interrupt)
+ EXTRA_EPSIZE, // wMaxPacketSize
+ 10), // bInterval
+ #endif /* EXTRAKEY_ENABLE */
+
+ #ifdef NKRO_ENABLE
+ /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
+ USB_DESC_INTERFACE(NKRO_INTERFACE, // bInterfaceNumber
+ 0, // bAlternateSetting
+ 1, // bNumEndpoints
+ 0x03, // bInterfaceClass: HID
+ 0x00, // bInterfaceSubClass: None
+ 0x00, // bInterfaceProtocol: None
+ 0), // iInterface
+
+ /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
+ USB_DESC_BYTE(9), // bLength
+ USB_DESC_BYTE(0x21), // bDescriptorType (HID class)
+ USB_DESC_BCD(0x0111), // bcdHID: HID version 1.11
+ USB_DESC_BYTE(0), // bCountryCode
+ USB_DESC_BYTE(1), // bNumDescriptors
+ USB_DESC_BYTE(0x22), // bDescriptorType (report desc)
+ USB_DESC_WORD(sizeof(nkro_hid_report_desc_data)), // wDescriptorLength
+
+ /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
+ USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80, // bEndpointAddress
+ 0x03, // bmAttributes (Interrupt)
+ NKRO_EPSIZE, // wMaxPacketSize
+ 1), // bInterval
+ #endif /* NKRO_ENABLE */
+};
+
+/* Configuration Descriptor wrapper */
+static const USBDescriptor hid_configuration_descriptor = {
+ sizeof hid_configuration_descriptor_data,
+ hid_configuration_descriptor_data
+};
+
+/* wrappers */
+#define HID_DESCRIPTOR_SIZE 9
+static const USBDescriptor keyboard_hid_descriptor = {
+ HID_DESCRIPTOR_SIZE,
+ &hid_configuration_descriptor_data[KBD_HID_DESC_OFFSET]
+};
+#ifdef MOUSE_ENABLE
+static const USBDescriptor mouse_hid_descriptor = {
+ HID_DESCRIPTOR_SIZE,
+ &hid_configuration_descriptor_data[MOUSE_HID_DESC_OFFSET]
+};
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+static const USBDescriptor console_hid_descriptor = {
+ HID_DESCRIPTOR_SIZE,
+ &hid_configuration_descriptor_data[CONSOLE_HID_DESC_OFFSET]
+};
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+static const USBDescriptor extra_hid_descriptor = {
+ HID_DESCRIPTOR_SIZE,
+ &hid_configuration_descriptor_data[EXTRA_HID_DESC_OFFSET]
+};
+#endif /* EXTRAKEY_ENABLE */
+#ifdef NKRO_ENABLE
+static const USBDescriptor nkro_hid_descriptor = {
+ HID_DESCRIPTOR_SIZE,
+ &hid_configuration_descriptor_data[NKRO_HID_DESC_OFFSET]
+};
+#endif /* NKRO_ENABLE */
+
+
+/* U.S. English language identifier */
+static const uint8_t usb_string_langid[] = {
+ USB_DESC_BYTE(4), // bLength
+ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
+ USB_DESC_WORD(0x0409) // wLANGID (U.S. English)
+};
+
+/* ugly ugly hack */
+#define PP_NARG(...) \
+ PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
+#define PP_NARG_(...) \
+ PP_ARG_N(__VA_ARGS__)
+#define PP_ARG_N( \
+ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
+ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
+ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
+ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
+ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
+ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
+ _61,_62,_63,N,...) N
+#define PP_RSEQ_N() \
+ 63,62,61,60, \
+ 59,58,57,56,55,54,53,52,51,50, \
+ 49,48,47,46,45,44,43,42,41,40, \
+ 39,38,37,36,35,34,33,32,31,30, \
+ 29,28,27,26,25,24,23,22,21,20, \
+ 19,18,17,16,15,14,13,12,11,10, \
+ 9,8,7,6,5,4,3,2,1,0
+
+/* Vendor string = manufacturer */
+static const uint8_t usb_string_vendor[] = {
+ USB_DESC_BYTE(PP_NARG(USBSTR_MANUFACTURER)+2), // bLength
+ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
+ USBSTR_MANUFACTURER
+};
+
+/* Device Description string = product */
+static const uint8_t usb_string_description[] = {
+ USB_DESC_BYTE(PP_NARG(USBSTR_PRODUCT)+2), // bLength
+ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
+ USBSTR_PRODUCT
+};
+
+/* Serial Number string (will be filled by the function init_usb_serial_string) */
+static uint8_t usb_string_serial[] = {
+ USB_DESC_BYTE(22), // bLength
+ USB_DESC_BYTE(USB_DESCRIPTOR_STRING), // bDescriptorType
+ '0', 0, 'x', 0, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'B', 0, 'E', 0, 'E', 0, 'F', 0
+};
+
+/* Strings wrappers array */
+static const USBDescriptor usb_strings[] = {
+ { sizeof usb_string_langid, usb_string_langid }
+ ,
+ { sizeof usb_string_vendor, usb_string_vendor }
+ ,
+ { sizeof usb_string_description, usb_string_description }
+ ,
+ { sizeof usb_string_serial, usb_string_serial }
+};
+
+/*
+ * Handles the GET_DESCRIPTOR callback
+ *
+ * Returns the proper descriptor
+ */
+static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) {
+ (void)usbp;
+ (void)lang;
+ switch(dtype) {
+ /* Generic descriptors */
+ case USB_DESCRIPTOR_DEVICE: /* Device Descriptor */
+ return &usb_device_descriptor;
+
+ case USB_DESCRIPTOR_CONFIGURATION: /* Configuration Descriptor */
+ return &hid_configuration_descriptor;
+
+ case USB_DESCRIPTOR_STRING: /* Strings */
+ if(dindex < 4)
+ return &usb_strings[dindex];
+ break;
+
+ /* HID specific descriptors */
+ case USB_DESCRIPTOR_HID: /* HID Descriptors */
+ switch(lang) { /* yea, poor label, it's actually wIndex from the setup packet */
+ case KBD_INTERFACE:
+ return &keyboard_hid_descriptor;
+
+#ifdef MOUSE_ENABLE
+ case MOUSE_INTERFACE:
+ return &mouse_hid_descriptor;
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+ case CONSOLE_INTERFACE:
+ return &console_hid_descriptor;
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+ case EXTRA_INTERFACE:
+ return &extra_hid_descriptor;
+#endif /* EXTRAKEY_ENABLE */
+#ifdef NKRO_ENABLE
+ case NKRO_INTERFACE:
+ return &nkro_hid_descriptor;
+#endif /* NKRO_ENABLE */
+ }
+
+ case USB_DESCRIPTOR_HID_REPORT: /* HID Report Descriptor */
+ switch(lang) {
+ case KBD_INTERFACE:
+ return &keyboard_hid_report_descriptor;
+
+#ifdef MOUSE_ENABLE
+ case MOUSE_INTERFACE:
+ return &mouse_hid_report_descriptor;
+#endif /* MOUSE_ENABLE */
+#ifdef CONSOLE_ENABLE
+ case CONSOLE_INTERFACE:
+ return &console_hid_report_descriptor;
+#endif /* CONSOLE_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+ case EXTRA_INTERFACE: