嵌入式内核及驱动开发之学习笔记(七) 非阻塞模式+中断实现读取数据
当中断发生时,驱动程序会跳转到中断处理的函数入口,实现了中断的捕获和处理,但这样还不够。要让用户能够获取到中断分析的结果,我们将创建一个描述中断事件的结构体对象。硬件产生中断后,驱动代码将对中断事件的分析结果保存在结构体变量中,用户需要的时候,直接通过接口函数获取这个结构体的数据。
内核层:
硬件(中断事件) --> 驱动程序(中断处理) --> 结构体变量(添加到对象属性)
应用层:
结构体(添加到对象属性) --> API(内核层对应用层的接口) --> 用户程序
实验:根据之前学到的字符驱动步骤和代码规范,再进一步对之前的程序调整,便有了这个程序。对于内核层,当有中断事件,去驱动程序跳到处理函数并将中断信息保存在定义的结构体中;对于应用,使用while循环调用read函数 轮询的方式,这算是一种非阻塞模型,比较耗费CPU的资源。
驱动程序
当按键按下(1->0)或者松开(0->1)时,产生一个中断事件,驱动程序进入中断处理key_irq_handler,并将对按键的分析数据存放在key_event类型的结构体中。提供key_drv_read函数,实际上就是应用程序获取这个结构体数据的接口函数
-
//key_drv.c
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/of.h>
-
#include <linux/of_irq.h>
-
#include <linux/interrupt.h>
-
#include <linux/slab.h>
-
#include <linux/fs.h>
-
#include <linux/device.h>
-
-
#include <asm/io.h>
-
#include <asm/uaccess.h>
-
-
irqreturn_t key_irq_handler(int irqno, void *devid);
-
ssize_t key_drv_read (struct file *, char __user *, size_t, loff_t *);
-
ssize_t key_drv_write (struct file *, const char __user *, size_t, loff_t *);
-
int key_drv_open (struct inode *, struct file *);
-
int key_drv_close (struct inode *, struct file *);
-
-
#define GPXCON_REG 0x11000C20
-
#define KEY_ENTER 28
-
-
-
const struct file_operations key_fops = {
-
.open = key_drv_open,
-
.read = key_drv_read,
-
.write = key_drv_write,
-
.release = key_drv_close,
-
-
};
-
-
struct key_event{
-
int code; // 按键的类型
-
int value; // 状态
-
};
-
-
-
struct key_desc{
-
unsigned int dev_major;
-
struct class *cls;
-
struct device *dev;
-
int irqno;
-
void *reg_base;
-
struct key_event event;
-
};
-
struct key_desc *key_dev;
-
-
-
//static int irqno;
-
-
-
int get_irqno_from_node(void)
-
{
-
//从设备树路径,查找节点
-
struct device_node *np = of_find_node_by_path("/key_int_node");
-
if(np){
-
printk("find node ok\n");
-
}else{
-
printk("find node failed\n");
-
}
-
-
int irqno = irq_of_parse_and_map(np, 0);
-
printk("irqno = %d\n", irqno);
-
-
return irqno;
-
}
-
-
-
static int __init key_drv_init(void)
-
{
-
int ret;
-
-
//对象实例化
-
key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);
-
-
//申请主设备号
-
key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
-
-
//创建设备结点
-
key_dev->cls = class_create(THIS_MODULE, "key_cls");
-
key_dev->dev = device_create(key_dev->cls, NULL,
-
MKDEV(key_dev->dev_major,0), NULL, "key0");
-
-
-
//硬件初始化
-
key_dev->irqno = get_irqno_from_node();
-
ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
-
"key3_eint10", NULL);
-
if(ret != 0)
-
{
-
printk("request_irq error\n");
-
return ret;
-
}
-
-
-
key_dev->reg_base = ioremap(GPXCON_REG, 8);
-
-
return 0;
-
}
-
-
static void __exit key_drv_exit(void)
-
{
-
-
iounmap(key_dev->reg_base); //去映射
-
free_irq(key_dev->irqno, NULL); //释放中断资源
-
device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,0)); //
-
class_destroy(key_dev->cls); //
-
unregister_chrdev(key_dev->dev_major, "key_drv"); //注销主设备号
-
kfree(key_dev); //释放结构体内存
-
-
-
}
-
-
-
irqreturn_t key_irq_handler(int irqno, void *devid)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
int value = readl(key_dev->reg_base + 4) & (1<<2);
-
-
if(value){// 1
-
printk("key3 up\n");
-
key_dev->event.code = KEY_ENTER;
-
key_dev->event.value = 0;
-
-
}else{// 0
-
printk("key3 pressed\n");
-
key_dev->event.code = KEY_ENTER;
-
key_dev->event.value = 1;
-
}
-
-
return IRQ_HANDLED;
-
-
}
-
-
-
ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
-
{
-
//printk("-------%s-------------\n", __FUNCTION__);
-
int ret;
-
-
ret = copy_to_user(buf, &key_dev->event, count);
-
if(ret > 0)
-
{
-
printk("copy_to_user error\n");
-
return -EFAULT;
-
}
-
-
// 清除key_dev->event的数据记录
-
memset(&key_dev->event, 0, sizeof(key_dev->event));
-
-
return count;
-
-
}
-
-
ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
int key_drv_open(struct inode *inode, struct file *filp)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
int key_drv_close (struct inode *inode, struct file *filp)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return 0;
-
}
-
-
-
-
-
module_init(key_drv_init);
-
module_exit(key_drv_exit);
-
-
MODULE_LICENSE("GPL");
-
-
应用程序
在应用程序中,不断read获取按键的状态,有按键触发立即打印数据。
-
//key_test.c
-
#include <stdio.h>
-
#include <string.h>
-
#include <stdlib.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <unistd.h>
-
-
-
struct key_event{
-
int code; // 按键的类型
-
int value; // 状态
-
};
-
-
-
#define KEY_ENTER 28
-
-
int main(int argc, char *argv[])
-
{
-
struct key_event event;
-
-
int fd = open("/dev/key0", O_RDWR);
-
if(fd < 0)
-
{
-
perror("open");
-
exit(1);
-
}
-
-
while(1)
-
{
-
read(fd, &event, sizeof(struct key_event));
-
-
if(event.code == KEY_ENTER)
-
{
-
if(event.value)
-
{
-
printf("APP__ key enter pressed\n");
-
}else{
-
printf("APP__ key enter up\n");
-
}
-
}
-
}
-
-
-
close(fd);
-
-
-
return 0;
-
-
}
-
-
-
结果演示
编译后在开发板上运行,查看串口打印结果
文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/feit2417/article/details/84143560
- 点赞
- 收藏
- 关注作者
评论(0)