【Linux驱动开发】input子系统

input子系统负责处理输入事件,属于字符设备。input子系统分为input驱动层、input核心层和input事件层。系统启动后,在/sys/class/input/路径下显示input子系统。

  • input驱动层:输入设备的具体驱动程序,如按键驱动,向内核层报告输入内容。
  • input核心层:为驱动层提供输入设备注册和操作接口,通知事件层对输入事件进行处理。
  • input事件层:与用户空间进行信息交互。

input子系统的主设备号都是13,不需要注册字符设备,只需注册一个input设备。

Linux定义input_dev结构体表示input设备,include/linux/input.h。

struct input_dev {
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;

	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];    /* 事件类型的位图 */
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  /* 按键值的位图 */
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];  /* 相对坐标的位图 */
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  /* 绝对坐标的位图 */
	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  /* 杂项事件的位图 */
	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  /*LED 相关的位图 */
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  /* sound 有关的位图 */
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];    /* 压力反馈的位图 */
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];    /*开关状态的位图 */

/*... */

	bool devres_managed;
};

xxbit表示输入事件类型事件类型事件值include/uapi/linux/input.h文件下。

#define EV_SYN			0x00    /* 同步事件 */
#define EV_KEY			0x01    /* 按键事件 */
#define EV_REL			0x02    /* 相对坐标事件 */
#define EV_ABS			0x03    /* 绝对坐标事件 */
#define EV_MSC			0x04    /* 杂项事件 */
#define EV_SW			0x05    /* 开关事件 */
#define EV_LED			0x11    /* LED */
#define EV_SND			0x12    /* 声音 */
#define EV_REP			0x14    /* 重复事件 */
#define EV_FF			0x15    /* 压力事件 */
#define EV_PWR			0x16    /* 电源事件 */
#define EV_FF_STATUS	0x17    /* 压力状态事件 */
#define EV_MAX			0x1f
#define EV_CNT			(EV_MAX+1)

使用input_allocate_device申请一个input_dev。

struct input_dev *input_allocate_device(void)
  • 返回值:申请到的input_dev。

使用input_free_device释放input_dev。

void input_free_device(struct input_dev *dev);
  • dev:要释放的input_dev。
  • 返回值:无。

使用input_register_device向Linux内核注册input_dev。

int input_register_device(struct input_dev *dev);
  • dev:要注册的input_dev。
  • 返回值:0,成功;负值,失败。

使用input_register_device注销input_dev。

void input_unregister_device(struct input_dev *dev);
  • dev:要注销的input_dev。
  • 返回值:无。

input_dev注册流程

  1. 使用input_allocate_device申请一个input_dev。
  2. 初始化input_dev的事件类型和事件值,三种设置方法
  3. 使用input_register_device向Linux内核注册input_dev。
  4. 卸载input驱动,先使用input_unregister_device,然后使用input_free_device。
#define INPUT_DEV_NAME  "input_name"

struct input_dev *inputdev;  /* input结构体变量 */

static int __init xxx_init(void)
{
    inputdev = input_allocate_device(); /* 申请一个input_dev */
    inputdev->name = INPUT_DEV_NAME;

    /* 设置事件类型和事件值,以按键为例 */
    /* 方法一 */
    __set_bit(EV_KEY, inputdev->evbit); /* 设置产生按键事件 */
    __set_bit(EV_REP, inputdev->evbit); /* 设置重复事件 */
    __set_bit(KEY_0, inputdev->keybit); /* 设置事件值,这里是按键的值 */

    /* 方法二 */
    inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
    inputdev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0);
    
    /* 方法三 */
    inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
    input_set_capability(inputdev, EV_KEY, KEY_0);

    input_register_device(inputdev); /* 注册input_dev */

    return 0;
}

static void __exit xxx_exit(void)
{
    input_unregister_device(inputdev);  /* 注销input_dev */
    input_free_device(inputdev);        /* 删除input_dev */
}

input_dev设备注册成功后,需要上报输入事件(输入的值)。

使用input_event上报事件和对应的值,Linux也提供了其他针对具体事件的上报函数,如input_report_key、input_report_rel、input_report_abs等都是基于input_event函数的,include/linux/input.h。

void input_event(struct input_dev *dev, 
                 unsigned int     type,
                 unsigned int     code,
                 int              value)
  • dev:要上报的input_dev。
  • type:上报的事件类型。
  • code:事件码,例如注册的按键值KEY_0等。
  • value:事件值,例如1按键按下,0按键松开。
  • 返回值:无。

上报事件后,使用input_sync通知Linux内核input子系统上报结束,input_sync本质是上报一个同步事件。

void input_sync(struct input_dev *dev);
  • dev:要上报同步的input_dev。
  • 返回值:无。

Linux定义input_event结构体表示所有输入事件,include/uapi/linux/input.h。

struct timeval
{
	long tv_sec;  /* 秒 */
	long tv_usec; /* 微秒 */
};

struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};
  • time:事件发生的时间,秒和微秒都是long类型。
  • type:事件类型,如按键事件EV_KEY。
  • code:事件码,如按键事件中KEY_0、KEY_1等键值。
  • value:事件值,如按键事件中1,按键按下;0,按键松开。

input_event类型的原始事件数据值,以KEY_0按键按下和松开为例,使用命令查看input事件信息。

hexdump /dev/input/event1
/* 编号 */ /* tv_sec */ /* tv_usec */ /* type */ /* code */ /* value */
0000000     0c41 0000     d7cd 000c     0001        000b     0001 0000
0000010     0c41 0000     d7cd 000c     0000        0000     0000 0000
0000020     0c42 0000     54bb 0000     0001        000b     0000 0000
0000030     0c42 0000     54bb 0000     0000        0000     0000 0000
  • 第 1 行,表示EV_KEY事件,按下按键事件。EV_KEY事件值为1;KEY_0按键编号为11,对应的十六进制为0xb;按键值,1表示按下,0的话表示松开。
  • 第 2 行,表示EV_SYN事件,同步。
  • 第 3 行,表示EV_KEY事件,松开按键事件。
  • 第 4行,表示EV_SYN事件,同步。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奶油芝士汉堡包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值