Linux内核中断引入用户空间(异步通知机制)【转】
转自:http://blog.csdn.net/kingdragonfly120/article/details/10858647
版权声明:本文为博主原创文章,未经博主允许不得转载。
当Linux内核空间发生中断后怎么使用户空间的应用程序运行相应的函数呢,当芯片有数据到来时内核会产生一个中断,但是怎样通知应用程序来取数据,以前这个问题一直困扰我很长时间,后来发现linux中有异步通知机制,在用户程序中用signal注册一个响应SIGIO信号的回调函数,然后在驱动程序中向该进程发出SIGIO信号便完成该功能,下面是该功能具体实施方法:
1.在驱动中定义一个static struct fasync_struct *async;
2.在fasync系统调用中注册fasync_helper(fd, filp, mode, &async);
3.在中断服务程序(顶半部、底半部都可以)发出信号kill_fasync(&async, SIGIO, POLL_IN);
4.在用户应用程序中用signal注册一个响应SIGIO的回调函数signal(SIGIO, sig_handler);
5.通过fcntl(fd, F_SETOWN, getpid())将将进程pid传入内核
6.通过fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC)设置异步通知
驱动部分代码:
- #include <linux/kernel.h>
 - #include <linux/errno.h>
 - #include <linux/module.h>
 - #include <linux/fs.h>
 - #include <linux/miscdevice.h>
 - #include <asm/io.h>
 - #include <linux/interrupt.h>
 - #include <linux/irq.h>
 - #include <linux/gpio.h>
 - #include <mach/regs-gpio.h>
 - #include <asm-generic/siginfo.h>
 - #include <linux/init.h>
 - #include <asm/signal.h>
 - #include <linux/timer.h>
 - #include <asm/uaccess.h>
 - #define DEVICE_NAME "mybeep"
 - volatile unsigned long *GPBCON;
 - volatile unsigned long *GPBDAT;
 - volatile unsigned long *GPBUP;
 - void beep_start(void);
 - void beep_stop(void);
 - int beep_irq_register(void);
 - unsigned int flag=1;
 - static struct fasync_struct *async; //声明fasync_struct
 - struct key_irq_desc {
 - unsigned int irq;
 - int pin;
 - int pin_setting;
 - int number;
 - char *name;
 - };
 - static int beep_fasync(int fd, struct file *filp, int mode)
 - {
 - printk("application fasync!\n");
 - return fasync_helper(fd, filp, mode, &async); //注册上层调用进程的信息,上层调用fcntl设置FASYNC会调用这个系统调用
 - }
 - static struct key_irq_desc key_irqs [] = {
 - {IRQ_EINT8, S3C2410_GPG(0), S3C2410_GPG0_EINT8, 0, "KEY1"},
 - };
 - static irqreturn_t key_interrupt(int irq, void *dev_id)
 - {
 - kill_fasync(&async, SIGIO, POLL_IN); //向打开设备文件的进程发出SIGIO信号
 - return (IRQ_HANDLED);
 - }
 - void beep_gpiob_init(void)
 - {
 - *GPBCON&=~((1<<0)|(1<<1));
 - *GPBCON|=(1<<0);
 - *GPBUP&=~(1<<0);
 - }
 - void beep_start(void)
 - {
 - *GPBDAT|=(1<<0);
 - }
 - void beep_stop(void)
 - {
 - *GPBDAT&=~(1<<0);
 - }
 - int beep_open(struct inode *inode, struct file *filp)
 - {
 - if(beep_irq_register() != 0)
 - {
 - printk("Request irq error!\n");
 - }
 - printk(KERN_ALERT "application open!\n");
 - return 0;
 - }
 - ssize_t beep_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
 - {
 - printk("application read!\n");
 - return 0;
 - }
 - ssize_t beep_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
 - {
 - printk("application write!\n");
 - return 0;
 - }
 - static int beep_release(struct inode *inode, struct file *file)
 - {
 - disable_irq(key_irqs[0].irq);
 - free_irq(key_irqs[0].irq, (void *)&key_irqs[0]);
 - printk("application close!\n");
 - return beep_fasync(-1, file, 0);
 - }
 - static int beep_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 - {
 - switch(cmd)
 - {
 - case 0:
 - beep_start();
 - break;
 - case 1:
 - beep_stop();
 - break;
 - default:
 - break;
 - }
 - return 0;
 - }
 - static struct file_operations beep_ops = {
 - .owner = THIS_MODULE,
 - .open = beep_open,
 - .release = beep_release,
 - .ioctl = beep_ioctl,
 - .read = beep_read,
 - .write = beep_write,
 - .fasync = beep_fasync,
 - };
 - static struct miscdevice beep_misc = {
 - .minor = MISC_DYNAMIC_MINOR,
 - .name = DEVICE_NAME,
 - .fops = &beep_ops,
 - };
 - int beep_irq_register(void)
 - {
 - int err;
 - err = request_irq(key_irqs[0].irq, key_interrupt, 0, key_irqs[0].name, (void *)&key_irqs[0]);
 - set_irq_type(key_irqs[0].irq, IRQ_TYPE_EDGE_RISING);
 - if(err)
 - {
 - disable_irq(key_irqs[0].irq);
 - free_irq(key_irqs[0].irq, (void *)&key_irqs[0]);
 - return -EBUSY;
 - }
 - return 0;
 - }
 - static int __init beep_init(void)
 - {
 - int ret;
 - ret=misc_register(&beep_misc);
 - if(ret <0)
 - {
 - printk("register miscdevice error code:%d\n",ret);
 - return ret;
 - }
 - printk("beep device create!\n");
 - GPBCON=(volatile unsigned long *)ioremap(0x56000010,12);
 - GPBDAT=GPBCON+1;
 - GPBUP=GPBCON+2;
 - beep_gpiob_init();
 - return 0;
 - }
 - static void __exit beep_exit(void)
 - {
 - iounmap(GPBCON);
 - misc_deregister(&beep_misc);
 - printk("beep device delete!\n");
 - }
 - MODULE_LICENSE("GPL");
 - MODULE_AUTHOR("kingdragonfly");
 - module_init(beep_init);
 - module_exit(beep_exit);
 
