Zephyr输入子系统-3输入设备和KSCAN兼容

本文简要介绍输入设备的实现情况和对Kscan的兼容。

输入设备 链接到标题

在输入子系统导入前,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即可

ft5336@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的设备树节点

#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);

当遇到下面这个设备树

ft5336@38 {
		compatible = "focaltech,ft5336";
		reg = <0x38>;
		int-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;

		kscan_input: kscan-input {
			compatible = "zephyr,kscan-input";
		};
	};

就会被展开为

	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);

也就是kscan向输入子系统注册一个监听器kscan_input_cb_0当触摸屏有事件发生时,会调用kscan_input_cb_0->kscan_input_cb


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的三个接口函数的实现

static 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