Linux驱动学习记录-19.INPUT子系统

按键、鼠标、键盘等设备都属于输入(input)设备。Linux内核有input子系统框架来处理事件。

一、INPUT子系统简介

在这里插入图片描述
我们写驱动程序主要关注中间的驱动层、核心层和事件层。分工如下:

  • 驱动层:输入设备的具体驱动程序。
  • 核心层:承上启下,为驱动层提供输入设备注册和操作接口。通知事件层进行处理。
  • 事件层:和用户空间交互。

二、驱动程序编写

在使用input子系统处理输入设备的时候不需要去注册字符设备。只需要向系统注册一个input_device即可:

1.input_dev说明

在使用input子系统的时候,只需要注册一个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)];
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
...
	unsigned int hint_events_per_packet;
	bool devres_managed;
};

其中evbit表示输入事件类型,定义如下:

/*
 * Event types
 */
#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
#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)

这次使用按键输入事件,所以选择EV_KEY,使用keybit。
按键值也定义在input.h按键值如下:

#define KEY_RESERVED		0
#define KEY_ESC			1
#define KEY_1			2
#define KEY_2			3
#define KEY_3			4
#define KEY_4			5
#define KEY_5			6
#define KEY_6			7
#define KEY_7			8
#define KEY_8			9
#define KEY_9			10
......

开发板上的按键值KEY设置为KEY_0

2.申请&注销input_dev

struct input_dev *input_allocate_device(void)
//返回结构体地址
void input_free_device(struct input_dev *dev)
//输入结构体地址

3.初始化input_dev

需要初始化的内容主要为事件类(evbit)和事件值(keybit)。

4.向内核注册&注销

int input_register_device(struct input_dev *dev)
//返回值0注册成功。负值注册失败
void input_unregister_device(struct input_dev *dev)

三、注册示例

struct input_dev *inputdev;

static int __init xxx_init(void)
{
	inputdev = input_allocate_device();
	inputdev->name = "test_inputdev";
	/*第一种*/
	__set_bit(EV_KEY, inputdev->evbit);
	__set_bit(EV_REP, inputdev->evbit);
	__set_bit(KEY_0, inputdev->keybit);
	/*第二种*/
	keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
	keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0);
	/*第三种*/
	keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
	input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0);
	//注册
	input_register_device(inputdev);
	return 0;
}
static void __exit xxx_exit(void)
{
	input_unregister_device(inputdev); //注销
	input_free_device(inputdev);  //删除
} 

四、通知示例

1.函数

input设备都有输入功能,驱动程序需要告诉内核,输入了什么,因此有了上报事件。一般在按键中断里上报。

void input_event(struct input_dev *dev, //需要上报的input_dev
				 unsigned int typr, //上报事件 EV_KEY
				 unsigend int code, //时间码:注册的按键值KEY_0
				 int value) //事件值,1、0
//下面是专门的按键上报,推荐使用这个
static inline void input_report_key(struct input_dev *dev,
									unsigned int code, 
									int value)
{
input_event(dev, EV_KEY, code, !!value);
}

上报完成后需要告诉内核,上报结束

void input_sync(struct input_dev *dev)

2.示例

void timer_function(unsigned long arg)
{
    unsigned char value;

	value = gpio_get_value(keydesc->gpio); /* 读取 IO 值 */
    if(value == 0){ /* 按下按键 */
	/* 上报按键值 */
		input_report_key(inputdev, KEY_0, 1); /* 最后一个参数 1, 按下 */
		input_sync(inputdev); /* 同步事件 */
	}
}

五、应用层的接收

1.input_event

Linux内核告诉input_event这个结构体所有的输入事件。

struct input_event{
	struct timeval time;
	__u16 type;
	__u16 vode;
	__s32 value;
};
struct timeval{
	__kernel_time_t  tv_sec; //秒
	__kernel_suseconds tv_usec; //微秒
}

2.示例

static struct input_event inputevent;

ina main (int argc, char *argv[])
{
	fd = open(argv[1], O_RDWR);
	err = reaf(fd, &inputevent, sizeof(inputevent));
	switch(inputevent.type){
	case EV_KEY:
	...
	}
}

六、驱动代码

见下章

七、编译测试

见下章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值