fix(split): Use our managed queue for input report to avoid deadlock

- Use our service work queue to process input report to avoid deadlock on the system work queue
- Add config `CONFIG_ZMK_INPUT_SPLIT_MSG_QUEUE_SIZE`
This commit is contained in:
tomori-k 2025-11-08 00:26:17 +09:00
parent 7738924349
commit f060e3f375
2 changed files with 50 additions and 1 deletions

View File

@ -102,6 +102,17 @@ config BT_GAP_AUTO_UPDATE_CONN_PARAMS
endif # !ZMK_SPLIT_ROLE_CENTRAL
if ZMK_INPUT_SPLIT
config ZMK_INPUT_SPLIT_MSG_QUEUE_SIZE
int "Max number of input split messages to queue for sending over BLE"
default 32
help
Sets the maximum number of input split events that can be queued for BLE notifications.
Increasing this reduces drops during high-rate input bursts at the cost of additional RAM.
endif # ZMK_INPUT_SPLIT
endmenu
endif # ZMK_SPLIT_BLE

View File

@ -312,6 +312,27 @@ static int zmk_split_bt_sensor_triggered(uint8_t sensor_index,
#if IS_ENABLED(CONFIG_ZMK_INPUT_SPLIT)
struct input_event_notify_item {
uint16_t attr_index;
struct zmk_split_input_event_payload payload;
};
K_MSGQ_DEFINE(input_event_msgq, sizeof(struct input_event_notify_item),
CONFIG_ZMK_INPUT_SPLIT_MSG_QUEUE_SIZE, 4);
static void send_input_event_callback(struct k_work *work) {
struct input_event_notify_item item;
while (k_msgq_get(&input_event_msgq, &item, K_NO_WAIT) == 0) {
int err = bt_gatt_notify(NULL, &split_svc.attrs[item.attr_index], &item.payload,
sizeof(item.payload));
if (err) {
LOG_ERR("Error notifying input event %d", err);
}
}
}
static K_WORK_DEFINE(service_input_notify_work, send_input_event_callback);
static int zmk_split_bt_report_input(uint8_t reg, uint8_t type, uint16_t code, int32_t value,
bool sync) {
@ -326,7 +347,24 @@ static int zmk_split_bt_report_input(uint8_t reg, uint8_t type, uint16_t code, i
.sync = sync ? 1 : 0,
};
return bt_gatt_notify(NULL, &split_svc.attrs[i], &payload, sizeof(payload));
struct input_event_notify_item item = {.attr_index = (uint16_t)i, .payload = payload};
int err = k_msgq_put(&input_event_msgq, &item, K_NO_WAIT);
if (err == 0) {
k_work_submit_to_queue(&service_work_q, &service_input_notify_work);
return 0;
} else {
LOG_WRN("Input event queue full, dropping one and retry");
struct input_event_notify_item discarded;
k_msgq_get(&input_event_msgq, &discarded, K_NO_WAIT);
err = k_msgq_put(&input_event_msgq, &item, K_NO_WAIT);
if (err != 0) {
LOG_WRN("Failed to queue input event (%d)", err);
return err;
}
}
}
}
return -ENODEV;