[国嵌攻略][123][多按键驱动优化]

keydev.c

/********************************************************************
*头文件
*********************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

/********************************************************************
*宏定义
*********************************************************************/
#define GPGCON 0x56000060   //按键控制寄存器地址
#define GPGDAT 0x56000064   //按键数据寄存器地址

/********************************************************************
*全局变量
*********************************************************************/
unsigned int *keycon;       //按键控制指针
unsigned int *keydat;       //按键数据指针

struct work_struct *work;   //按键工作
struct timer_list timer;    //按键定时
int keynum;                 //按键编号

/********************************************************************
*定时处理
*********************************************************************/
//设备定时
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){
        keynum = 1;
        printk("key1 down!
");
    }
    
    if(key2 == 0){
        keynum = 2;
        printk("key2 down!
");
    }
}

/********************************************************************
*中断处理
*********************************************************************/
//设备中断下部
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;
}

/********************************************************************
*设备方法
*********************************************************************/
//设备读取
ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){
    //读取按键编号
    copy_to_user(buf, &keynum, sizeof(keynum));
    
    return sizeof(keynum);
}

//设备打开
int key_open(struct inode *node, struct file *filp){
    return 0;
}

//设备关闭
int key_close(struct inode *node, struct file *filp){
    return 0;
}

//设备方法
struct file_operations key_fops = {
    .read    = key_read,
    .open    = key_open,
    .release = key_close
};

/********************************************************************
*模块安装
*********************************************************************/
//混杂设备
struct miscdevice misdev = {
    .minor = 200,        //次设备号
    .name  = "keydev",   //设备名称
    .fops  = &key_fops   //设备方法
};

//注册硬件
void handware_init(void){
    //初始化按键控制寄存器
    unsigned int dattmp;
    
    keycon = ioremap(GPGCON, 4);   //虚拟地址映射
    
    dattmp = readl(keycon);             //获取GPGCON值
    dattmp &= ~((0x3<<6) | (0x3<<0));   //GPB3[7:6]:00,GPG0[1:0]:00
    dattmp |=  ((0x2<<6) | (0x2<<0));   //GPB3[7:6]:EINT[11],GPG0[1:0]:EINT[8]
    writel(dattmp, keycon);             //设置GPGCON值
    
    //初始化按键状态寄存器
    keydat = ioremap(GPGDAT, 2);   //虚拟地址映射
}

//安装模块
static int key_init(void){
    //注册混杂设备
    misc_register(&misdev);
    
    //注册硬件设备
    handware_init();
        
    //注册中断处理
    request_irq(IRQ_EINT8, key_irq, IRQF_TRIGGER_FALLING, "keyirq", 0);    //下降沿触发,IRQ_EINT8定义在irqs.h文件中
    request_irq(IRQ_EINT11, key_irq, IRQF_TRIGGER_FALLING, "keyirq", 0);
    
    //注册工作队列
    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 key_exit(void){
    //注销混杂设备
    misc_deregister(&misdev);
    
    //注销中断处理
    free_irq(IRQ_EINT8, 0);
    free_irq(IRQ_EINT11, 0);
}

/********************************************************************
*模块声明
*********************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("D");
MODULE_DESCRIPTION("");
MODULE_VERSION("v1.0");

module_init(key_init);
module_exit(key_exit);

keyapp.c

mknod /dev/keydev0 c 10 200

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv){
    //打开设备
    int fd;
    
    fd = open("/dev/keydev0", O_RDWR);
    
    //读取设备
    int keynum;
    
    read(fd, &keynum, sizeof(keynum));
    printf("key number is %d
", keynum);
    
    //关闭设备
    close(fd);
}
原文地址:https://www.cnblogs.com/d442130165/p/5258837.html