Merge remote-tracking branch 'upstream/develop' into xap

This commit is contained in:
Nick Brassel
2026-06-15 09:56:10 +10:00
14 changed files with 127 additions and 89 deletions
-5
View File
@@ -103,11 +103,6 @@ endif
VALID_STENO_PROTOCOL_TYPES := geminipr txbolt all
STENO_PROTOCOL ?= all
ifeq ($(strip $(PLOVER_HID_ENABLE)), yes)
OPT_DEFS += -DPLOVER_HID_ENABLE
SRC += $(QUANTUM_DIR)/process_keycode/process_plover_hid.c
endif
ifeq ($(strip $(STENO_ENABLE)), yes)
ifeq ($(filter $(STENO_PROTOCOL),$(VALID_STENO_PROTOCOL_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid STENO_PROTOCOL,STENO_PROTOCOL="$(STENO_PROTOCOL)" is not a valid stenography protocol)
+1
View File
@@ -45,6 +45,7 @@ GENERIC_FEATURES = \
MOUSEKEY \
MUSIC \
OS_DETECTION \
PLOVER_HID \
PROGRAMMABLE_BUTTON \
REPEAT_KEY \
SECURE \
+1 -1
View File
@@ -166,7 +166,7 @@ In your keyboard config.h:
The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using the integrated PIO peripheral and is therefore only available on this MCU.
There are strict requirements for pin ordering but any pair of GPIO pins can be used. The GPIO used for clock must be directly after data, see the included info.json snippet for an example of correct order.
The GPIOs used for clock and data must be consecutive (in either order).
You may optionally switch the PIO peripheral used with the following define in config.h:
```c
+35 -27
View File
@@ -21,8 +21,16 @@
# endif
#endif
#if PS2_DATA_PIN + 1 != PS2_CLOCK_PIN
# error PS/2 clock pin must be data pin + 1!
#if PS2_DATA_PIN + 1 == PS2_CLOCK_PIN
# define PS2_FIRST_PIN PS2_DATA_PIN
# define PS2_DATA_PINDIR_BIT 1
# define PS2_CLOCK_PINDIR_BIT 2
#elif PS2_DATA_PIN - 1 == PS2_CLOCK_PIN
# define PS2_FIRST_PIN PS2_CLOCK_PIN
# define PS2_DATA_PINDIR_BIT 2
# define PS2_CLOCK_PINDIR_BIT 1
#else
# error PS/2 clock and data pin must be consecutive!
#endif
static inline void pio_serve_interrupt(void);
@@ -50,29 +58,29 @@ OSAL_IRQ_HANDLER(RP_PIO0_IRQ_0_HANDLER) {
// clang-format off
static const uint16_t ps2_program_instructions[] = {
// .wrap_target
0x00c7, // 0: jmp pin, 7
0xe02a, // 1: set x, 10
0x2021, // 2: wait 0 pin, 1
0x4001, // 3: in pins, 1
0x20a1, // 4: wait 1 pin, 1
0x0042, // 5: jmp x--, 2
0x0000, // 6: jmp 0
0x00e9, // 7: jmp !osre, 9
0x0000, // 8: jmp 0
0xff81, // 9: set pindirs, 1 [31]
0xe280, // 10: set pindirs, 0 [2]
0xe082, // 11: set pindirs, 2
0x2021, // 12: wait 0 pin, 1
0xe029, // 13: set x, 9
0x6081, // 14: out pindirs, 1
0x20a1, // 15: wait 1 pin, 1
0x2021, // 16: wait 0 pin, 1
0x004e, // 17: jmp x--, 14
0xe083, // 18: set pindirs, 3
0x2021, // 19: wait 0 pin, 1
0x20a1, // 20: wait 1 pin, 1
// .wrap
// .wrap_target
0x00c7, // 0: jmp pin, 7
0xe02a, // 1: set x, 10
0x2000 | PS2_CLOCK_PIN, // 2: wait 0 gpio, CLK
0x4001, // 3: in pins, 1
0x2080 | PS2_CLOCK_PIN, // 4: wait 1 gpio, CLK
0x0042, // 5: jmp x--, 2
0x0000, // 6: jmp 0
0x00e9, // 7: jmp !osre, 9
0x0000, // 8: jmp 0
0xff80 | PS2_DATA_PINDIR_BIT, // 9: set pindirs, DATA [31]
0xe280, // 10: set pindirs, 0 [2]
0xe080 | PS2_CLOCK_PINDIR_BIT, // 11: set pindirs, CLK
0x2000 | PS2_CLOCK_PIN, // 12: wait 0 gpio, CLK
0xe029, // 13: set x, 9
0x6081, // 14: out pindirs, 1
0x2080 | PS2_CLOCK_PIN, // 15: wait 1 gpio, CLK
0x2000 | PS2_CLOCK_PIN, // 16: wait 0 gpio, CLK
0x004e, // 17: jmp x--, 14
0xe083, // 18: set pindirs, 3
0x2000 | PS2_CLOCK_PIN, // 19: wait 0 gpio, CLK
0x2080 | PS2_CLOCK_PIN, // 20: wait 1 gpio, CLK
// .wrap
};
// clang-format on
@@ -133,9 +141,9 @@ void ps2_host_init(void) {
sm_config_set_wrap(&c, offset + PS2_WRAP_TARGET, offset + PS2_WRAP);
// Set pindirs to input (output enable is inverted below)
pio_sm_set_consecutive_pindirs(pio, state_machine, PS2_DATA_PIN, 2, true);
pio_sm_set_consecutive_pindirs(pio, state_machine, PS2_FIRST_PIN, 2, true);
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / (200.0f * KHZ));
sm_config_set_set_pins(&c, PS2_DATA_PIN, 2);
sm_config_set_set_pins(&c, PS2_FIRST_PIN, 2);
sm_config_set_out_pins(&c, PS2_DATA_PIN, 1);
sm_config_set_out_shift(&c, true, true, 10);
sm_config_set_in_shift(&c, true, true, 11);
+46
View File
@@ -0,0 +1,46 @@
/* Copyright 2021 dnaq
*
* 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 <limits.h>
#include "plover_hid.h"
#include "report.h"
#include "host.h"
#include "compiler_support.h"
// The button index handed to plover_hid_update() is `keycode - QK_PLOVER_HID`, so the report's
// data field must hold a bit for every keycode in the range or the bit-packing below overflows.
STATIC_ASSERT(sizeof(((report_plover_hid_t *)0)->data) * CHAR_BIT >= (QK_PLOVER_HID_MAX - QK_PLOVER_HID + 1), "Plover HID report data too small for the QK_PLOVER_HID keycode range");
static report_plover_hid_t plover_hid_report = {.report_id = REPORT_ID_PLOVER_HID};
static bool plover_hid_report_updated = false;
void plover_hid_update(uint8_t button, bool pressed) {
if (pressed) {
plover_hid_report.data[button / 8] |= (1 << (7 - (button % 8)));
} else {
plover_hid_report.data[button / 8] &= ~(1 << (7 - (button % 8)));
}
plover_hid_report_updated = true;
}
void plover_hid_task(void) {
if (!plover_hid_report_updated) {
return;
}
host_plover_hid_send(&plover_hid_report);
plover_hid_report_updated = false;
}
+3
View File
@@ -16,5 +16,8 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
void plover_hid_update(uint8_t button, bool pressed);
void plover_hid_task(void);
+4 -4
View File
@@ -89,11 +89,7 @@ usb_endpoint_in_t usb_endpoints_in[USB_ENDPOINT_IN_COUNT] = {
#endif
#if defined(PLOVER_HID_ENABLE)
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
[USB_ENDPOINT_IN_PLOVER_HID] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_INTR, PLOVER_HID_EPSIZE, PLOVER_HID_IN_EPNUM, PLOVER_HID_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(PLOVER_HID_EPSIZE)),
# else
[USB_ENDPOINT_IN_PLOVER_HID] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, PLOVER_HID_EPSIZE, PLOVER_HID_IN_EPNUM, PLOVER_HID_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(PLOVER_HID_EPSIZE)),
# endif
#endif
#if defined(MIDI_ENABLE)
@@ -127,6 +123,10 @@ usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES] = {
[XAP_INTERFACE] = USB_ENDPOINT_IN_XAP,
#endif
#if defined(PLOVER_HID_ENABLE)
[PLOVER_HID_INTERFACE] = USB_ENDPOINT_IN_PLOVER_HID,
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
[MOUSE_INTERFACE] = USB_ENDPOINT_IN_MOUSE,
#endif
+6 -22
View File
@@ -493,6 +493,12 @@ void send_digitizer(report_digitizer_t *report) {
#endif
}
void send_plover_hid(report_plover_hid_t *report) {
#ifdef PLOVER_HID_ENABLE
send_report(USB_ENDPOINT_IN_PLOVER_HID, report, sizeof(report_plover_hid_t));
#endif
}
/* ---------------------------------------------------------
* Console functions
* ---------------------------------------------------------
@@ -586,28 +592,6 @@ void xap_task(void) {
}
#endif // XAP_ENABLE
#ifdef PLOVER_HID_ENABLE
static bool plover_hid_report_updated = false;
static uint8_t plover_hid_current_report[PLOVER_HID_EPSIZE] = {0x50};
void plover_hid_update(uint8_t button, bool pressed) {
if (pressed) {
plover_hid_current_report[1 + button / 8] |= (1 << (7 - (button % 8)));
} else {
plover_hid_current_report[1 + button / 8] &= ~(1 << (7 - (button % 8)));
}
plover_hid_report_updated = true;
}
void plover_hid_task(void) {
if (!plover_hid_report_updated) {
return;
}
send_report(USB_ENDPOINT_IN_PLOVER_HID, plover_hid_current_report, sizeof(plover_hid_current_report));
plover_hid_report_updated = false;
}
#endif
#ifdef MIDI_ENABLE
void send_midi_packet(MIDI_EventPacket_t *event) {
+8
View File
@@ -342,6 +342,14 @@ void host_programmable_button_send(uint32_t data) {
__attribute__((weak)) void send_programmable_button(report_programmable_button_t *report) {}
#ifdef PLOVER_HID_ENABLE
void host_plover_hid_send(report_plover_hid_t *report) {
send_plover_hid(report);
}
#endif
__attribute__((weak)) void send_plover_hid(report_plover_hid_t *report) {}
#ifdef RAW_ENABLE
void host_raw_hid_send(uint8_t *data, uint8_t length) {
host_driver_t *driver = host_get_active_driver();
+1
View File
@@ -44,6 +44,7 @@ void host_mouse_send(report_mouse_t *report);
void host_system_send(uint16_t usage);
void host_consumer_send(uint16_t usage);
void host_programmable_button_send(uint32_t data);
void host_plover_hid_send(report_plover_hid_t *report);
void host_raw_hid_send(uint8_t *data, uint8_t length);
uint16_t host_last_system_usage(void);
+1
View File
@@ -37,3 +37,4 @@ typedef struct {
void send_joystick(report_joystick_t *report);
void send_digitizer(report_digitizer_t *report);
void send_programmable_button(report_programmable_button_t *report);
void send_plover_hid(report_plover_hid_t *report);
+6 -30
View File
@@ -68,10 +68,6 @@
# include "xap.h"
#endif
#ifdef PLOVER_HID_ENABLE
# include "plover_hid.h"
#endif
#ifdef WAIT_FOR_USB
// TODO: Remove backwards compatibility with old define
# define USB_WAIT_FOR_ENUMERATION
@@ -286,28 +282,6 @@ void xap_task(void) {
}
#endif // XAP_ENABLE
#ifdef PLOVER_HID_ENABLE
static bool plover_hid_report_updated = false;
static uint8_t plover_hid_current_report[PLOVER_HID_EPSIZE] = {0x50};
void plover_hid_update(uint8_t button, bool pressed) {
if (pressed) {
plover_hid_current_report[1 + button / 8] |= (1 << (7 - (button % 8)));
} else {
plover_hid_current_report[1 + button / 8] &= ~(1 << (7 - (button % 8)));
}
plover_hid_report_updated = true;
}
void plover_hid_task(void) {
if (!plover_hid_report_updated) {
return;
}
send_report(PLOVER_HID_IN_EPNUM, plover_hid_current_report, sizeof(plover_hid_current_report));
plover_hid_report_updated = false;
}
#endif
/*******************************************************************************
* Console
******************************************************************************/
@@ -711,6 +685,12 @@ void send_digitizer(report_digitizer_t *report) {
#endif
}
void send_plover_hid(report_plover_hid_t *report) {
#ifdef PLOVER_HID_ENABLE
send_report(PLOVER_HID_IN_EPNUM, report, sizeof(report_plover_hid_t));
#endif
}
/*******************************************************************************
* sendchar
******************************************************************************/
@@ -986,10 +966,6 @@ void protocol_post_task(void) {
MIDI_Device_USBTask(&USB_MIDI_Interface);
#endif
#ifdef PLOVER_HID_ENABLE
plover_hid_task();
#endif
#ifdef VIRTSER_ENABLE
virtser_task();
CDC_Device_USBTask(&cdc_device);
+10
View File
@@ -44,6 +44,11 @@ enum hid_report_ids {
#define IS_VALID_REPORT_ID(id) ((id) >= REPORT_ID_ALL && (id) <= REPORT_ID_COUNT)
// Plover HID has its own dedicated interface rather than the shared endpoint, so its report ID
// is fixed by the protocol at 0x50 ('P') and is intentionally NOT a member of enum
// hid_report_ids above (which only enumerates shared-endpoint reports up to REPORT_ID_COUNT).
#define REPORT_ID_PLOVER_HID 0x50
/* Mouse buttons */
#define MOUSE_BTN_MASK(n) (1 << (n))
enum mouse_buttons {
@@ -193,6 +198,11 @@ typedef struct {
uint32_t usage;
} PACKED report_programmable_button_t;
typedef struct {
uint8_t report_id; // REPORT_ID_PLOVER_HID
uint8_t data[8];
} PACKED report_plover_hid_t;
#ifdef MOUSE_EXTENDED_REPORT
# define MOUSE_REPORT_XY_MIN (INT16_MIN + 1)
# define MOUSE_REPORT_XY_MAX INT16_MAX
+5
View File
@@ -40,6 +40,7 @@
#include "report.h"
#include "usb_descriptor.h"
#include "usb_descriptor_common.h"
#include "compiler_support.h"
#ifdef JOYSTICK_ENABLE
# include "joystick.h"
@@ -494,6 +495,10 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM PloverReport[] = {
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
};
// The Plover HID report is sent with sizeof(report_plover_hid_t), but the endpoint and descriptor
// are sized with PLOVER_HID_EPSIZE; they must match or reports get truncated/padded.
STATIC_ASSERT(sizeof(report_plover_hid_t) == PLOVER_HID_EPSIZE, "report_plover_hid_t size must match PLOVER_HID_EPSIZE");
#endif
#ifdef CONSOLE_ENABLE