用户应用程序代码:
- #include <stdio.h>
 - #include <unistd.h>
 - #include <signal.h>
 - #include <fcntl.h>
 - void sig_handler(int sig)
 - {
 - if(sig == SIGIO)
 - {
 - printf("Receive io signal from kernel!\n");
 - }
 - }
 - int main(void)
 - {
 - int fd;
 - signal(SIGIO, sig_handler);
 - fd = open("/dev/mybeep",O_RDWR);
 - fcntl(fd, F_SETOWN, getpid());
 - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
 - printf("waiting key interrupt:\n");
 - while(1)
 - {
 - }
 - }
 
当内核里发生中断时在中断服务程序中发出SIGIO信号从而自动调用相应的回调函数,在回调函数中可以进行相应处理。
上面程序在mini2440开发板实现了按K1键,用户程序自动调用void sig_handler(int sig)功能
Linux内核中断引入用户空间(异步通知机制)【转】的更多相关文章
- Linux 内核态与用户态通信 netlink
		
参考资料: https://blog.csdn.net/zqixiao_09/article/details/77131283 https://www.cnblogs.com/lopnor/p/615 ...
 - Linux 内核中断内幕
		
转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.html#resources Linux 内核中断内幕 ...
 - 嵌入式Linux设备驱动程序:用户空间中的设备驱动程序
		
嵌入式Linux设备驱动程序:用户空间中的设备驱动程序 Embedded Linux device drivers: Device drivers in user space Interfacing ...
 - Linux内核中断顶半部和底半部的理解
		
文章目录 中断上半部.下半部的概念 实现中断下半部的三种方法 软中断 软中断模版 tasklet tasklet函数模版 工作队列 工作队列函数模版 进程上下文和中断上下文 软中断和硬中断的区别 硬中 ...
 - Linux内核中断和异常分析(中)
		
在linux内核中,每一个能够发出中断请求的硬件设备控制器都有一条名为IRQ的输出线.所有现在存在的IRQ线都与一个名为可编程中断控制器的硬件电路的输入引脚相连,上次讲到单片机的时候,我就讲到了单片机 ...
 - Linux之异步通知机制分析
		
1.概念: 异步通知机制:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,是一种“信号驱动的异步I/O”.信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号 ...
 - linux内核态和用户态的信号量
		
在Linux的内核态和用户态都有信号量,使用也不同,简单记录一下. 1> 内核信号量,由内核控制路径使用.内核信号量是struct semaphore类型的对象,它在中定义struct sema ...
 - Linux内核态和用户态
		
两张图说明Linux内核态和用户态之间的关系
 - linux 设备驱动与应用程序异步通知
		
一.异步通知机制简介 异步通知机制的意思:一旦设备准备就绪,可以主动的通知应用程序进行相应的操作,从而使得应用程序不必去查询设备的状态. 异步通知比较准确的称谓是"信号驱动的异步IO&quo ...
 
随机推荐
- C++机试笔记
 - 调试bug 技巧
			
两天,一个小bug 我调试了两天,最终调试成功了.还是在别人的帮助下. 问题是刷新相关的.当用户登录了,其他的页面都要刷新.也就是加上一些参数. 但是有一个fragment一直加不上,其他挨着的两个都 ...
 - react书写规范小记
			
1.对齐方式 //如果没有属性,在自闭和标签前添加一个空格: <Footer /> //如果可以放在一行,放在一行上即可: <Footer bar="bar" / ...
 - 《Cracking the Coding Interview》——第18章:难题——题目1
			
2014-04-29 00:56 题目:不用算数运算,完成加法. 解法:那就位运算吧,用加法器的做法就可以了. 代码: // 18.1 add two numbers wihout using ari ...
 - USACO Section1.3 Ski Course Design 解题报告
			
skidesign解题报告 —— icedream61 博客园(转载请注明出处)------------------------------------------------------------ ...
 - jeakins忘记密码时的处理(简单粗暴)
			
1.打开config文件(通过ps -elf | grep jenkins查看JENKINS_HOME目录,然后在目录下查找config.xml文件) 2.修改<useSecurity>t ...
 - Yapi的坑
			
前一段时间,研究WEB Api相关的工具. YApi 可以内网部署,内心十分的欢喜啊.而且gitHub上推荐超过4000星,成绩很优异嘛.然而通过最终的尝试,我还是打算放弃他,投入Postman的怀抱 ...
 - Java进制间的转换
			
最近学习了Java间的进制转换,记录下自己的学习心得,希望可以帮到前来查看的朋友们,如果有不懂的地方可以在下方评论留言,我们一起学习进步,只有自己足够强大才能弥补不足,多学习, 任意进制到十进制的转换 ...
 - diskimage-builder-command
			
yum -y install python-virtualenv.noarch virtualenv ~/dib-virtualenv . ~/dib-virtualenv/bin/activate ...
 - Set(), Get() 真正的目的
			
在各种面向对象编程中,都有 Set(), Get() 两种方法. 1 常见理解 1 为了保证安全性 2 为了规范代码 其实这些理解都是对的.具体看我们从哪个角度去理解这个内容. 2 个人理解 2.1 ...