输入设备
在输入子系统导入前,Zephyr的输入设备大部分都放在zephyr/drivers/kscan/
下以kscan的接口和应用对接,导入输入子系统同时zephyr也开始添加输入设备驱动在zephyr/drivers/input
下面,目前支持
- ft5336
- gpio-key
- npcx-kbd
- sdl-touch
这些驱动的设备树绑定在zephyr/dts/bindings/input
内,将来kscan的驱动将被逐步转换为输入设备驱动。
输入设备驱动通过输入子系统的input_report
发送输入事件,没有定义其它和应用程序的接口。实现输入设备驱动只需要根据其硬件特性设计设备树绑定文件,并撰写驱动程序,将从硬件获得的输入事件用input_report
送到输入子系统即可。
Kscan兼容
现阶段,上层应用和模块(例如lvgl)都还使用的时kscan作为输入,为了让输入系统兼容kscan,在kscan驱动中引入了input。当需要一个input设备驱动兼容kscan时,在其设备树内加入kscan_input
即可1
2
3
4
5
6
7
8
9ft5336@38 {
compatible = "focaltech,ft5336";
reg = <0x38>;
int-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
kscan_input: kscan-input {
compatible = "zephyr,kscan-input";
};
};
在zephyr/drivers/kscan/kscan_input.c
中会查找支持kscan_input的输入设备,并将其发送的event转换为kscan的.
先使用KSCAN_INPUT_INIT
遍历所有设kscan_input的设备树节点1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#define KSCAN_INPUT_INIT(index) \
static void kscan_input_cb_0(struct input_event *evt) \
{ \
kscan_input_cb(DEVICE_DT_GET(DT_INST(index, DT_DRV_COMPAT)), \
evt); \
} \
INPUT_LISTENER_CB_DEFINE(DEVICE_DT_GET(DT_INST_PARENT(index)), \
kscan_input_cb_0); \
static const struct kscan_input_config kscan_input_config_0 = { \
.input_dev = DEVICE_DT_GET(DT_INST_PARENT(index)), \
}; \
static struct kscan_input_data kscan_input_data_0; \
DEVICE_DT_INST_DEFINE(index, kscan_input_init, NULL, \
&kscan_input_data_0, \
&kscan_input_config_0, \
POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \
&kscan_input_driver_api);
当遇到下面这个设备树1
2
3
4
5
6
7
8
9ft5336@38 {
compatible = "focaltech,ft5336";
reg = <0x38>;
int-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
kscan_input: kscan-input {
compatible = "zephyr,kscan-input";
};
};
就会被展开为1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16static void kscan_input_cb_0(struct input_event *evt) \
{ \
kscan_input_cb(DEVICE_DT_GET(DT_INST(index, DT_DRV_COMPAT)), \
evt); \
} \
INPUT_LISTENER_CB_DEFINE(DEVICE_DT_GET(DT_INST_PARENT(index)), \
kscan_input_cb_0); \
static const struct kscan_input_config kscan_input_config_0 = { \
.input_dev = DEVICE_DT_GET(DT_INST_PARENT(index)), \
}; \
static struct kscan_input_data kscan_input_data_0; \
DEVICE_DT_INST_DEFINE(index, kscan_input_init, NULL, \
&kscan_input_data_0, \
&kscan_input_config_0, \
POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \
&kscan_input_driver_api);
也就是kscan向输入子系统注册一个监听器kscan_input_cb_0
当触摸屏有事件发生时,会调用kscan_input_cb_0->kscan_input_cb
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
static void kscan_input_cb(const struct device *dev, struct input_event *evt)
{
struct kscan_input_data *data = dev->data;
//按照event code转换为kscan的参数
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;
}
//通过kscan的callback通知应用
if (evt->sync) {
LOG_DBG("input event: %3d %3d %d",
data->row, data->col, data->pressed);
if (data->callback) {
data->callback(dev, data->row, data->col, data->pressed);
}
}
}
kscan的三个接口函数的实现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
38static int kscan_input_configure(const struct device *dev,
kscan_callback_t callback)
{
struct kscan_input_data *data = dev->data;
if (!callback) {
LOG_ERR("Invalid callback (NULL)");
return -EINVAL;
}
data->callback = callback;
return 0;
}
static int kscan_input_enable_callback(const struct device *dev)
{
struct kscan_input_data *data = dev->data;
data->enabled = true;
return 0;
}
static int kscan_input_disable_callback(const struct device *dev)
{
struct kscan_input_data *data = dev->data;
data->enabled = false;
return 0;
}
static const struct kscan_driver_api kscan_input_driver_api = {
.config = kscan_input_configure,
.enable_callback = kscan_input_enable_callback,
.disable_callback = kscan_input_disable_callback,
};
kscan-input只是目前输入子系统导入的一个兼容kscan的过渡,当kscan的驱动全部被迁移为输入设备驱动后,kscan将会被废弃
参考
https://docs.zephyrproject.org/3.4.0/services/input/index.html