input 子系统

1、在linux开发中,输入子系统能产生那些事件呢??

Linux中输入设备的事件类型有(这里只列出了常用的一些,更多请看linux/input.h中):

EV_SYN 0x00 同步事件
EV_KEY 0x01 按键事件
EV_REL 0x02 相对坐标
EV_ABS 0x03 绝对坐标
EV_MSC 0x04 其它
EV_LED 0x11 LED
EV_SND 0x12 声音
EV_REP 0x14 Repeat
EV_FF 0x15 力反馈 
~~~~~~~~~~~~~~~~~~~~~~~~
EV_PWR 电源

EV_FF_STATUS 状态

与输入子系统有关的内核配置:  event interface  和 event debug 


2、输入子系统的组成

在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。下面用图形来描述一下这三者的关系吧!




输入子系统核心层位于drivers/input/input.c    其中提供了大量可以使用的函数;在linux/input.h中声明了大量的宏。

3、实现input驱动

3.1 设备描述:input_dev结构

声明一个结构体指针:

struct input_dev *input_device;

分配空间:

input_device =  input_allocate_device();

这里不要直接用kzalloc();  具体的看input_allocate_device();就知道了  这个函数不仅仅只是分配内存;

当然释放内存也不要用 kfree();  要用input_free_device();

填充input_dev 结构体

其中的name等等成员都是常见的就不说了,在这里都可以不填充,重要的是下面几个

unsigned long evbit[NBITS(EV_MAX)];
unsigned long keybit[NBITS(KEY_MAX)];
unsigned long relbit[NBITS(REL_MAX)];
unsigned long absbit[NBITS(ABS_MAX)];
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];

其中evbit用于设置是什么事件类型,本文开头就说了事件类型,当然可以设置多种事件类型,例如

set_bit(EV_ABS,input_device->evbit);
set_bit(EV_KEY,input_device->evbit);

这样就设置了两类事件既有按键事件也有绝对坐标事件;绝对坐标事件就可以用于触摸屏;

set_bit();这个函数是用来设置位的;具体的实现就不说了;自己可以在内核中查看源代码;

设置了按键还需要知道是什么按键,input子系统支持的按键类型也在linux/input.h用宏进行了声明;

/*
* Keys and buttons
*
* Most of the keys/buttons are modeled after USB HUT 1.12
* (see http://www.usb.org/developers/hidpage).
* Abbreviations in the comments:
* AC - Application Control
* AL - Application Launch Button
* SC - System Control
*/

#define KEY_RESERVED       0
#define KEY_ESC                   1
#define KEY_1                        2


………………

………………

………………

#define KEY_MIN_INTERESTING KEY_MUTE
#define KEY_MAX 0x1ff

我们需要设置input_device->keybit成员来声明我们用到的按键;

例如:

set_bit(BTN_TOUCH,input_device->keybit);

set_bit(KEY_1, input_device->keybit);

这样我们就说明了我们要使用的两个按键BTN_TOUCH,KEY_1;

对于EV_ABS事件也是一样的我们也要说明我们要用到的变量;在absbit中设置;内核支持的变量也在linux/input.h用宏进行了声明;

/*
* Absolute axes
*/

#define ABS_X                   0x00
#define ABS_Y 0x01
#define ABS_Z 0x02
#define ABS_RX 0x03
#define ABS_RY 0x04
#define ABS_RZ 0x05
#define ABS_THROTTLE 0x06
#define ABS_RUDDER 0x07
#define ABS_WHEEL 0x08
#define ABS_GAS 0x09
#define ABS_BRAKE 0x0a
#define ABS_HAT0X 0x10
#define ABS_HAT0Y 0x11
#define ABS_HAT1X 0x12
#define ABS_HAT1Y 0x13
#define ABS_HAT2X 0x14
#define ABS_HAT2Y 0x15
#define ABS_HAT3X 0x16
#define ABS_HAT3Y 0x17
#define ABS_PRESSURE 0x18
#define ABS_DISTANCE 0x19
#define ABS_TILT_X 0x1a
#define ABS_TILT_Y 0x1b
#define ABS_TOOL_WIDTH 0x1c
#define ABS_VOLUME 0x20
#define ABS_MISC         0x28
#define ABS_MAX                       0x3f

例如:

input_set_abs_params(input_device, ABS_X, 0, 0x3ff, 0, 0);
input_set_abs_params(input_device, ABS_Y, 0, 0x3ff, 0, 0);
input_set_abs_params(input_device,ABS_PRESSURE, 0, 1, 0, 0);

其中ABS_PRESSURE为压力值

input_set_abs_params)();函数的声明;

static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat);

具体实现大家去内核查看源代码:很简单就不多说了;


3.2 注册输入设备函数:int input_register_device(struct input_dev *dev) 

 input_register_device(input_device) ;

3.3 注销输入设备函数:void input_unregister_device(struct input_dev *dev) 

在卸载驱动时需要注销输入设备函数;

 input_unregister_device(input_device) ;

3.4 实现设备驱动核心工作是:向系统报告按键、触摸屏等输入事件(event,通过input_event结构描述),不再需要关心文件操作接口。驱动报告事件经过inputCore和Eventhandler到达用户空间。 

驱动设备正确注册后就可以,一旦时间发生了就可以向系统报告事件,具体的因个人代码不同而不同,可以在中断处理函数中,你也可以用查询等等,看自己程序的设计了;你需要向系统报告事件时就可以调用报告事件的函数;

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);

其中type是时间类型EV_SYN,EV_KEY,EV_ABS,等等

    code就是该类型下的某个值;例如EV_KEY下的KEY_1;      EV_ABS下的ABS_X  ,

    value就是code的值;

另外内核还特供了一些其他的函数input_report_abs();      input_report_key();     其实只不过是对input_event();的调用而已;

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}


static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}

这里就看程序员的选择了;不必多说 一看就懂;

最后还要写一个 input_sync(input_device)

static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}

这样就完成了事件的上报!!

上报的数据可以在/dev/event*中看到(用十六进制显示hexdump /dev/event*)  其中数据的含义如下

                        秒            |         微秒      |  typ    |  code   |       value
0000000      29a4 0000       8625 0008    0003      0000      0172 0000
0000010      29a4 0000       8631 0008    0003      0001      027c 0000
0000020      29a4 0000       8634 0008    0003      0018      0001 0000
0000030      29a4 0000       8638 0008     0001     014a      0001 0000






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值