INPUT子系统驱动框架

  input 就是输入的意思,因此 input 子系统就是管理输入的子系统,和 pinctrl、gpio 子系统
一样,都是 Linux 内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触摸屏等
等这些都属于输入设备,不同的输入设备所代表的含义不同,按键和键盘就是代表按键信息,
鼠标和触摸屏代表坐标信息,因此在应用层的处理就不同,对于驱动编写者而言不需要去关心
应用层的事情,我们只需要按照要求上报这些输入事件即可。

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define keyinputdev_CNT            1        /* 设备号个数 */
#define keyinputdev_NAKE            "ketinput"    /* 名字 */
#define KEY_NUM    1//KEY按键数量
#define KEY0VALUE            0X01        /* KEY0按键值     */
#define INVAKEY                0XFF        /* 无效的按键值 */ 

//key结构体
struct irq_keydesc{
    int gpio;       //io编号
    int irqnum;     //中断号
    unsigned char value;  //键值
    char name[10];   //名字
    irqreturn_t (*handler) (int, void *)        //中断处理函数
};

/* keyinputdev设备结构体 */
struct keyinputdev_dev{

    struct devide_node *nd;    //设备节点
    struct irq_keydesc irqkey[KEY_NUM];  //描述按键数组
    
    struct timer_list timer; //定义一个定时器

    struct input_dev *inputdev; //输入设备 已经在内核里面的文件定义好
};

struct keyinputdev_dev keyinputdev;        /* keyinputdev设备 */

//中断处理函数
static irqreturn_t key0_handler(int irq, void *dev_id)
{
    
    struct keyinputdev_dev *dev = (struct keyinputdev_dev *)dev_id;
    
    /*value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0)  {//按下
        printk("KEY0 Push!\r\n");
    }else if(value == 1){  //释放
        printk("KEY0 release!\r\n");
    }*/

    dev->timer.data = (volatile long)dev_id;
    mod_timer(&dev->timer,jiffies + msecs_to_jiffies(20)); //20ms定时,消抖

    return IRQ_HANDLED;
}

//定时器消抖函数
static void timer_func(unsigned long arg){  //20ms结束后此函数执行
    int value = 0;
    struct keyinputdev_dev *dev = (struct keyinputdev_dev*)arg;

    //printk("timer_func\r\n");
    value = gpio_get_value(dev->irqkey[0].gpio); //读取io值
    if(value == 0)  {//按下
        //上报按键值
        input_event(dev->inputdev, EV_KEY, KEY_0, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
        //input_report_key(dev->inputdev, keydesc->value, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
        input_sync(dev->inputdev); //告诉 Linux 内核 input 子系统上报结束
    }else if(value == 1){  //释放
        //上报按键值
        input_event(dev->inputdev, EV_KEY, KEY_0, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
        //input_report_key(dev->inputdev, keydesc->value, 0);
        input_sync(dev->inputdev);
    }
}

//按键初始化
static int  keyio_init(struct keyinputdev_dev *dev)
{
    int ret = 0;
    int i = 0;

    //1.按键初始化
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL){
        ret = -EINVAL;
        goto fail_nd;
    }

    for(i=0; i<KEY_NUM; i++){
        dev->irqkey[i].gpio = of_get_named_gpio(dev->nd,"key-gpio",i);
    }

    for(i=0;i<KEY_NUM;i++){
        memset(dev->irqkey[i].name,0,sizeof(dev->irqkey[i].name));
        sprintf(dev->irqkey[i].name,"KEY%d",i);  //名字
        gpio_request(dev->irqkey[i].gpio,dev->irqkey[i].name);
        gpio_direction_input(dev->irqkey[i].gpio);

    //    dev->irqkey[i].irqnum = gpio_toirq(dev->irqkey[i].gpio);//获取中断号    
        dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->nd,i); //获取中断号
        }
    
    //2.按键中断初始化
    /* 申请中断 */
    dev->irqkey[0].handler = key0_handler;
    dev->irqkey[0].value = KEY_0;
    
    for(i=0;i<KEY_NUM;i++){
        ret = request_irq(dev->irqkey[i].irqnum, dev->irqkey[i].handler, 
                         IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, dev->irqkey[i].name, &keyinputdev);
        if(ret){
            printk("irq %d request faild!\r\n",dev->irqkey[i].irqnum);
            goto fail_irq;
        }

    }

    //3.初始化定时器
    init_timer(&keyinputdev.timer);;
    keyinputdev.timer.function = timer_func; 
    keyinputdev.timer.data = (unsigned long)&keyinputdev;  //传递给timer_func函数的一个参数
    
    
    
    return 0;

 fail_irq:
    for(i=0;i<KEY_NUM;i++){
        gpio_free(dev->irqkey[i].gpio);
    }
 fail_nd:
    return ret;

}

static int __init keyinputdev_init(void)
{
    int ret = 0;
        
    
    //1.初始化IO
    ret = keyio_init(&keyinputdev);
    if(ret < 0){
        printk("keyio_init fail\r\n");
    }

    //2.申请input_dev输入设备
    keyinputdev.inputdev = input_allocate_device();
    if(keyinputdev.inputdev == NULL){
        ret = -EINVAL;
        goto fail_keyinit;
    }

    keyinputdev.inputdev->name = keyinputdev_NAKE;
    __set_bit(EV_KEY,keyinputdev.inputdev->evbit); //按键事件,evbit 表示输入事件类型
    __set_bit(EV_REP,keyinputdev.inputdev->evbit); //重复事件
    __set_bit(KEY_0,keyinputdev.inputdev->keybit); //keybit是按键事件使用的位图

    //注册input_dev输入设备
    ret = input_register_device(keyinputdev.inputdev);
    if (ret) {
        goto fail_input_register;
    }

    return 0;
fail_input_register:
    input_free_device(keyinputdev.inputdev);

fail_keyinit:
    return ret;

}


static void __exit keyinputdev_exit(void)
{
    int i;
    //1.释放中断
    for(i=0;i<KEY_NUM;i++){
        free_irq(keyinputdev.irqkey[i].irqnum,&keyinputdev);
    }

    //2.释放io
    for(i=0;i<KEY_NUM;i++){
        gpio_free(keyinputdev.irqkey[i].gpio);
    }

    //3.删除定时器
    del_timer_sync(&keyinputdev.timer);

    //4.注销input_dev
    input_unregister_device(keyinputdev.inputdev);
    input_free_device(keyinputdev.inputdev);
}

module_init(keyinputdev_init);
module_exit(keyinputdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("deng");
 

因为是Linux 内核针对某一类设备而创建的框架,所以不需要我自己去创建设备

应用程序为:

#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>

//input_event结构体变量
static struct input_event inputevent;

int main(int argc, char *argv[])
{
    int fd,err;
    int ret = 0;
    char *filename;
//    unsigned char data;
    
    if (argc != 2) {
        printf("Error Usage!\r\n");
        return -1;
    }

    filename = argv[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");
        }
    }
    
    close(fd);
    return ret;
}
 

执行结果为:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值