跳转至

13.input 子系统

驱动程序

input_dev 注册过程如下:

1、使用 input_allocate_device 函数申请一个 input_dev。

2、初始化 input_dev 的事件类型以及事件值。

3、使用 input_register_device 函数向 Linux 系统注册前面初始化好的 input_dev。

4、卸载input驱动的时候需要先使用input_unregister_device 函数注销掉注册的input_dev,然后使用 input_free_device 函数释放掉前面申请的 input_dev。

struct key_dev{ 
    struct class *class;        
    struct device *device;
    struct device_node  *nd;
    struct gpio_desc *gpiod;
    struct timer_list timer;
    struct input_dev *inputdev; 
    int gpio;
    int irq;
    int major;              
    int minor;              
};

static int gpio_key_probe(struct platform_device *pdev)
{
    /*初始化引脚、注册中断、初始化定时器*/

    key.inputdev = input_allocate_device();
    key.inputdev->name = KEYINPUT_NAME;

#if 0
    /* 初始化input_dev,设置产生哪些事件 */
    __set_bit(EV_KEY, keyinputdev.inputdev->evbit); /* 设置产生按键事件          */
    __set_bit(EV_REP, keyinputdev.inputdev->evbit); /* 重复事件,比如按下去不放开,就会一直输出信息*/

    /* 初始化input_dev,设置产生哪些按键 */
    __set_bit(KEY_0, keyinputdev.inputdev->keybit); 
#endif

#if 0
    keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
    keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0);
#endif

#if 1
    key.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
    input_set_capability(key.inputdev, EV_KEY, KEY_0);
#endif

    /* 注册输入设备 */
    ret = input_register_device(key.inputdev);
    if (ret) {
        printk("register input device failed!\r\n");
        return ret;
    }

    return 0;
}

在remove中释放掉这个注册的函数

static int gpio_key_remove(struct platform_device *pdev)
{
    printk("%s %s line %d\r\n", __FILE__, __FUNCTION__, __LINE__);
    /* 释放input_dev */
    input_unregister_device(key.inputdev);
    input_free_device(key.inputdev);
    //释放gpio
    gpiod_put(key.gpiod);
    del_timer(&key.timer);
    //注销中断
    free_irq(key.irq, &key);
    return 0;
}

上报输入事件

在这个例程中,我在中断中触发了一个定时器,所以在定时器处理函数中来进行按键值的上报

static void key_timer_expire(unsigned long data)
{
    /* data ==> gpio */
    struct key_dev *gpio_key = (struct key_dev *)data;

    int val;
    val = gpiod_get_value(gpio_key->gpiod);

    printk("key %d %d\n", gpio_key->gpio, val); 

    if(val == 0){                       /* 按下按键 */
        /* 上报按键值 */
        //input_event(dev->inputdev, EV_KEY, KEY_0, 1);
        input_report_key(gpio_key->inputdev, KEY_0, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
        input_sync(gpio_key->inputdev);
        printk("input_sync1\n");    
    } else {                                    /* 按键松开 */
        //input_event(dev->inputdev, EV_KEY, KEY_0, 0);
        input_report_key(gpio_key->inputdev, KEY_0, 0);
        input_sync(gpio_key->inputdev);
        printk("input_sync2\n");    
    }   
}

应用程序

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/input.h>

static struct input_event inputevent;

int main(int argc, char *argv[])
{
    int fd;
    int err = 0;
    char *filename;

    filename = argv[1];

    if(argc != 2) {
        printf("Error Usage!\r\n");
        return -1;
    }

    fd = open(filename, O_RDWR);
    if (fd < 0) {
        printf("Can't open file %s\r\n", filename);
        return -1;
    }

    while (1) {
        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;

                /* 其他类型的事件,自行处理 */
                case EV_REL:
                    break;
                case EV_ABS:
                    break;
                case EV_MSC:
                    break;
                case EV_SW:
                    break;
            }
        } else {
            printf("读取数据失败\r\n");
        }
    }
    return 0;
}