先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题

一 why

字符设备驱动在我们之前的博文中都已经有过比较详细的介绍了,为什么需要带上一个中断开发呢?我们知道CPU获取外设的数据有两种方式,一种是CPU主动去轮询外设,另一种就是外设通过中断的方式异步地将自己的数据上报给CPU。轮询的方式会造成CPU占用率过高浪费太多的资源,同时实时性得不到保障,中断是一种比较好的解决轮询缺点的解决方案,今天我们就来看看字符设备驱动中的中断开发

二 what

a. 驱动如何获取中断号

//1. 获取到设备树中的节点
of_find_node_by_path()
//2. 通过节点去获取到中断号码
irq_of_parse_and_map()

b. 驱动如何申请中断

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char * name, void * dev)
参数1: 设备对应的中断号
参数2: 中断的处理函数typedef irqreturn_t (*irq_handler_t)(int, void *);
参数3: 触发方式#define IRQF_TRIGGER_NONE  0x00000000#define IRQF_TRIGGER_RISING   0x00000001#define IRQF_TRIGGER_FALLING  0x00000002#define IRQF_TRIGGER_HIGH 0x00000004#define IRQF_TRIGGER_LOW  0x00000008
参数4: 中断的描述,自定义,主要是给用户查看的/proc/interrupts
参数5: 传递给参数2的参数
返回值: 正确为0,错误为非零

三 how

a. 获取中断号的函数如下

//获取中断号
static int get_irqno_from_node(void)
{struct device_node *np;int no;//获取到设备树中的节点np = of_find_node_by_path("/key_interrupt");if (np) {printk("find node ok\n");} else {printk("find node fail\n");}//通过节点去获取到中断号码no = irq_of_parse_and_map(np, 0);printk("irqno = %d\n", no);return no;
}

b. 获取完中断号就可以注册中断了

key_dev->irqno = get_irqno_from_node();
ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"key3_exit10", NULL);

c. 完整代码
这个程序只是一个字符设备驱动之中断开发的一个框架,暂时还没有实现任何实际的功能,当然这个驱动是可以正确编译并被加载到内核的

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>typedef struct key_desc_s {unsigned int dev_major;struct class *chardev_class;struct device *chardrv_class_dev;int irqno;
} key_desc_t;key_desc_t *key_dev;static int kernel_value1 = 555;
static int kernel_value2;irqreturn_t key_irq_handler(int irq_no, void *devid)
{printk("-----------------\n");return IRQ_HANDLED;
}static int chardev_drv_open(struct inode *inode, struct file *file)
{printk(KERN_INFO "chardev_drv_open\n");return 0;
}static ssize_t chardev_drv_read(struct file *filp, char __user *buf,size_t size, loff_t *ppos)
{int ret = 0;printk(KERN_INFO "chardev_drv_read\n");ret = copy_to_user(buf, &kernel_value1, size);if (ret > 0) {printk(KERN_ERR "copy_to_user error\n");return -EINVAL;}return 0;
}static ssize_t chardev_drv_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos)
{int ret = 0;printk(KERN_INFO "chardev_drv_write\n");ret = copy_from_user(&kernel_value2, buf, size);if (ret > 0) {printk(KERN_ERR "copy_from_user error\n");return -EINVAL;}printk("kernel_value2 = %d", kernel_value2);return 0;
}int chardev_drv_close(struct inode *inode, struct file *file)
{printk(KERN_INFO "chardev_drv_close\n");return 0;
}static struct file_operations chardev_drv_fops = {.owner   = THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */.open  = chardev_drv_open,.read   = chardev_drv_read,.write  = chardev_drv_write,.release = chardev_drv_close,
};//获取中断号
static int get_irqno_from_node(void)
{struct device_node *np;int no;//获取到设备树中的节点np = of_find_node_by_path("/key_interrupt");if (np) {printk("find node ok\n");} else {printk("find node fail\n");}//通过节点去获取到中断号码no = irq_of_parse_and_map(np, 0);printk("irqno = %d\n", no);return no;
}static int __init key_drv_init(void)
{int ret = 0;//1. 设定一个全局的设备对象key_dev = (key_desc_t *)kzalloc(sizeof(key_desc_t), GFP_KERNEL);if (key_dev == NULL) {printk("kzalloc failure\n");return -EINVAL;}//2. 申请主设备号key_dev->dev_major = register_chrdev(0, "chardev0", &chardev_drv_fops);//3. 创建设备节点文件key_dev->chardev_class = class_create(THIS_MODULE, "chardev0");key_dev->chardrv_class_dev = device_create(key_dev->chardev_class, NULL,MKDEV(key_dev->dev_major, 0), NULL, "chardev0"); /* /dev/xyz *///4. 注册中断key_dev->irqno = get_irqno_from_node();ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"key3_exit10", NULL);return 0;
}static void __exit key_drv_exit(void)
{printk(KERN_INFO "new exit chardev0\n");//释放中断free_irq(key_dev->irqno, NULL);unregister_chrdev(key_dev->dev_major, "chardev0");device_unregister(key_dev->chardrv_class_dev);class_destroy(key_dev->chardev_class);kfree(key_dev);
}module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

