基本事件类型(types)
~~~~~~~~~~~~~~~~~~~~~
最简单的事件类型是EV_KEY,它用于键盘和按钮,它通过以下函数上报给input子系统:
- input_report_key(struct input_dev *dev, int code, int value)
除了EV_KEY外,还有另外两个基本的事件类型:EV_REL和EV_ABS 。它们用来提供设备的相对和绝对值。鼠标移动是一种相对值,鼠标报告相对于上一个位置的相对差值,因为它工作在没有任何绝对坐标系系统中。绝对值事件对游戏操纵杆和数字化仪有用,这些设备工作在一个绝对坐标系统中。
设备上报EV_REL就像EV_KEY一样简单,只要设置相应的位然后调用以下函数即可:
- input_report_rel(struct input_dev *dev, int code, int value)
只有当非0的value时,事件才会被产生。
不过EV_ABS需要一点点特别的处理。在调用input_register_device之前,你需要在input_dev结构中为你的设备所支持的轴填充的额外字段。假如我们的按钮设备有ABS_X轴:
- button_dev.absmin[ABS_X] = 0;
- button_dev.absmax[ABS_X] = 255;
- button_dev.absfuzz[ABS_X] = 4;
- button_dev.absflat[ABS_X] = 8;
或者,你只需要这样:
- input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8);
上述设置适合于一个游系操纵杆设备,它有一个X轴,最小值是0,最大值是255(这表明它必须能提供的范围,偶尔上报超出该范围也不会有问题,但它必须要能达到最大和最小值)
,它的噪声范围是+-4,并且有一个大小是8的中心点。
如果你不需要absfuzz和absflat,你可以把它们设置为0,这意味着它是绝对准确的并总是返回正中心位置(如果他有的话)。
1.4 BITS_TO_LONGS(), BIT_WORD(), BIT_MASK()
~~~~~~~~~~~~~~~~~~~~~~~~~~
这3个宏来自bitops.h,有助于进行位域计算:
- BITS_TO_LONGS(x) - 返回x位的位域数组需要多少个long类型来组成。
- BIT_WORD(x) - 返回位域数组中第x位所对应的按long为单位的索引。
- BIT_MASK(x) - 返回位x对应的long型的mask值。
1.5 The id* and name fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dev->name字段应该要在驱动程序注册输入设备之前设置好。它是一个像'Generic button device'之类的对用户友好的设备名字符串
id*字段包含了总线的ID(PCI,USB...),厂商ID和设备ID。总线IDs在input.h中定义。厂商和设备IDs在pci_ids.h,usb_ids.h和类似的头文件中定义。这些字段也应该在注册设备之前被设置好。
idtype字段可以被用作输入设备的专有信息。
这些id和name字段可以通过evdev接口传递到用户空间中。
1.6 keycode, keycodemax, keycodesize 字段
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这3个字段用于需要键值映射的输入设备,keycode是一个用于把扫描码转换为输入系统键值的数组,keycodemax是这个数组的大小,keycodesize则是该数组每个元素的大小(以字节为单位)
用户空间可以通过相应的evdev接口,使用EVIOCGKEYCODE和EVIOCSKEYCODE ioctls来查询和修改当前的扫描码到键值的映射表。当设备填充了3个上述的字段,驱动程序可以根据kernel的默认实现来设置和查询键值映射表。
1.7 dev->getkeycode() and dev->setkeycode()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
getkeycode()和setkeycode()回调允许驱动程序覆写由input核心代码提供的对keycode/keycodemax/keycodesize的默认映射机制,从而可以实现稀疏的映射方式。
1.8 按键的autorepeat
~~~~~~~~~~~~~~~~~~
... 很简单,它由input.c模块处理。硬件autorepeat没有被使用,因为很多设备不存在该功能,而且就算存在该功能,有时候也不正常(例如,Toshiba笔记本中的键盘)。要使能你的设备的autorepeat功能,只要设置dev->evbit中的EV_REP位即可,其它的事情都有输入子系统处理。
1.9 其它的事件types, 输出事件处理
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
现在为止,其它的事件types有:
- EV_LED - 用作键盘的LEDs灯。
- EV_SND - 用于键盘的蜂鸣器。
它们和键盘事件很相似,但是它们按另一个方向走动 - 从系统到输入设备驱动程序。如果你的驱动程序可以处理这些事件,必须设置evbit中相应的位,而且要实现一个回调函数:
- button_dev->event = button_event;
- int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
- {
- if (type == EV_SND && code == SND_BELL) {
- outb(value, BUTTON_BELL);
- return 0;
- }
- return -1;
- }
这个回调可以在中断上下文或者BH上下文中被调用,所以它不能睡眠,不要处理太长的时间