Use an explicit callback name so that multiple instances of this do not result in a: redefinition of '_input_callback__longpress_cb' error. This used to work when it was using unique generated wrappers, but now it needs an index in the callback name. Use it in one of the API tests as well, just in case. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
125 lines
3.4 KiB
C
125 lines
3.4 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT input_keymap
|
|
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/dt-bindings/input/keymap.h>
|
|
#include <zephyr/input/input.h>
|
|
#include <zephyr/input/input_keymap.h>
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(input_keymap, CONFIG_INPUT_LOG_LEVEL);
|
|
|
|
struct keymap_config {
|
|
const struct device *input_dev;
|
|
const uint16_t *codes;
|
|
uint32_t num_codes;
|
|
uint8_t row_size;
|
|
uint8_t col_size;
|
|
};
|
|
|
|
struct keymap_data {
|
|
uint32_t row;
|
|
uint32_t col;
|
|
bool pressed;
|
|
};
|
|
|
|
static void keymap_cb(struct input_event *evt, void *user_data)
|
|
{
|
|
const struct device *dev = user_data;
|
|
const struct keymap_config *cfg = dev->config;
|
|
struct keymap_data *data = dev->data;
|
|
const uint16_t *codes = cfg->codes;
|
|
uint32_t offset;
|
|
|
|
switch (evt->code) {
|
|
case INPUT_ABS_X:
|
|
data->col = evt->value;
|
|
break;
|
|
case INPUT_ABS_Y:
|
|
data->row = evt->value;
|
|
break;
|
|
case INPUT_BTN_TOUCH:
|
|
data->pressed = evt->value;
|
|
break;
|
|
}
|
|
|
|
if (!evt->sync) {
|
|
return;
|
|
}
|
|
|
|
if (data->row >= cfg->row_size ||
|
|
data->col >= cfg->col_size) {
|
|
LOG_WRN("keymap event out of range: row=%u col=%u", data->row, data->col);
|
|
return;
|
|
}
|
|
|
|
offset = (data->row * cfg->col_size) + data->col;
|
|
|
|
if (offset >= cfg->num_codes || codes[offset] == 0) {
|
|
LOG_DBG("keymap event undefined: row=%u col=%u", data->row, data->col);
|
|
return;
|
|
}
|
|
|
|
LOG_DBG("input event: %3u %3u %d", data->row, data->col, data->pressed);
|
|
|
|
input_report_key(dev, codes[offset], data->pressed, true, K_FOREVER);
|
|
}
|
|
|
|
static int keymap_init(const struct device *dev)
|
|
{
|
|
const struct keymap_config *cfg = dev->config;
|
|
|
|
if (!device_is_ready(cfg->input_dev)) {
|
|
LOG_ERR("input device not ready");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define KEYMAP_ENTRY_OFFSET(keymap_entry, col_size) \
|
|
(MATRIX_ROW(keymap_entry) * col_size + MATRIX_COL(keymap_entry))
|
|
|
|
#define KEYMAP_ENTRY_CODE(keymap_entry) (keymap_entry & 0xffff)
|
|
|
|
#define KEYMAP_ENTRY_VALIDATE(node_id, prop, idx) \
|
|
BUILD_ASSERT(MATRIX_ROW(DT_PROP_BY_IDX(node_id, prop, idx)) < \
|
|
DT_PROP(node_id, row_size), "invalid row"); \
|
|
BUILD_ASSERT(MATRIX_COL(DT_PROP_BY_IDX(node_id, prop, idx)) < \
|
|
DT_PROP(node_id, col_size), "invalid col");
|
|
|
|
#define CODES_INIT(node_id, prop, idx) \
|
|
[KEYMAP_ENTRY_OFFSET(DT_PROP_BY_IDX(node_id, prop, idx), DT_PROP(node_id, col_size))] = \
|
|
KEYMAP_ENTRY_CODE(DT_PROP_BY_IDX(node_id, prop, idx)),
|
|
|
|
#define INPUT_KEYMAP_DEFINE(inst) \
|
|
INPUT_CALLBACK_DEFINE_NAMED(DEVICE_DT_GET(DT_INST_PARENT(inst)), keymap_cb, \
|
|
(void *)DEVICE_DT_INST_GET(inst), keymap_cb_##inst); \
|
|
\
|
|
DT_INST_FOREACH_PROP_ELEM(inst, keymap, KEYMAP_ENTRY_VALIDATE) \
|
|
\
|
|
static const uint16_t keymap_codes_##inst[] = { \
|
|
DT_INST_FOREACH_PROP_ELEM(inst, keymap, CODES_INIT) \
|
|
}; \
|
|
\
|
|
static const struct keymap_config keymap_config_##inst = { \
|
|
.input_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
|
|
.codes = keymap_codes_##inst, \
|
|
.num_codes = ARRAY_SIZE(keymap_codes_##inst), \
|
|
.row_size = DT_INST_PROP(inst, row_size), \
|
|
.col_size = DT_INST_PROP(inst, col_size), \
|
|
}; \
|
|
\
|
|
static struct keymap_data keymap_data_##inst; \
|
|
\
|
|
DEVICE_DT_INST_DEFINE(inst, keymap_init, NULL, \
|
|
&keymap_data_##inst, &keymap_config_##inst, \
|
|
POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(INPUT_KEYMAP_DEFINE)
|