diff options
Diffstat (limited to 'tmk_core/protocol')
-rw-r--r-- | tmk_core/protocol/host.c | 138 | ||||
-rw-r--r-- | tmk_core/protocol/host.h | 58 | ||||
-rw-r--r-- | tmk_core/protocol/host_driver.h | 35 | ||||
-rw-r--r-- | tmk_core/protocol/report.c | 280 | ||||
-rw-r--r-- | tmk_core/protocol/report.h | 325 | ||||
-rw-r--r-- | tmk_core/protocol/usb_device_state.c | 51 | ||||
-rw-r--r-- | tmk_core/protocol/usb_device_state.h | 39 | ||||
-rw-r--r-- | tmk_core/protocol/usb_util.c | 29 | ||||
-rw-r--r-- | tmk_core/protocol/usb_util.h | 22 |
9 files changed, 977 insertions, 0 deletions
diff --git a/tmk_core/protocol/host.c b/tmk_core/protocol/host.c new file mode 100644 index 0000000000..56d4bb0847 --- /dev/null +++ b/tmk_core/protocol/host.c @@ -0,0 +1,138 @@ +/* +Copyright 2011,2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdint.h> +//#include <avr/interrupt.h> +#include "keyboard.h" +#include "keycode.h" +#include "host.h" +#include "util.h" +#include "debug.h" +#include "digitizer.h" + +#ifdef NKRO_ENABLE +# include "keycode_config.h" +extern keymap_config_t keymap_config; +#endif + +static host_driver_t *driver; +static uint16_t last_system_report = 0; +static uint16_t last_consumer_report = 0; +static uint32_t last_programmable_button_report = 0; + +void host_set_driver(host_driver_t *d) { driver = d; } + +host_driver_t *host_get_driver(void) { return driver; } + +#ifdef SPLIT_KEYBOARD +uint8_t split_led_state = 0; +void set_split_host_keyboard_leds(uint8_t led_state) { split_led_state = led_state; } +#endif + +uint8_t host_keyboard_leds(void) { +#ifdef SPLIT_KEYBOARD + if (!is_keyboard_master()) return split_led_state; +#endif + if (!driver) return 0; + return (*driver->keyboard_leds)(); +} + +led_t host_keyboard_led_state(void) { return (led_t)host_keyboard_leds(); } + +/* send report */ +void host_keyboard_send(report_keyboard_t *report) { + if (!driver) return; +#if defined(NKRO_ENABLE) && defined(NKRO_SHARED_EP) + if (keyboard_protocol && keymap_config.nkro) { + /* The callers of this function assume that report->mods is where mods go in. + * But report->nkro.mods can be at a different offset if core keyboard does not have a report ID. + */ + report->nkro.mods = report->mods; + report->nkro.report_id = REPORT_ID_NKRO; + } else +#endif + { +#ifdef KEYBOARD_SHARED_EP + report->report_id = REPORT_ID_KEYBOARD; +#endif + } + (*driver->send_keyboard)(report); + + if (debug_keyboard) { + dprint("keyboard_report: "); + for (uint8_t i = 0; i < KEYBOARD_REPORT_SIZE; i++) { + dprintf("%02X ", report->raw[i]); + } + dprint("\n"); + } +} + +void host_mouse_send(report_mouse_t *report) { + if (!driver) return; +#ifdef MOUSE_SHARED_EP + report->report_id = REPORT_ID_MOUSE; +#endif + (*driver->send_mouse)(report); +} + +void host_system_send(uint16_t report) { + if (report == last_system_report) return; + last_system_report = report; + + if (!driver) return; + (*driver->send_system)(report); +} + +void host_consumer_send(uint16_t report) { + if (report == last_consumer_report) return; + last_consumer_report = report; + + if (!driver) return; + (*driver->send_consumer)(report); +} + +void host_digitizer_send(digitizer_t *digitizer) { + if (!driver) return; + + report_digitizer_t report = { +#ifdef DIGITIZER_SHARED_EP + .report_id = REPORT_ID_DIGITIZER, +#endif + .tip = digitizer->tipswitch & 0x1, + .inrange = digitizer->inrange & 0x1, + .x = (uint16_t)(digitizer->x * 0x7FFF), + .y = (uint16_t)(digitizer->y * 0x7FFF), + }; + + send_digitizer(&report); +} + +__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {} + +void host_programmable_button_send(uint32_t report) { + if (report == last_programmable_button_report) return; + last_programmable_button_report = report; + + if (!driver) return; + (*driver->send_programmable_button)(report); +} + +uint16_t host_last_system_report(void) { return last_system_report; } + +uint16_t host_last_consumer_report(void) { return last_consumer_report; } + +uint32_t host_last_programmable_button_report(void) { return last_programmable_button_report; } diff --git a/tmk_core/protocol/host.h b/tmk_core/protocol/host.h new file mode 100644 index 0000000000..6b15f0d0c1 --- /dev/null +++ b/tmk_core/protocol/host.h @@ -0,0 +1,58 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <stdint.h> +#include <stdbool.h> +#include "report.h" +#include "host_driver.h" +#include "led.h" + +#define IS_LED_ON(leds, led_name) ((leds) & (1 << (led_name))) +#define IS_LED_OFF(leds, led_name) (~(leds) & (1 << (led_name))) + +#define IS_HOST_LED_ON(led_name) IS_LED_ON(host_keyboard_leds(), led_name) +#define IS_HOST_LED_OFF(led_name) IS_LED_OFF(host_keyboard_leds(), led_name) + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t keyboard_idle; +extern uint8_t keyboard_protocol; + +/* host driver */ +void host_set_driver(host_driver_t *driver); +host_driver_t *host_get_driver(void); + +/* host driver interface */ +uint8_t host_keyboard_leds(void); +led_t host_keyboard_led_state(void); +void host_keyboard_send(report_keyboard_t *report); +void host_mouse_send(report_mouse_t *report); +void host_system_send(uint16_t data); +void host_consumer_send(uint16_t data); +void host_programmable_button_send(uint32_t data); + +uint16_t host_last_system_report(void); +uint16_t host_last_consumer_report(void); +uint32_t host_last_programmable_button_report(void); + +#ifdef __cplusplus +} +#endif diff --git a/tmk_core/protocol/host_driver.h b/tmk_core/protocol/host_driver.h new file mode 100644 index 0000000000..affd0dcb34 --- /dev/null +++ b/tmk_core/protocol/host_driver.h @@ -0,0 +1,35 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <stdint.h> +#include "report.h" +#ifdef MIDI_ENABLE +# include "midi.h" +#endif + +typedef struct { + uint8_t (*keyboard_leds)(void); + void (*send_keyboard)(report_keyboard_t *); + void (*send_mouse)(report_mouse_t *); + void (*send_system)(uint16_t); + void (*send_consumer)(uint16_t); + void (*send_programmable_button)(uint32_t); +} host_driver_t; + +void send_digitizer(report_digitizer_t *report);
\ No newline at end of file diff --git a/tmk_core/protocol/report.c b/tmk_core/protocol/report.c new file mode 100644 index 0000000000..854b59ae48 --- /dev/null +++ b/tmk_core/protocol/report.c @@ -0,0 +1,280 @@ +/* Copyright 2017 Fred Sundvik + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "report.h" +#include "host.h" +#include "keycode_config.h" +#include "debug.h" +#include "util.h" +#include <string.h> + +#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE +# define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS) +# define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS) +# define RO_INC(a) RO_ADD(a, 1) +# define RO_DEC(a) RO_SUB(a, 1) +static int8_t cb_head = 0; +static int8_t cb_tail = 0; +static int8_t cb_count = 0; +#endif + +/** \brief has_anykey + * + * FIXME: Needs doc + */ +uint8_t has_anykey(report_keyboard_t* keyboard_report) { + uint8_t cnt = 0; + uint8_t* p = keyboard_report->keys; + uint8_t lp = sizeof(keyboard_report->keys); +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + p = keyboard_report->nkro.bits; + lp = sizeof(keyboard_report->nkro.bits); + } +#endif + while (lp--) { + if (*p++) cnt++; + } + return cnt; +} + +/** \brief get_first_key + * + * FIXME: Needs doc + */ +uint8_t get_first_key(report_keyboard_t* keyboard_report) { +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + uint8_t i = 0; + for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++) + ; + return i << 3 | biton(keyboard_report->nkro.bits[i]); + } +#endif +#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE + uint8_t i = cb_head; + do { + if (keyboard_report->keys[i] != 0) { + break; + } + i = RO_INC(i); + } while (i != cb_tail); + return keyboard_report->keys[i]; +#else + return keyboard_report->keys[0]; +#endif +} + +/** \brief Checks if a key is pressed in the report + * + * Returns true if the keyboard_report reports that the key is pressed, otherwise false + * Note: The function doesn't support modifers currently, and it returns false for KC_NO + */ +bool is_key_pressed(report_keyboard_t* keyboard_report, uint8_t key) { + if (key == KC_NO) { + return false; + } +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + if ((key >> 3) < KEYBOARD_REPORT_BITS) { + return keyboard_report->nkro.bits[key >> 3] & 1 << (key & 7); + } else { + return false; + } + } +#endif + for (int i = 0; i < KEYBOARD_REPORT_KEYS; i++) { + if (keyboard_report->keys[i] == key) { + return true; + } + } + return false; +} + +/** \brief add key byte + * + * FIXME: Needs doc + */ +void add_key_byte(report_keyboard_t* keyboard_report, uint8_t code) { +#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE + int8_t i = cb_head; + int8_t empty = -1; + if (cb_count) { + do { + if (keyboard_report->keys[i] == code) { + return; + } + if (empty == -1 && keyboard_report->keys[i] == 0) { + empty = i; + } + i = RO_INC(i); + } while (i != cb_tail); + if (i == cb_tail) { + if (cb_tail == cb_head) { + // buffer is full + if (empty == -1) { + // pop head when has no empty space + cb_head = RO_INC(cb_head); + cb_count--; + } else { + // left shift when has empty space + uint8_t offset = 1; + i = RO_INC(empty); + do { + if (keyboard_report->keys[i] != 0) { + keyboard_report->keys[empty] = keyboard_report->keys[i]; + keyboard_report->keys[i] = 0; + empty = RO_INC(empty); + } else { + offset++; + } + i = RO_INC(i); + } while (i != cb_tail); + cb_tail = RO_SUB(cb_tail, offset); + } + } + } + } + // add to tail + keyboard_report->keys[cb_tail] = code; + cb_tail = RO_INC(cb_tail); + cb_count++; +#else + int8_t i = 0; + int8_t empty = -1; + for (; i < KEYBOARD_REPORT_KEYS; i++) { + if (keyboard_report->keys[i] == code) { + break; + } + if (empty == -1 && keyboard_report->keys[i] == 0) { + empty = i; + } + } + if (i == KEYBOARD_REPORT_KEYS) { + if (empty != -1) { + keyboard_report->keys[empty] = code; + } + } +#endif +} + +/** \brief del key byte + * + * FIXME: Needs doc + */ +void del_key_byte(report_keyboard_t* keyboard_report, uint8_t code) { +#ifdef RING_BUFFERED_6KRO_REPORT_ENABLE + uint8_t i = cb_head; + if (cb_count) { + do { + if (keyboard_report->keys[i] == code) { + keyboard_report->keys[i] = 0; + cb_count--; + if (cb_count == 0) { + // reset head and tail + cb_tail = cb_head = 0; + } + if (i == RO_DEC(cb_tail)) { + // left shift when next to tail + do { + cb_tail = RO_DEC(cb_tail); + if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) { + break; + } + } while (cb_tail != cb_head); + } + break; + } + i = RO_INC(i); + } while (i != cb_tail); + } +#else + for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { + if (keyboard_report->keys[i] == code) { + keyboard_report->keys[i] = 0; + } + } +#endif +} + +#ifdef NKRO_ENABLE +/** \brief add key bit + * + * FIXME: Needs doc + */ +void add_key_bit(report_keyboard_t* keyboard_report, uint8_t code) { + if ((code >> 3) < KEYBOARD_REPORT_BITS) { + keyboard_report->nkro.bits[code >> 3] |= 1 << (code & 7); + } else { + dprintf("add_key_bit: can't add: %02X\n", code); + } +} + +/** \brief del key bit + * + * FIXME: Needs doc + */ +void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code) { + if ((code >> 3) < KEYBOARD_REPORT_BITS) { + keyboard_report->nkro.bits[code >> 3] &= ~(1 << (code & 7)); + } else { + dprintf("del_key_bit: can't del: %02X\n", code); + } +} +#endif + +/** \brief add key to report + * + * FIXME: Needs doc + */ +void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key) { +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + add_key_bit(keyboard_report, key); + return; + } +#endif + add_key_byte(keyboard_report, key); +} + +/** \brief del key from report + * + * FIXME: Needs doc + */ +void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key) { +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + del_key_bit(keyboard_report, key); + return; + } +#endif + del_key_byte(keyboard_report, key); +} + +/** \brief clear key from report + * + * FIXME: Needs doc + */ +void clear_keys_from_report(report_keyboard_t* keyboard_report) { + // not clear mods +#ifdef NKRO_ENABLE + if (keyboard_protocol && keymap_config.nkro) { + memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits)); + return; + } +#endif + memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys)); +} diff --git a/tmk_core/protocol/report.h b/tmk_core/protocol/report.h new file mode 100644 index 0000000000..1adc892f3b --- /dev/null +++ b/tmk_core/protocol/report.h @@ -0,0 +1,325 @@ +/* +Copyright 2011,2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <stdint.h> +#include <stdbool.h> +#include "keycode.h" + +// clang-format off + +/* HID report IDs */ +enum hid_report_ids { + REPORT_ID_KEYBOARD = 1, + REPORT_ID_MOUSE, + REPORT_ID_SYSTEM, + REPORT_ID_CONSUMER, + REPORT_ID_PROGRAMMABLE_BUTTON, + REPORT_ID_NKRO, + REPORT_ID_JOYSTICK, + REPORT_ID_DIGITIZER +}; + +/* Mouse buttons */ +#define MOUSE_BTN_MASK(n) (1 << (n)) +enum mouse_buttons { + MOUSE_BTN1 = MOUSE_BTN_MASK(0), + MOUSE_BTN2 = MOUSE_BTN_MASK(1), + MOUSE_BTN3 = MOUSE_BTN_MASK(2), + MOUSE_BTN4 = MOUSE_BTN_MASK(3), + MOUSE_BTN5 = MOUSE_BTN_MASK(4), + MOUSE_BTN6 = MOUSE_BTN_MASK(5), + MOUSE_BTN7 = MOUSE_BTN_MASK(6), + MOUSE_BTN8 = MOUSE_BTN_MASK(7) +}; + +/* Consumer Page (0x0C) + * + * See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf#page=75 + */ +enum consumer_usages { + // 15.5 Display Controls + SNAPSHOT = 0x065, + BRIGHTNESS_UP = 0x06F, // https://www.usb.org/sites/default/files/hutrr41_0.pdf + BRIGHTNESS_DOWN = 0x070, + // 15.7 Transport Controls + TRANSPORT_RECORD = 0x0B2, + TRANSPORT_FAST_FORWARD = 0x0B3, + TRANSPORT_REWIND = 0x0B4, + TRANSPORT_NEXT_TRACK = 0x0B5, + TRANSPORT_PREV_TRACK = 0x0B6, + TRANSPORT_STOP = 0x0B7, + TRANSPORT_EJECT = 0x0B8, + TRANSPORT_RANDOM_PLAY = 0x0B9, + TRANSPORT_STOP_EJECT = 0x0CC, + TRANSPORT_PLAY_PAUSE = 0x0CD, + // 15.9.1 Audio Controls - Volume + AUDIO_MUTE = 0x0E2, + AUDIO_VOL_UP = 0x0E9, + AUDIO_VOL_DOWN = 0x0EA, + // 15.15 Application Launch Buttons + AL_CC_CONFIG = 0x183, + AL_EMAIL = 0x18A, + AL_CALCULATOR = 0x192, + AL_LOCAL_BROWSER = 0x194, + AL_LOCK = 0x19E, + AL_CONTROL_PANEL = 0x19F, + AL_ASSISTANT = 0x1CB, + AL_KEYBOARD_LAYOUT = 0x1AE, + // 15.16 Generic GUI Application Controls + AC_NEW = 0x201, + AC_OPEN = 0x202, + AC_CLOSE = 0x203, + AC_EXIT = 0x204, + AC_MAXIMIZE = 0x205, + AC_MINIMIZE = 0x206, + AC_SAVE = 0x207, + AC_PRINT = 0x208, + AC_PROPERTIES = 0x209, + AC_UNDO = 0x21A, + AC_COPY = 0x21B, + AC_CUT = 0x21C, + AC_PASTE = 0x21D, + AC_SELECT_ALL = 0x21E, + AC_FIND = 0x21F, + AC_SEARCH = 0x221, + AC_HOME = 0x223, + AC_BACK = 0x224, + AC_FORWARD = 0x225, + AC_STOP = 0x226, + AC_REFRESH = 0x227, + AC_BOOKMARKS = 0x22A +}; + +/* Generic Desktop Page (0x01) + * + * See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf#page=26 + */ +enum desktop_usages { + // 4.5.1 System Controls - Power Controls + SYSTEM_POWER_DOWN = 0x81, + SYSTEM_SLEEP = 0x82, + SYSTEM_WAKE_UP = 0x83, + SYSTEM_RESTART = 0x8F, + // 4.10 System Display Controls + SYSTEM_DISPLAY_TOGGLE_INT_EXT = 0xB5 +}; + +// clang-format on + +#define NKRO_SHARED_EP +/* key report size(NKRO or boot mode) */ +#if defined(NKRO_ENABLE) +# if defined(PROTOCOL_LUFA) || defined(PROTOCOL_CHIBIOS) +# include "protocol/usb_descriptor.h" +# define KEYBOARD_REPORT_BITS (SHARED_EPSIZE - 2) +# elif defined(PROTOCOL_ARM_ATSAM) +# include "protocol/arm_atsam/usb/udi_device_epsize.h" +# define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) +# undef NKRO_SHARED_EP +# undef MOUSE_SHARED_EP +# else +# error "NKRO not supported with this protocol" +# endif +#endif + +#ifdef KEYBOARD_SHARED_EP +# define KEYBOARD_REPORT_SIZE 9 +#else +# define KEYBOARD_REPORT_SIZE 8 +#endif + +#define KEYBOARD_REPORT_KEYS 6 + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * keyboard report is 8-byte array retains state of 8 modifiers and 6 keys. + * + * byte |0 |1 |2 |3 |4 |5 |6 |7 + * -----+--------+--------+--------+--------+--------+--------+--------+-------- + * desc |mods |reserved|keys[0] |keys[1] |keys[2] |keys[3] |keys[4] |keys[5] + * + * It is exended to 16 bytes to retain 120keys+8mods when NKRO mode. + * + * byte |0 |1 |2 |3 |4 |5 |6 |7 ... |15 + * -----+--------+--------+--------+--------+--------+--------+--------+-------- +-------- + * desc |mods |bits[0] |bits[1] |bits[2] |bits[3] |bits[4] |bits[5] |bits[6] ... |bit[14] + * + * mods retains state of 8 modifiers. + * + * bit |0 |1 |2 |3 |4 |5 |6 |7 + * -----+--------+--------+--------+--------+--------+--------+--------+-------- + * desc |Lcontrol|Lshift |Lalt |Lgui |Rcontrol|Rshift |Ralt |Rgui + * + */ +typedef union { + uint8_t raw[KEYBOARD_REPORT_SIZE]; + struct { +#ifdef KEYBOARD_SHARED_EP + uint8_t report_id; +#endif + uint8_t mods; + uint8_t reserved; + uint8_t keys[KEYBOARD_REPORT_KEYS]; + }; +#ifdef NKRO_ENABLE + struct nkro_report { +# ifdef NKRO_SHARED_EP + uint8_t report_id; +# endif + uint8_t mods; + uint8_t bits[KEYBOARD_REPORT_BITS]; + } nkro; +#endif +} __attribute__((packed)) report_keyboard_t; + +typedef struct { + uint8_t report_id; + uint16_t usage; +} __attribute__((packed)) report_extra_t; + +typedef struct { + uint8_t report_id; + uint32_t usage; +} __attribute__((packed)) report_programmable_button_t; + +typedef struct { +#ifdef MOUSE_SHARED_EP + uint8_t report_id; +#endif + uint8_t buttons; + int8_t x; + int8_t y; + int8_t v; + int8_t h; +} __attribute__((packed)) report_mouse_t; + +typedef struct { +#ifdef DIGITIZER_SHARED_EP + uint8_t report_id; +#endif + uint8_t tip : 1; + uint8_t inrange : 1; + uint8_t pad2 : 6; + uint16_t x; + uint16_t y; +} __attribute__((packed)) report_digitizer_t; + +typedef struct { +#if JOYSTICK_AXES_COUNT > 0 +# if JOYSTICK_AXES_RESOLUTION > 8 + int16_t axes[JOYSTICK_AXES_COUNT]; +# else + int8_t axes[JOYSTICK_AXES_COUNT]; +# endif +#endif + +#if JOYSTICK_BUTTON_COUNT > 0 + uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1]; +#endif +} __attribute__((packed)) joystick_report_t; + +/* keycode to system usage */ +static inline uint16_t KEYCODE2SYSTEM(uint8_t key) { + switch (key) { + case KC_SYSTEM_POWER: + return SYSTEM_POWER_DOWN; + case KC_SYSTEM_SLEEP: + return SYSTEM_SLEEP; + case KC_SYSTEM_WAKE: + return SYSTEM_WAKE_UP; + default: + return 0; + } +} + +/* keycode to consumer usage */ +static inline uint16_t KEYCODE2CONSUMER(uint8_t key) { + switch (key) { + case KC_AUDIO_MUTE: + return AUDIO_MUTE; + case KC_AUDIO_VOL_UP: + return AUDIO_VOL_UP; + case KC_AUDIO_VOL_DOWN: + return AUDIO_VOL_DOWN; + case KC_MEDIA_NEXT_TRACK: + return TRANSPORT_NEXT_TRACK; + case KC_MEDIA_PREV_TRACK: + return TRANSPORT_PREV_TRACK; + case KC_MEDIA_FAST_FORWARD: + return TRANSPORT_FAST_FORWARD; + case KC_MEDIA_REWIND: + return TRANSPORT_REWIND; + case KC_MEDIA_STOP: + return TRANSPORT_STOP; + case KC_MEDIA_EJECT: + return TRANSPORT_STOP_EJECT; + case KC_MEDIA_PLAY_PAUSE: + return TRANSPORT_PLAY_PAUSE; + case KC_MEDIA_SELECT: + return AL_CC_CONFIG; + case KC_MAIL: + return AL_EMAIL; + case KC_CALCULATOR: + return AL_CALCULATOR; + case KC_MY_COMPUTER: + return AL_LOCAL_BROWSER; + case KC_WWW_SEARCH: + return AC_SEARCH; + case KC_WWW_HOME: + return AC_HOME; + case KC_WWW_BACK: + return AC_BACK; + case KC_WWW_FORWARD: + return AC_FORWARD; + case KC_WWW_STOP: + return AC_STOP; + case KC_WWW_REFRESH: + return AC_REFRESH; + case KC_BRIGHTNESS_UP: + return BRIGHTNESS_UP; + case KC_BRIGHTNESS_DOWN: + return BRIGHTNESS_DOWN; + case KC_WWW_FAVORITES: + return AC_BOOKMARKS; + default: + return 0; + } +} + +uint8_t has_anykey(report_keyboard_t* keyboard_report); +uint8_t get_first_key(report_keyboard_t* keyboard_report); +bool is_key_pressed(report_keyboard_t* keyboard_report, uint8_t key); + +void add_key_byte(report_keyboard_t* keyboard_report, uint8_t code); +void del_key_byte(report_keyboard_t* keyboard_report, uint8_t code); +#ifdef NKRO_ENABLE +void add_key_bit(report_keyboard_t* keyboard_report, uint8_t code); +void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code); +#endif + +void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key); +void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key); +void clear_keys_from_report(report_keyboard_t* keyboard_report); + +#ifdef __cplusplus +} +#endif diff --git a/tmk_core/protocol/usb_device_state.c b/tmk_core/protocol/usb_device_state.c new file mode 100644 index 0000000000..5ccd309ec2 --- /dev/null +++ b/tmk_core/protocol/usb_device_state.c @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Andrei Purdea <andrei@purdea.ro> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "usb_device_state.h" + +enum usb_device_state usb_device_state = USB_DEVICE_STATE_NO_INIT; + +__attribute__((weak)) void notify_usb_device_state_change_kb(enum usb_device_state usb_device_state) { notify_usb_device_state_change_user(usb_device_state); } + +__attribute__((weak)) void notify_usb_device_state_change_user(enum usb_device_state usb_device_state) {} + +static void notify_usb_device_state_change(enum usb_device_state usb_device_state) { notify_usb_device_state_change_kb(usb_device_state); } + +void usb_device_state_set_configuration(bool isConfigured, uint8_t configurationNumber) { + usb_device_state = isConfigured ? USB_DEVICE_STATE_CONFIGURED : USB_DEVICE_STATE_INIT; + notify_usb_device_state_change(usb_device_state); +} + +void usb_device_state_set_suspend(bool isConfigured, uint8_t configurationNumber) { + usb_device_state = USB_DEVICE_STATE_SUSPEND; + notify_usb_device_state_change(usb_device_state); +} + +void usb_device_state_set_resume(bool isConfigured, uint8_t configurationNumber) { + usb_device_state = isConfigured ? USB_DEVICE_STATE_CONFIGURED : USB_DEVICE_STATE_INIT; + notify_usb_device_state_change(usb_device_state); +} + +void usb_device_state_set_reset(void) { + usb_device_state = USB_DEVICE_STATE_INIT; + notify_usb_device_state_change(usb_device_state); +} + +void usb_device_state_init(void) { + usb_device_state = USB_DEVICE_STATE_INIT; + notify_usb_device_state_change(usb_device_state); +} diff --git a/tmk_core/protocol/usb_device_state.h b/tmk_core/protocol/usb_device_state.h new file mode 100644 index 0000000000..c229311d46 --- /dev/null +++ b/tmk_core/protocol/usb_device_state.h @@ -0,0 +1,39 @@ +/* + * Copyright 2021 Andrei Purdea <andrei@purdea.ro> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +void usb_device_state_set_configuration(bool isConfigured, uint8_t configurationNumber); +void usb_device_state_set_suspend(bool isConfigured, uint8_t configurationNumber); +void usb_device_state_set_resume(bool isConfigured, uint8_t configurationNumber); +void usb_device_state_set_reset(void); +void usb_device_state_init(void); + +enum usb_device_state { + USB_DEVICE_STATE_NO_INIT = 0, // We're in this state before calling usb_device_state_init() + USB_DEVICE_STATE_INIT = 1, // Can consume up to 100mA + USB_DEVICE_STATE_CONFIGURED = 2, // Can consume up to what is specified in configuration descriptor, typically 500mA + USB_DEVICE_STATE_SUSPEND = 3 // Can consume only suspend current +}; + +extern enum usb_device_state usb_device_state; + +void notify_usb_device_state_change_kb(enum usb_device_state usb_device_state); +void notify_usb_device_state_change_user(enum usb_device_state usb_device_state); diff --git a/tmk_core/protocol/usb_util.c b/tmk_core/protocol/usb_util.c new file mode 100644 index 0000000000..dd1deeaa11 --- /dev/null +++ b/tmk_core/protocol/usb_util.c @@ -0,0 +1,29 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "quantum.h" +#include "usb_util.h" + +__attribute__((weak)) void usb_disconnect(void) {} +__attribute__((weak)) bool usb_connected_state(void) { return true; } +__attribute__((weak)) bool usb_vbus_state(void) { +#ifdef USB_VBUS_PIN + setPinInput(USB_VBUS_PIN); + wait_us(5); + return readPin(USB_VBUS_PIN); +#else + return true; +#endif +} diff --git a/tmk_core/protocol/usb_util.h b/tmk_core/protocol/usb_util.h new file mode 100644 index 0000000000..13db9fbfbd --- /dev/null +++ b/tmk_core/protocol/usb_util.h @@ -0,0 +1,22 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#pragma once + +#include <stdbool.h> + +void usb_disconnect(void); +bool usb_connected_state(void); +bool usb_vbus_state(void); |