Hi3519v101gpio字符驱动-按键中断poll机制

25 篇文章 0 订阅
10 篇文章 0 订阅

1、key_irq_poll_drv.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/poll.h>

//主设备号
int major;

//udev自动创建节点
static struct class *keyirqdrv_class;
static struct class_device *keyirqdrv_class_dev;

// 操作管脚为gpio14_2
// 该管脚采用boot_sel[1:0]硬件配置复用功能,现单板已经配置为gpio,默认高电平,按键按下为低电平
static void __iomem *key_base; //寄存器基地址

#define gpio_phy_base 0x1214E000   //key管脚物理地址
#define gpio_data key_base + 0x010 //GPIO 数据寄存器 ,0b00_0001_0000
#define gpio_dir key_base + 0x400  //GPIO 方向控制寄存器
#define gpio_is key_base + 0x404   //GPIO 中断触发寄存器
#define gpio_ibe key_base + 0x408  //GPIO 双沿触发中断寄存器
#define gpio_iev key_base + 0x40C  //GPIO 触发中断条件寄存器
#define gpio_ie key_base + 0x410   //GPIO 中断屏蔽寄存器
#define gpio_ris key_base + 0x414  //GPIO 原始中断状态寄存器
#define gpio_mis key_base + 0x418  //GPIO 屏蔽状态中断寄存器
#define gpio_ic key_base + 0x41C   //GPIO 中断清除寄存器

#define gpio_in 0x00 //配置为输入,1输出 0输入def
#define gpio_out_h 0xFF
#define gpio_out_l 0x00

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/* 中断事件标志, 中断服务程序置1 不进休眠,drv_read将它清0 进休眠*/
static volatile int ev_press = 0;

unsigned int val; //中断值

//引脚描述结构体
struct pin_irq_desc
{
    unsigned int irq;    //中断号
    unsigned int pin;    //中断标志寄存器,有中断产生时为1,无中断时为0
    unsigned int number; //编号
    char *name;          //名称
};

struct pin_irq_desc pins_desc[] =
    {
        {76, 0x04, 0x01, "key_irq"},
};

static irqreturn_t irq_interrupt(int irq, void *dev_id)
{
    static unsigned int cnt = 0;
    unsigned int key;
    // printk("cnt = %d\n", cnt++);

    key = ioread8(gpio_ris); //读取中断标志位
    if (key == 0x04)
    {
        val = key;
        ev_press = 1;                         //不进去休眠
        wake_up_interruptible(&button_waitq); //唤醒休眠的进程
    }
    iowrite8(0xFF, gpio_ic); //清除中断

    return IRQ_HANDLED;
}

static int key_drv_open(struct inode *inode, struct file *filp)
{
    iowrite8(gpio_in, gpio_dir); //gpio14_2 配置为输入
    iowrite8(0x04, gpio_is);     //配置电平触发
    iowrite8(0x00, gpio_iev);    //配置下降沿触发或者是低电平触发
    iowrite8(0x00, gpio_ibe);    //配置单边沿触发
    iowrite8(0xFF, gpio_ic);     //清除中断
    iowrite8(0x04, gpio_ie);     //使能gpio14_2中断

    //Hi3519v101好几组GPIO只有一个中断号,所以这里得是共享中断IRQF_SHARED,作为共享中断,dev用来区分不同的中断
    request_irq(pins_desc->irq, irq_interrupt, IRQF_SHARED, pins_desc->name, (void *)&pins_desc);
    printk("set key rising irq mode\n");
    return 0;
}

static int key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    //如果没有按键动作, 休眠
    wait_event_interruptible(button_waitq, ev_press);

    __copy_to_user(buf, &val, 1);
    ev_press = 0; //数据拷贝给运用之后,一次中断完成,进去休眠

    return 0;
}

int key_drv_close(struct inode *inode, struct file *file)
{
    free_irq(pins_desc->irq, (void *)&pins_desc);
    return 0;
}

static unsigned key_drv_poll(struct file *file, poll_table *wait)
{
    unsigned int mask = 0;
    poll_wait(file, &button_waitq, wait); //让进程挂到队列,不会立即休眠

    if (ev_press)
        mask |= POLLIN | POLLRDNORM; //判断返回值mask

    return mask;
}

static struct file_operations key_drv_fops =
    {
        .owner = THIS_MODULE,
        .open = key_drv_open,
        .read = key_drv_read,
        .release = key_drv_close,
        .poll = key_drv_poll,
};

int key_drv_int(void)
{
    major = register_chrdev(0, "key_drv", &key_drv_fops);
    keyirqdrv_class = class_create(THIS_MODULE, "key_drv");
    keyirqdrv_class_dev = device_create(keyirqdrv_class, NULL, MKDEV(major, 0), NULL, "key"); //dev/key

    key_base = ioremap(gpio_phy_base, 0x1000);

    printk("key_data = 0x%x\n", (unsigned int)gpio_data);
    printk("key_dir = 0x%x\n", (unsigned int)gpio_dir);
    return 0;
}

void key_drv_exit(void)
{
    unregister_chrdev(major, "key_drv");
    device_unregister(keyirqdrv_class_dev);
    class_destroy(keyirqdrv_class);
}

module_init(key_drv_int);
module_exit(key_drv_exit);

MODULE_LICENSE("GPL");

2、test_key_irq_poll.c

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

int main(int argc, char **argv)
{
    int fd;
    unsigned int val = 0;
    struct pollfd fds[1];
    int ret;

    fd = open("/dev/key", O_RDWR);
    if (fd < 0)
        printf("can`t open!\n");
    fds[0].fd = fd;
    fds[0].events = POLLIN; //有数据读取
    while (1)
    {
        ret = poll(fds, 1, 5000); //查询fds,1个事件,5000ms时间,在服务器上可通过man poll查看具体用法
        if (ret == 0)             // == 0 表示超时
        {
            printf("time out !\n");
        }
        else
        {
            read(fd, &val, 1);
            printf("key down!get val = %d\n", val);
        }
    }

    return 0;
}

3、Makefile

#内核路径
KERN_DIR = /home/osrc/Hi3519V101_SDK_V1.0.4.0/osdrv/opensource/kernel/linux-3.18.y
 
all:
	make -C $(KERN_DIR) M=`pwd` modules 
 
clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
 
obj-m += key_irq_poll_drv.o

4、测试

/ # insmod key_irq_poll_drv.ko
key_data = 0xfea4e010
key_dir = 0xfea4e400
/ # ./test_key_irq_poll
set key rising irq mode
key down!get val = 4
key down!get val = 4

5s内不中断,则返回打印time out !

key down!get val = 4
time out !
time out !
time out !

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值