linux驱动之按键(中断)

说明:以下由两部分组成,按键驱动、按键应用程序构成;

1.驱动程序;

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/poll.h>


#define DEVICE_NAME     "CL_key"    /*驱动加载后,执行"cat /proc/devices"命令可以查看到该设备名。*/

#define BUTTON_MAJOR    232     /*主设备号*/

typedef struct{
    int irq;    /*中断号*/
    int pin;    /*中断管脚*/
    int pin_setting;    /*管脚功能设置*/
    int number; /*按键编号*/ 
    char *name; /*按键名称*/
}Button_irq_desc;

static Button_irq_desc button_irq[] = {
    {IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KEY1"}, /*K1*/
    {IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, 1, "KEY2"}, /*K2*/
    {IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY3"}, /*K3*/
    {IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY4"}, /*K4*/   
};

/*按键被按下的次数*/
static volatile int key_values[] = {0, 0, 0, 0}; 

 /*等待队列,应用层调用读按键接口,如果没有按键按下时,它将休眠*/
static DECLARE_WAIT_QUEUE_HEAD(Button_waitq);  

/*中断事件标识*/
static volatile int env_press = 0;  

static irqreturn_t button_interrupt(int irq, void *dev_id)
{
    Button_irq_desc *button_irqs = (Button_irq_desc*)dev_id;

    /*读取管脚的状态*/
    int key_state = s3c2410_gpio_getpin(button_irqs->irq);   

    if (!key_state)  /*按键按下*/
        key_values[button_irqs->number] = (button_irqs->number+1) + 0x80;   
    else
        key_values[button_irqs->number] = (button_irqs->number+1);

    printk("KER_INFO: [isr] key_values[%d] = %d\n", button_irqs->number+1, key_values[button_irqs->number]);

    env_press = 1;
    /*唤醒等待队列*/
    wake_up_interruptible(&Button_waitq);   

    return IRQ_RETVAL(IRQ_HANDLED);
}

static int CL_buttons_open(struct inode *node, struct file *file)
{
    int i;
    int err;

    for (i = 0; i < sizeof(button_irq)/sizeof(button_irq[0]); i++) {
        /*配置管脚功能*/
        s3c2410_gpio_setpin(button_irq[i].pin, button_irq[i].pin_setting);  
        /*注册中断处理函数*/ 
        err = request_irq(button_irq[i].irq, button_interrupt, NULL, button_irq[i].name, (void*)&button_irq[i]);          
        if (err) {
            printk("KER_INFO: open %s pin=%d faild\n", button_irq[i].name, button_irq[i].pin);
            break;
        }
    }   

    if (err) {
        i--;
        for (; i >= 0; i--) {
            /*关中断函数*/
            disable_irq(button_irq[i].irq);    
            /*释放中断函数*/   
            free_irq(button_irq[i].irq, (void*)&button_irq[i]);    
        }

        return -EBUSY;
    }
}

static int CL_buttons_close(struct inode *node, struct file *file)
{
    int i;
    
    for (i = 0; i < sizeof(button_irq)/sizeof(button_irq[0]); i++) {
        /*关中断函数*/
        disable_irq(button_irq[i].irq);    
        /*释放中断函数*/   
        free_irq(button_irq[i].irq, (void*)&button_irq[i]);    
    }

    return 0;
}

/*应用程序调用read()函数时调用的接口*/
static int CL_buttons_read(struct file *file, char __user *buff, size_t conut, loff_t *offp)
{
    unsigned long err;
    int i;

    /*按键没有按下*/
    if (!env_press){    
        if (file->f_flags & O_NONBLOCK) {
            return -EAGAIN;
        }else {
            /*如果全局变量env_press为0,休眠等待, 注意下面函数是宏定义*/
            wait_event_interruptible(Button_waitq, env_press);  
        }        
    }

    /*到这里已经env_press为1,清零*/
    env_press = 0;  
    err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), conut));

    for (i = 0; i < sizeof(key_values)/sizeof(key_values[0]); i++) {
        printk("KER_INFO: [loop] key_values[%d] = %d\n", i+1, key_values[i]);
    }


    memset(key_values, 0, sizeof(key_values));

    return err? -EFAULT : min(sizeof(key_values), conut); 
}

/*应用程序调用select()函数时调用*/
static int CL_button_poll(struct file *file, struct poll_table_struct *wait)
{
    unsigned int mask = 0;

    /*用于非阻塞访问,当有数据时将立即返回,否则进入等待状态*/
    poll_wait(file, &Button_waitq, wait);   

    if (env_press) {
        /*普通或优先级带数据可读 | 普通数据可读*/
        mask |= POLLIN|POLLRDNORM;  
    }

    return mask;
}

static struct file_operations CL_button_fops = {
    .owner = THIS_MODULE,
    .open = CL_buttons_open,
    .release = CL_buttons_close,
    .read = CL_buttons_read,
    .poll = CL_button_poll,
};

static struct class *button_class;
static int __init CL_buttons_init(void)
{
    int ret;

    /*注册字符设备驱动程序*/
    ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &CL_button_fops);  
    if (ret) {
        printk(DEVICE_NAME"can`t register major number.\n");
        return ret;
    }

    /*注册一个类,使mdev可以在/dev目录下创建设备节点*/
    button_class = class_create(THIS_MODULE, DEVICE_NAME); 
    if (IS_ERR(button_class)) {
        printk("Err: create class failed.\n");
        return -1;
    }

    /*创建一个设备节点,节点名为DEVICE_NAME*/
    device_create(button_class, NULL, MKDEV(BUTTON_MAJOR, 0), NULL, DEVICE_NAME);

    printk(DEVICE_NAME" initialized.\n");

    return 0;
}


static void __exit CL_button_exit(void)
{
    unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);
    device_destroy(button_class, MKDEV(BUTTON_MAJOR, 0));
    class_destroy(button_class);

    printk(DEVICE_NAME" exit!\n");
}

module_init(CL_buttons_init);
module_exit(CL_button_exit);

MODULE_AUTHOR("Cl learning...");
MODULE_DESCRIPTION("[2016-02-20] Cl interrupt for button test");
MODULE_LICENSE("GPL");


2.按键应用;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>

#define DEVICE_NAME     "/dev/CL_key"

int main(void)
{
    int fd;
    int key_values[4];

    if((fd=open(DEVICE_NAME, 0)) < 0) {
        perror("open()");
        return -1;
    }

    while (1) {
        fd_set rfds;
        int ret;
        
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);

        ret = select(fd+1, &rfds, NULL, NULL, NULL);
        if (ret < 0) {
            perror("select()");
            exit(1);
        } else if (ret == 0) {
            perror("select() timeout");
        } else if (FD_ISSET(fd, &rfds)) {   /*能够读取到数据*/
            memset(key_values, 0, sizeof(key_values));
            int ret = read(fd, &key_values, sizeof(key_values));
            if (ret != sizeof(key_values)) {
                if (errno != EAGAIN)
                    perror("read key");
                continue;
            }else {
                int i;
                for (i = 0; i < sizeof(key_values)/sizeof(key_values[0]); i++) {
                   if (key_values[i]) {
                      printf("Key_%d %s\n", i+1, ((key_values[i]&0x80)? "press" : "release"));   
                   }
                }
            }
        }
    }

    return 1;
}


3.运行结果



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值