linux输入子系统

输入子系统

为了实现按键、触摸屏、鼠标等输入型设备的驱动程序设计,linux推荐使用的方法是input输入子系统输入型设备都可以利用input接口函数来实现设备驱动。

体系结构
在这里插入图片描述
在这里插入图片描述
输入子系统由驱动层,**输入子系统核心层(input core)和事件处理层(event handler)三部分组成。**一个输入事件,如鼠标移动,键盘按键按下,通过 Driver -> InputCore -> Event handler -> userspace 的顺序到达用户空间的应用程序。

  • 驱动层:
    将底层的硬件输入转化为统一事件型式,向输入核心(Input core)汇报。
  • 输入核心层:
    为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在**/PROC**下产生相应的设备信息。
  • 事件处理层:
    主要作用是和用户空间交互,我们知道linux在用户空间将所有设备当成文件来处理,在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,而在输入子系统中,这些工作都是由事件处理层完成的。

设备描述

在linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体描述),不再需要关心文件操作接口,因为input子系统已经完成了文件操作接口。驱动报告的事件经过InputCore和Eventhandler 最终到达用户空间。

设备注册、注销

  • 注册输入设备的函数为:
int input_register_device(struct input_dev *dev)
  • 注销输入设备的函数为:
void input_unregister_device(struct input_dev *dev)

驱动实现

事件支持

设备驱动通过 set_bit() 告诉 input 子系统它支持哪些事件,哪些按键。例:
set_bit(EV_KEY,button_dev.evbit)

struct input_dev 中有两个成员:
evbit:事件类型
keybit:按键类型

  • 事件类型
    EV_RST : Reset
    EV_REL: 相对坐标
    EV_MSC: 其他
    EV_SND: 声音
    EV_FF: 力反馈
    EV_KEY: 按键
    EV_ABS: 绝对坐标

    EV_LED: LED
    EV_REP: Repeat

当事件为 EV_KEY 时,还需指明按键类型
BTN_LEFT: 鼠标左键
BTN_RIGHT: 鼠标右键
BTN_MIDDLE: 鼠标中键
BTN_0: 数字0键
BTN_1: 数字1键

报告事件

用于报告 EV_KEY,EV_RELEV_ABS 事件的函数分别为:

  • void input_report_key(struct input_dev *dev,unsigned int code,int value)
  • void input_report_rel(struct input_dev *dev,unsigned int code,int value)
  • void input_report_abs(struct input_dev *dev,unsigned int code,int value)
    参数:
  • code:
    事件的代码。如果事件类型是 EV_KEY,则代码为设备的键盘代码。例如键盘上的按键代码值为0~127鼠标按键代码为:0x110----0x116,其中0x110(BTN_LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标右键,0x112(BTN_MODDLE)为鼠标中键,其他代码参考 /include/linux/input.h
  • value:
    事件的值。如果事件的类型是 EV_KEY,当按键按下时值为1,松开值为0

报告结束

input_sync()用于告诉 input core:此次报告已经结束

实例:
在触摸屏设备驱动中,一次点击的整个报告过程如下:

input_report_abs(input_dev,ABS_X,x); //x坐标
input_report_abs(input_dev,ABS_Y,y); //y坐标
input_report_abs(input_dev,ABS_PRESSURE,1); //x坐标

input_sync(input_dev);  //同步

实例分析

//在按键中断中报告事件
static void button_interrupt(int irq,void *dummy,struct pt_regs *fp)
{
	input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));
	input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT1));
	input_sync(&button_dev);
}

static int __init button_init(void)
{
	//申请中断
	if(request_irq(BUTTON_IRQ,button_interrupt,0,"button",NULL))
		return -EBUSY;

	set_bit(EV_KEY,button_dev.evbit);  //支持EV_KEY事件
	set_bit(BTN_0,button_dev.keybit);  //设置支持两个键
	set_bit(BTN_1,button_dev.keybit);  //设置支持两个键
	input_register_device(&button_dev);  //注册input设备
}

应用程序改动

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>

int main(void)
{
	int buttons_fd;
	int key_value, i = 0, count;
	 
	struct input_event ev_key;
	
	buttons_fd = open("/dev/event0",O_RDWR);
	if(buttons_fd < 0)
	{
		perror("open device buttons");
		exit(1);
	} 
	
	for(;;)
	{
		count = read(buttons_fd,&ev_key,sizeof(struct input_event));

	for(i = 0; i < (int)count/sizeof(struct input_event); i++)
	{
		if(EV_KEY == ev_key.type)
			printf("type:%d,code:%d,value:%d\n",ev_key.type,ev_key.code,ev_key.value);
	}
	
	if(EV_SYN == ev_key.type)
		printf("syn event\n\n");
	}
close(buttons_fd);
return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值