key驱动

这个博客介绍了如何在Linux中编写一个简单的按键驱动程序,包括注册中断处理函数、请求和释放中断,以及读取设备文件获取按键计数。驱动程序涉及到字符设备的注册、中断处理、内存映射和用户空间交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/string.h>


#define THIRD_NAME "third_drv"
static int major = 0;

struct class *third_class = NULL;
struct class_device * third_class_dev = NULL;

volatile unsigned long *gph2con;
volatile unsigned long *gph2dat;

volatile unsigned long *gph3con;
volatile unsigned long *gph3dat;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;

struct button_irq_desc {
    int irq;
    unsigned long flags;
    char *name;
};

static struct button_irq_desc button_irqs[] = {
    {IRQ_EINT0, IRQF_TRIGGER_FALLING, "KEY1"},
    {IRQ_EINT2, IRQF_TRIGGER_FALLING, "KEY2"},
    {IRQ_EINT19, IRQF_TRIGGER_FALLING, "KEY3"},
    {IRQ_EINT11, IRQF_TRIGGER_FALLING, "KEY4"},
};

static volatile int press_cnt[] = {0,0,0,0};

struct press_key {
    char *name;
    unsigned long irq;
    unsigned long flags;
    unsigned int cnts;
};

static struct press_key press_keys[4] = {
    {NULL, 0, 0, 0},
    {NULL, 0, 0, 0},
    {NULL, 0, 0, 0},
    {NULL, 0, 0, 0},
};

static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
    volatile int press_i = (void *)dev_id;

    strcpy(press_keys[press_i].name ,button_irqs[press_i].name);
    press_keys[press_i].irq   = button_irqs[press_i].irq;
    press_keys[press_i].flags = button_irqs[press_i].flags;
    press_keys[press_i].cnts += 1;

//    printk("press_cnt[0]=%d \n", press_cnt[0]);
//    printk("press_cnt[1]=%d \n", press_cnt[1]);
//    printk("press_cnt[2]=%d \n", press_cnt[2]);
//    printk("press_cnt[3]=%d \n", press_cnt[3]);

    ev_press = 1;
    wake_up_interruptible(&button_waitq);

    return IRQ_RETVAL(IRQ_HANDLED); 
}

static int third_drv_open(struct inode *inode, struct file *file)
{
    int i, err;
    int button_cnt = sizeof(button_irqs)/sizeof(button_irqs[0]);

    for (i = 0; i < button_cnt; i++)
    {
        err = request_irq(button_irqs[i].irq, buttons_interrupt, button_irqs[i].flags,  \
                                button_irqs[i].name, i);
        if (err)
            break;
    }

    if (err)
    {
        i = 0;
        for (i = 0; i < button_cnt; i++ )
            free_irq(button_irqs[i].irq, i);
        return -EBUSY;
    }
    
    return 0;
}
static ssize_t third_drv_read(struct file *file, char __user *buf, size_t count , loff_t *ppos)
{
    int ret = 0;
    if (count != sizeof(press_cnt))
        return -EINVAL;

    printk("third_drv_read begin \n");

    wait_event_interruptible(button_waitq, ev_press);

    copy_to_user(buf, press_keys, sizeof(press_keys));
    
    ev_press = 0;

    return sizeof(press_keys);
}
static int third_drv_release(struct inode *inode, struct file *file)
{
    int i = 0;
    int button_cnt = sizeof(button_irqs)/sizeof(button_irqs[0]);
    
    for (i = 0; i < button_cnt; i++ )
        free_irq(button_irqs[i].irq, i);

    return 0;
}


static struct file_operations third_drv_fops ={
    .owner = THIS_MODULE,
    .open  = third_drv_open,
    .read  = third_drv_read,
    .release =  third_drv_release,
};


static __init int third_drv_init(void)
{
    major = register_chrdev(0, THIRD_NAME, &third_drv_fops);
    third_class = class_create(THIS_MODULE, "third_drv");
    third_class_dev = class_device_create(third_class, NULL, MKDEV(major, 0), NULL, "buttons");

    gph2con = (volatile unsigned long *)ioremap(0xe0200c40, 16);
    gph2dat = gph2con + 1;

    gph3con = (volatile unsigned long *)ioremap(0xE0200C60, 16);
    gph3dat = gph3con + 1;

//    press_keys = kzalloc(4 * sizeof(struct press_key), GFP_KERNEL);

    return 0;
}

static __exit void third_drv_exit(void)
{
//    kfree(press_keys);
    unregister_chrdev(major, THIRD_NAME);
    class_device_unregister(third_class_dev);
    class_destroy(third_class);
}

module_init(third_drv_init);
module_exit(third_drv_exit);
MODULE_LICENSE("GPL");


echo 5</dev/buttons

cat /proc/interrupts 

ps

ls /proc/771/fd

exec 5<&-

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值