Linux输入子系统:输入设备编程指南 -- input-programming.txt

本文介绍了Linux内核中的输入子系统,包括基本事件类型如EV_KEY、EV_REL和EV_ABS的工作原理,按键自动重复机制,以及如何处理LED和声音事件等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本事件类型(types)

~~~~~~~~~~~~~~~~~~~~~

最简单的事件类型是EV_KEY,它用于键盘和按钮,它通过以下函数上报给input子系统:

  1. input_report_key(struct input_dev *dev, int code, int value)  
linux/input.h定义了该类型可用的values和code (从0 到 KEY_MAX)。Value被解释为真假值,也就是任何非0值意味着键被按下,0则意味着键被松开。input子系统的代码只有当value的值和之前的值不同时才会生成一次事件。

除了EV_KEY外,还有另外两个基本的事件类型:EV_REL和EV_ABS 。它们用来提供设备的相对和绝对值。鼠标移动是一种相对值,鼠标报告相对于上一个位置的相对差值,因为它工作在没有任何绝对坐标系系统中。绝对值事件对游戏操纵杆和数字化仪有用,这些设备工作在一个绝对坐标系统中。

设备上报EV_REL就像EV_KEY一样简单,只要设置相应的位然后调用以下函数即可:

  1. input_report_rel(struct input_dev *dev, int code, int value)  

只有当非0的value时,事件才会被产生。

不过EV_ABS需要一点点特别的处理。在调用input_register_device之前,你需要在input_dev结构中为你的设备所支持的轴填充的额外字段。假如我们的按钮设备有ABS_X轴:

  1. button_dev.absmin[ABS_X] = 0;  
  2. button_dev.absmax[ABS_X] = 255;  
  3. button_dev.absfuzz[ABS_X] = 4;  
  4. button_dev.absflat[ABS_X] = 8;  

或者,你只需要这样:

  1. 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中相应的位,而且要实现一个回调函数:

  1. button_dev->event = button_event;  
  2.   
  3. int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);  
  4. {  
  5.     if (type == EV_SND && code == SND_BELL) {  
  6.         outb(value, BUTTON_BELL);  
  7.         return 0;  
  8.     }  
  9.     return -1;  
  10. }  

这个回调可以在中断上下文或者BH上下文中被调用,所以它不能睡眠,不要处理太长的时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值