input 子系统是管理输入的子系统,和pinctrl、gpio 子系统一样,都是Linux 内核针对某一类设备而创建的框架。
input 子系统分为 input 驱动层、input 核心层、input 事件处理层,最终给用户空间提供可访问的设备节点。
struct input_dev *input_allocate_device(void)
返回值:申请到的input_dev
需要初始化的内容主要为事件类型(evbit) 和 事件值(keybit)这两种。
keyinputdev.inputdev = input_allocate_device();
keyinputdev.inputdev->name = KEYINPUT_NAME;
keyinputdev.inputdev->evbit[0] = BIT_MASK( EV_KEY ) | BIT_MASK( EV_REP );
input_set_capability( keyinputdev.inputdev, EV_KEY, KEY_3 );
int input_register_device(struct input_dev *dev)
dev : 要注册的input_dev
返回值:0,input_dev 注册成功;负值,input_dev 注册失败。
利用input 子系统编写按键驱动,input 子系统并不负责按键按下的检测。为了实现按键的检测,我们还是需要:
在上面的第4步,读取到gpio 的输入值之后,调用input 子系统的上报函数,上报输入事件。
不同的事件,其上报事件的API 函数不同。按键事件的上报API 如下:
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}
我们需要上报同步事件,告知input 子系统 上报结束
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
从上面可以看到,上报按键事件和上报同步事件,调用的都是input_event 函数。input_event 函数可以上报所有的事件类型和事件值。下面是input_event 的声明:
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
函数参数和返回值含义如下:
dev : 需要上报的input_dev 。
type: 上报的事件类型,比如:EV_KEY 。
code : 事件码,也就是我们注册的按键编号,比如:KEY_0
value : 事件值,比如1表示按键按下,0表示按键松开。
卸载input 驱动的时候,需要先注销input_dev
void input_unregister_device( struct input_dev *dev );
然后释放 input_dev
void input_free_device( struct input_dev *dev );
Linux 内核使用input_event 这个结构体来表示所有的输入事件,结构体定义在 include/uapi/linux/input.h 文件中。
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
err = read( fd, &inputevent, sizeof( inputevent ) );
//读取数据成功
if ( err > 0 )
{
switch ( inputevent.type )
{
case EV_KEY:
if ( inputevent.code < BTN_MISC )
{
printf( "key %d %s\r\n", inputevent.code, inputevent.value ? "press": "release" );
}
else
{
printf( "button %d %s\r\n", inputevent.code, inputevent.value ? "press": "release" );
}
break;
}
}