zoukankan      html  css  js  c++  java
  • [国嵌攻略][138][输入子系统模型解析]

    为什么需要输入子系统

    在Linux系统中按键属于输入型设备,同样的把按键换成鼠标、键盘等输入型设备,它们的注册和操作方法都是类似的,不同的是在中断处理中对硬件的操作。输入子系统就是把和输入设备有共性的部分提取出来,而把不同的部分让程序员来实现。

    输入子系统模型

    1.input device drivers,需要程序员来实现

    2.input core,属于系统内核实现

    3.input event drivers,属于系统内核实现

    例如:

    当按键被按下时,会产生一个事件,然后事件由input device drivers上报给input core,由input core处理后把事件交给input event drivers。input event drivers需要实现字符驱动和对应的系统调用接口。上层应用从input event drivers实现的系统调用接口中读取数据。input device drivers实现硬件相关的工作,input event drivers实现硬件无关的工作,这样就可以简化代码实现。

    输入型设备驱动

    输入设备事件:

    EV_RST reset   EV_KEY 按键   EV_LED LED   EV_REL 相对坐标   EV_ABS 绝对坐标

    EV_MSC 其他   EV_SND 声音   EV_REP repreat   EV_FF 力反馈

    当事件类型为EV_KEY时,还需要声明按键类型:

    BTN_LEFT:鼠标左键   BTN_RIGHT:鼠标右键   BTN_0:数字0键   BTN_1:数字1键

    初始化

    1.分配input_dev结构,使用input_allocate_device

    2.声明可能会上报的事件类型,使用set_bit

    3.如果上报的是按键,声明可能上报的键值

    4.注册输入型设备,使用input_register_device

    上报

    1.上报产生的事件,使用input_report_key

    2.告诉核心上报结束,使用input_sync

    注册输入型设备时,会自动创建设备文件,在/dev/目录下的event%d文件。

    keydev.c

    /********************************************************************
    *头文件
    *********************************************************************/
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/input.h>
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    #include <linux/sched.h>
    
    /********************************************************************
    *宏定义
    *********************************************************************/
    #define GPGCON 0x56000060   //按键控制寄存器地址
    #define GPGDAT 0x56000064   //按键数据寄存器地址
    
    /********************************************************************
    *全局变量
    *********************************************************************/
    unsigned int *keycon;       //按键控制指针
    unsigned int *keydat;       //按键数据指针
    
    struct work_struct *work;   //按键工作
    struct timer_list timer;    //按键定时
    
    struct input_dev *keydev;   //按键输入设备
    
    /********************************************************************
    *定时处理
    *********************************************************************/
    //设备定时
    void key_timer(unsigned long data){
        //读取按键状态
        unsigned short datTmp;
        int key1, key2;
        
        datTmp = readw(keydat);   //获取GPGDAT值
        key1 = datTmp & (1<<0);   //获取key1电平
        key2 = datTmp & (1<<3);   //获取key2电平
        
        //判断按键状态
        if(key1 == 0){
            input_report_key(keydev, KEY_1, 1);   //上报按键事件
            printk("key1 down!
    ");
        }
        
        if(key2 == 0){
            input_report_key(keydev, KEY_2, 1);   //上报按键事件
            printk("key2 down!
    ");
        }
        
        //上报事件完成
        input_sync(keydev);
    }
    
    /********************************************************************
    *中断处理
    *********************************************************************/
    //设备中断下部
    void key_work(struct work_struct *work){
        //启动定时设备
        mod_timer(&timer, jiffies + HZ/100);   //定时10ms,jiffies表示系统当前嘀嗒数,1HZ = 1s = 1000jiffies
    }
    
    //设备中断上部
    irqreturn_t key_irq(int irq, void *dev_id){
        //处理硬件相关
        
        //提交按键工作
        schedule_work(work);
        
        return 0;
    }
    
    /********************************************************************
    *模块安装
    *********************************************************************/
    //注册硬件
    void handware_init(void){
        //初始化按键控制寄存器
        unsigned int conTmp;
        
        keycon = ioremap(GPGCON, 4);   //虚拟地址映射
        
        conTmp = readl(keycon);             //获取GPGCON值
        conTmp &= ~((0x3<<6) | (0x3<<0));   //GPB3[7:6]:00,GPG0[1:0]:00
        conTmp |=  ((0x2<<6) | (0x2<<0));   //GPB3[7:6]:EINT[11],GPG0[1:0]:EINT[8]
        writel(conTmp, keycon);             //设置GPGCON值
        
        //初始化按键状态寄存器
        keydat = ioremap(GPGDAT, 2);   //虚拟地址映射
    }
    
    //安装模块
    static int ikey_init(void){
        //分配输入设备
        keydev = input_allocate_device();
        
        //声明按键事件
        set_bit(EV_KEY, keydev->evbit);
        
        //声明按键编号
        set_bit(KEY_1, keydev->keybit);
        set_bit(KEY_2, keydev->keybit);
        
        //注册输入设备
        input_register_device(keydev);
    
        //注册硬件设备
        handware_init();
            
        //注册中断处理
        request_irq(IRQ_EINT8, key_irq, IRQF_TRIGGER_FALLING, "ikey", (void *)1);    //下降沿触发,IRQ_EINT8定义在irqs.h文件中
        request_irq(IRQ_EINT11, key_irq, IRQF_TRIGGER_FALLING, "ikey", (void *)2);
        
        //注册工作队列
        work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
        INIT_WORK(work, key_work);
        
        //注册定时设备
        init_timer(&timer);           //初始化定时器
        timer.function = key_timer;   //添加定时函数
        add_timer(&timer);            //添加定时设备
        
        return 0;
    }
    
    //卸载模块
    static void ikey_exit(void){
        //注销输入设备
        input_unregister_device(keydev);
        
        //注销中断处理
        free_irq(IRQ_EINT8, (void *)1);
        free_irq(IRQ_EINT11, (void *)2);
    }
    
    /********************************************************************
    *模块声明
    *********************************************************************/
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("D");
    MODULE_DESCRIPTION("");
    MODULE_VERSION("v1.0");
    
    module_init(ikey_init);
    module_exit(ikey_exit);

    keyapp.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <linux/input.h>
    
    int main(int argc, char **argv){
        //打开设备
        int fd;
        
        fd = open("/dev/event1", O_RDWR);
        
        while(1){
            //读取设备
            struct input_event keyevt;
            
            read(fd, &keyevt, sizeof(keyevt));
            
            //显示数据
            if(keyevt.type == EV_KEY){
                printf("Event type:%d code:%d value:%d
    ", keyevt.type, keyevt.code - 1, keyevt.value);
            }
            
            if(keyevt.type == EV_SYN){
                printf("Sync event
    ");
            }
        }
        
        //关闭设备
        close(fd);
        
        return 0;
    }
  • 相关阅读:
    移动端疫情展示
    第四周学习总结
    构建之法阅读笔记二
    第三周学习总结
    AJAX学习篇
    jQuery学习篇
    软件工程开课第二周——介绍篇
    【Spring】DispatcherServlet的启动和初始化
    【设计模式】模板方法模式小解
    【Mybatis】MyBatis调用带有返回结果、output参数的存储过程上与ibatis的区别
  • 原文地址:https://www.cnblogs.com/d442130165/p/5269917.html
Copyright © 2011-2022 走看看