linux输入子系统(2)

<!--[if !supportLists]-->1.3 <!--[endif]-->输入子系统设备驱动讲解

<!--[if !supportLists]-->1.3.1 <!--[endif]-->打开和关闭函数

struct input_dev中有openclose两个函数指针。在与handler第一次连接之后会调用open函数,断开连接会调用closeopen中应该完成硬件初始化的相关工作,并且申请用到的其他资源,如中断号。close函数做相反的工作。

<!--[if !supportLists]-->1.3.2 <!--[endif]-->事件类型

Linux输入子系统支持的事件类型如程序清单 1.6<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000300034003700310038000000</w:data> </xml><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark:_Ref282004718'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282004718'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span><![endif]-->1<!--[if supportFields]><span style='mso-bookmark: _Ref282004718'></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282004718'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282004718'><span lang=EN-US> SEQ </span></span><span style='mso-bookmark:_Ref282004718'><span style='font-family:黑体;mso-ascii-font-family: Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element: field-separator'></span></span></span><![endif]-->6<!--[if supportFields]><span style='mso-bookmark:_Ref282004718'></span><span style='mso-element:field-end'></span><![endif]--> 输入子系统事件类型

/* include/linux/input.h */

#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 /* led */

#define EV_SND 0x12 /* beep */

#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)是最简单的事件类型,用来描述按键或者按钮。报告按键事件使用以下函数:

input_report_key(struct input_dev *dev, int code, int value)

code的值在<内核>include/linux/input.h中定义,大小从0KEY_MAX value0时表示按键抬起,非0时代表按键按下。对同一个按键来说,只有当value的值和上次不同才会产生一次事件。

除了按键事件,相对坐标事件(EV_REL)和绝对坐标事件(EV_ABS)也是常用的事件。为了使设备支持这两类事件,需要在初始化时对struct input_devevbit相应比特置1,并且还要分别在relbitabsbit位图中为支持的坐标轴置1。参考<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282006937 \r \h <span style='mso-element:field-separator'></span></span><![endif]-->1.2<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000300036003900330037000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->节的78两步。

相对坐标事件用来描述类似鼠标移动的消息。报告相对坐标的函数如下:

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

code描述坐标轴,value代表相对移动(可正可负)。只有当value的值非零时才能产生一个有效的事件。

绝对坐标需要额外的工作。初始化时需要填充input_dev中的一些数据域。对于支持的每个坐标轴调用如下函数:

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

函数参数从右往左依次代表输入设备指针、坐标轴、最小值、最大值、分辨率、基准值。最后两个参数也可以填为0,代表设备非常精确并且总能精确的回到中心位置。

input_set_abs_params函数的代码如<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282008551 \h <span style='mso-element:field-separator'></span></span><![endif]-->程序清单 1.7<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000300038003500350031000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark:_Ref282008551'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282008551'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span><![endif]-->1<!--[if supportFields]><span style='mso-bookmark: _Ref282008551'></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282008551'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282008551'><span lang=EN-US> SEQ </span></span><span style='mso-bookmark:_Ref282008551'><span style='font-family:黑体;mso-ascii-font-family: Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element: field-separator'></span></span></span><![endif]-->7<!--[if supportFields]><span style='mso-bookmark:_Ref282008551'></span><span style='mso-element:field-end'></span><![endif]--> 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)

{

dev->absmin[axis] = min;

dev->absmax[axis] = max;

dev->absfuzz[axis] = fuzz;

dev->absflat[axis] = flat;

dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); /* 这一行已经注册了坐标 */

}

另外输入设备驱动中经常用到同步事件(EV_SYN),输入子系统会默认支持此事件,驱动无需注册。鼠标、触摸板之类的设备需要用它来提示上层已经发送完了一个完整的事件报告。同步事件的报告形式如下:

input_sync(zlgkpd->input);

<!--[if !supportLists]-->1.3.3 <!--[endif]-->keycode keycodemaxkeycodesize

首先说明扫描码和键值的区别。如程序清单 1.4<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000300031003600390036000000</w:data> </xml><![endif]-->所示,例子中包含四个按键的值,那么扫描码的范围是0~3,键值就是keypad_keycode中的四个值。

keycode keycodemaxkeycodesize这三个数据域保存的值分别是键值数组的首地址、键值的个数和每个键值的字节大小。有了这三个变量,就可以在运行是改变键盘的键值映射。比如原来数组中的第四个键值为KEY_Z,可以根据需要改为KEY_D或者其他的值。这样同样的扫描码就对应的不同的键值。

这三个域正确填充之后,内核可以使用input_dev的成员函数来修改键值映射。修改映射的函数就是input_dev中的setkeycodegetkeycode这两个函数指针对应的函数,如果注册之前不初始化它们,则初始化函数把系统默认的函数赋给它们。

EVIOCGKEYCODEEVIOCSKEYCODE这两个ioctl命令分别用来查看和修改键值。

<!--[if !supportLists]-->1.3.4 <!--[endif]-->按键的自动连击

我们都有这样的经历:按住方向键不松开,一直把文档往某个方向拉。这个功能就是自动连击,也就是在按键抬起之前连续发送按键事件。

按键连击事件(EV_REP)的开启非常简单,在input_devdevbit相应比特置1即可。dev->rep[REP_DELAY]dev->rep[REP_PERIOD]分别存储连击的延时和周期,如果驱动不对它们赋值,则系统为他们分别赋为25033。按键延时即按键到第一次连击的间隔,按键周期即两次连击之间的间隔。它们的单位都是毫秒。

<!--[if !supportLists]-->1.3.5 <!--[endif]-->总线类型

input_devinput_id用到了总线类型。输入子系统支持的总线类型如程序清单 1.8<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000310037003100320031000000</w:data> </xml><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark:_Ref282017121'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282017121'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span><![endif]-->1<!--[if supportFields]><span style='mso-bookmark: _Ref282017121'></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282017121'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282017121'><span lang=EN-US> SEQ </span></span><span style='mso-bookmark:_Ref282017121'><span style='font-family:黑体;mso-ascii-font-family: Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element: field-separator'></span></span></span><![endif]-->8<!--[if supportFields]><span style='mso-bookmark:_Ref282017121'></span><span style='mso-element:field-end'></span><![endif]--> 输入子系统总线类型

/* include/linux/input.h */

#define BUS_PCI 0x01

#define BUS_ISAPNP 0x02

#define BUS_USB 0x03

#define BUS_HIL 0x04

#define BUS_BLUETOOTH 0x05

#define BUS_VIRTUAL 0x06

#define BUS_ISA 0x10

#define BUS_I8042 0x11

#define BUS_XTKBD 0x12

#define BUS_RS232 0x13

#define BUS_GAMEPORT 0x14

#define BUS_PARPORT 0x15

#define BUS_AMIGA 0x16

#define BUS_ADB 0x17

#define BUS_I2C 0x18

#define BUS_HOST 0x19

#define BUS_GSC 0x1A

#define BUS_ATARI 0x1B

<!--[if !supportLists]-->1.3.6 <!--[endif]-->其他的事件类型

EV_LEDEV_SND事件是针对键盘上的led和蜂鸣器。这两类事件是由输入子系统内核发送给驱动的。

如果驱动支持这两类事件的话,应该填充input_dev中的event函数指针,其实这是一个回调函数。另外需要填充input_devevbit对应的比特位。

这个回调函数可能在中断或者中断的底半部调用,因此event函数不能睡眠且必须尽快结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值