linux内核模块编程(六)----字符设备驱动中断开发相关推荐

  1. 一起分析Linux系统设计思想——05字符设备驱动框架剖析(四)

    在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习.我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直 ...

  2. Linux内核学习-字符设备驱动学习(二)

    在Linux内核学习-字符设备驱动学习(一)中编写字符设备驱动的一种方法,但是需要手动创建设备节点. 有没有能够自动的创建设备节点的呢? 有!使用class_create()和device_creat ...

  3. Linux 字符设备驱动的编写

    Linux 字符设备驱动的编写 作者:解琛 时间:2020 年 8 月 17 日 Linux 字符设备驱动的编写 一.Linux 设备分类 二.open() 三.数据结构 3.1 struct fil ...

  4. <Linux开发>--驱动开发-- 字符设备驱动(3) 过程详细记录

    <Linux开发>–驱动开发-- 字符设备驱动(3) 过程详细记录 驱动开发是建立再系统之上的,前面作者也记录了系统移植的过程记录,如果有兴趣,可进入博主的主页查看相关文章,这里就不添加链 ...

  5. linux PCI驱动调用字符设备驱动方式

    上一篇文章写了字符设备驱动的基本结构及访问方式,在实际应用时首先需要绑定自己的硬件设备.本篇主要描述字符设备驱动与PCI接口类型的设备访问方式(内核为2.6.24及以上的方法,测试内核为2.6.32) ...

  6. 【正点原子MP157连载】第二十章 字符设备驱动开发-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  7. Linux驱动-字符设备驱动

    Linux驱动-字符设备驱动 前言 一.预备知识 1.file_operations结构体 2.地址映射 二.涉及的API函数 1.字符设备驱动 1.1.设备号 1.1.1.register_chrd ...

  8. 二.字符设备驱动基础

    目录 一.开启驱动开发之路 二.最简单的模块源码分析1 2.1.常用的模块操作命令 三.最简单的模块源码分析2 3.1.模块卸载 3.2.模块中常用宏 四.最简单的模块源码分析3 4.1.printk ...

  9. 虚拟字符设备驱动开发步骤

    目录 前言 字符设备驱动简介 内核驱动操作函数集合(file_operations结构体) 字符设备驱动开发步骤 .ko驱动模块的加载和卸载(module_init驱动入口.insmod驱动加载) 字 ...

最新文章

  1. mysql语句将日期转换为时间戳的方法
  2. 乐在其中设计模式(C#) - 提供者模式(Provider Pattern)
  3. SpringBoot 整合Shiro 一指禅
  4. 集成电路的设计 —— 引脚
  5. [导入]你的网站被订阅了吗(浅谈RSS2.0)续
  6. Android窗口系统第二篇---Window的添加过程
  7. Intel IPP密码库 IPPCP 2018 开发笔记与总结(全)
  8. 漏洞扫描工具MySQL_打造一款自动扫描全网漏洞的扫描器
  9. nexus的下载与安装和启动
  10. fceux模拟器linux,FCEUX模拟器
  11. 微信小程序获取access_token报错errcode: 40125,errmsg: invalid appsecret
  12. 3-11 查询水果价格
  13. 20天学会UI设计(PS+AI)入门教程
  14. python 爬取贝壳网小区名称_用Python爬取贝壳网新房和二手房数据
  15. 2016-03-30 作业 朱宇飞
  16. 抖音电商副总裁木青:抖音电商正在成为服饰行业的增量风口
  17. Unit Test and Integration Test
  18. 【web项目】任务倒计时网页
  19. 为什么类只能单继承,而接口可以多继承?
  20. 多线程(二)线程控制(创建 退出 等待)

热门文章

  1. C++实验3-定期存款利息计算器
  2. 为什么一般公司面试结束后会说「回去等消息」,而不是直接告诉面试者结果?
  3. Java小农养成记第十三天
  4. 基于单片机模拟打地鼠游戏设计-protues仿真毕业
  5. 【Android -- 面试】复习指南之 Android 高级(下)
  6. 十次方中的前端知识点随记
  7. 背景建模(一) Evaluation of Background Subtraction Techniques
  8. 为什么放大器上的输入电阻越大越好?输出电阻越小越好?
  9. opencv-python 立体图像的深度图
  10. Word让目录页码和正文页码独立分开计算,分隔符中分页符、“下一页”分节符的区别与使用选择