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)设置异步通知

 

驱动部分代码:

 

 

[cpp] view plain copy

 

  1. #include <linux/kernel.h>  
  2. #include <linux/errno.h>  
  3. #include <linux/module.h>  
  4. #include <linux/fs.h>  
  5. #include <linux/miscdevice.h>  
  6. #include <asm/io.h>  
  7. #include <linux/interrupt.h>  
  8. #include <linux/irq.h>  
  9. #include <linux/gpio.h>  
  10. #include <mach/regs-gpio.h>  
  11. #include <asm-generic/siginfo.h>  
  12. #include <linux/init.h>  
  13. #include <asm/signal.h>  
  14. #include <linux/timer.h>  
  15. #include <asm/uaccess.h>  
  16.   
  17. #define DEVICE_NAME "mybeep"  
  18.   
  19. volatile unsigned long *GPBCON;  
  20. volatile unsigned long *GPBDAT;  
  21. volatile unsigned long *GPBUP;  
  22. void beep_start(void);  
  23. void beep_stop(void);  
  24. int  beep_irq_register(void);  
  25. unsigned int flag=1;  
  26.   
  27. static struct fasync_struct *async; //声明fasync_struct  
  28. struct key_irq_desc {  
  29.     unsigned int irq;  
  30.     int pin;  
  31.     int pin_setting;  
  32.     int number;  
  33.     char *name;  
  34. };  
  35.   
  36. static int beep_fasync(int fd, struct file *filp, int mode)  
  37. {  
  38.     printk("application  fasync!\n");  
  39.     return fasync_helper(fd, filp, mode, &async);         //注册上层调用进程的信息,上层调用fcntl设置FASYNC会调用这个系统调用  
  40. }  
  41.   
  42. static struct key_irq_desc key_irqs [] = {  
  43.     {IRQ_EINT8, S3C2410_GPG(0), S3C2410_GPG0_EINT8, 0, "KEY1"},  
  44. };  
  45.   
  46. static irqreturn_t key_interrupt(int irq, void *dev_id)  
  47. {  
  48.     kill_fasync(&async, SIGIO, POLL_IN);  //向打开设备文件的进程发出SIGIO信号  
  49.     return (IRQ_HANDLED);  
  50. }  
  51.   
  52. void beep_gpiob_init(void)  
  53. {  
  54.     *GPBCON&=~((1<<0)|(1<<1));  
  55.     *GPBCON|=(1<<0);  
  56.     *GPBUP&=~(1<<0);  
  57. }  
  58.   
  59. void beep_start(void)  
  60. {  
  61.     *GPBDAT|=(1<<0);  
  62. }  
  63.   
  64. void beep_stop(void)  
  65. {  
  66.     *GPBDAT&=~(1<<0);  
  67. }  
  68.   
  69. int beep_open(struct inode *inode, struct file *filp)  
  70. {  
  71.     if(beep_irq_register() != 0)  
  72.     {  
  73.         printk("Request irq error!\n");  
  74.     }  
  75.     printk(KERN_ALERT "application  open!\n");  
  76.     return 0;  
  77. }  
  78.   
  79. ssize_t beep_read(struct file *file, char __user *buff, size_t count, loff_t *offp)  
  80. {  
  81.     printk("application  read!\n");  
  82.     return 0;  
  83. }  
  84.   
  85. ssize_t beep_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)  
  86. {  
  87.     printk("application  write!\n");  
  88.     return 0;  
  89. }  
  90.   
  91. static int beep_release(struct inode *inode, struct file *file)  
  92. {  
  93.     disable_irq(key_irqs[0].irq);  
  94.     free_irq(key_irqs[0].irq, (void *)&key_irqs[0]);  
  95.     printk("application  close!\n");  
  96.     return beep_fasync(-1, file, 0);  
  97. }  
  98.   
  99. static int beep_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
  100. {  
  101.     switch(cmd)  
  102.     {  
  103.     case 0:  
  104.         beep_start();  
  105.         break;  
  106.     case 1:  
  107.         beep_stop();  
  108.         break;  
  109.     default:  
  110.         break;  
  111.     }  
  112.     return 0;  
  113. }  
  114.   
  115. static struct file_operations beep_ops = {  
  116.     .owner = THIS_MODULE,  
  117.     .open = beep_open,  
  118.     .release = beep_release,  
  119.     .ioctl = beep_ioctl,  
  120.     .read = beep_read,  
  121.     .write = beep_write,  
  122.     .fasync = beep_fasync,  
  123. };  
  124.   
  125. static struct miscdevice beep_misc = {  
  126.     .minor = MISC_DYNAMIC_MINOR,  
  127.     .name = DEVICE_NAME,  
  128.     .fops = &beep_ops,  
  129. };  
  130.   
  131. int beep_irq_register(void)  
  132. {  
  133.     int err;  
  134.     err = request_irq(key_irqs[0].irq, key_interrupt, 0, key_irqs[0].name, (void *)&key_irqs[0]);  
  135.     set_irq_type(key_irqs[0].irq, IRQ_TYPE_EDGE_RISING);  
  136.     if(err)  
  137.     {  
  138.         disable_irq(key_irqs[0].irq);  
  139.         free_irq(key_irqs[0].irq, (void *)&key_irqs[0]);  
  140.         return -EBUSY;  
  141.     }  
  142.     return 0;  
  143. }  
  144.   
  145. static int __init beep_init(void)  
  146. {  
  147.     int ret;  
  148.     ret=misc_register(&beep_misc);  
  149.     if(ret <0)  
  150.     {  
  151.         printk("register miscdevice error code:%d\n",ret);  
  152.         return ret;  
  153.     }  
  154.     printk("beep device create!\n");  
  155.     GPBCON=(volatile unsigned long *)ioremap(0x56000010,12);  
  156.     GPBDAT=GPBCON+1;  
  157.     GPBUP=GPBCON+2;  
  158.     beep_gpiob_init();  
  159.     return 0;  
  160. }  
  161.   
  162. static void __exit beep_exit(void)  
  163. {  
  164.     iounmap(GPBCON);  
  165.     misc_deregister(&beep_misc);  
  166.     printk("beep device delete!\n");  
  167. }  
  168.   
  169. MODULE_LICENSE("GPL");  
  170. MODULE_AUTHOR("kingdragonfly");  
  171. module_init(beep_init);  
  172. module_exit(beep_exit);  

 

用户应用程序代码:

 

[cpp] view plain copy

 

  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <signal.h>  
  4. #include <fcntl.h>  
  5.   
  6. void sig_handler(int sig)  
  7. {  
  8.     if(sig == SIGIO)  
  9.     {  
  10.         printf("Receive io signal from kernel!\n");  
  11.     }  
  12. }  
  13.   
  14. int main(void)  
  15. {  
  16.     int fd;  
  17.     signal(SIGIO, sig_handler);  
  18.     fd = open("/dev/mybeep",O_RDWR);  
  19.     fcntl(fd, F_SETOWN, getpid());  
  20.     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);  
  21.     printf("waiting key interrupt:\n");  
  22.     while(1)  
  23.     {  
  24.     }  
  25. }  

当内核里发生中断时在中断服务程序中发出SIGIO信号从而自动调用相应的回调函数,在回调函数中可以进行相应处理。

 

上面程序在mini2440开发板实现了按K1键,用户程序自动调用void sig_handler(int sig)功能

时间: 2024-09-04 20:32:29

Linux内核中断引入用户空间(异步通知机制)【转】的相关文章

Linux内核中断和异常分析(中)

在linux内核中,每一个能够发出中断请求的硬件设备控制器都有一条名为IRQ的输出线.所有现在存在的IRQ线都与一个名为可编程中断控制器的硬件电路的输入引脚相连,上次讲到单片机的时候,我就讲到了单片机中断的一些概念.我们现在来看一幅图,更好说明一个问题:      这下面的这幅图是51单片机的一个关于矩阵键盘的学习的一个proteus的仿真电路图. 其中P3.2和P3.3为外部中断引脚,当可编程控制器(51MCU)收到外部中断响应的时候,会执行一些特定的操作,当然这需要开发者去编写一个中断初始化

Linux基金会透露未来 Linux内核可能会引入形式验证

本月19日在北京举办的 LC3 大会 (LinuxCon + ContainerCon + CloudOpen)应该是全球最顶级的开源大会了,而这一为期两天的开源盛会过去几年在北美.欧洲和日本都举办过,而此次是其首次来到中国.就在同一天,Linux 发布了 4.12-rc6 的 release,而Linux 基金会在这次大会上也独家透露了一些未来 Linux 内核开发的新特性. Linux 基金会的执行董事 Jim Zemblin 是本次大会的主持人,他同时也出席了本次大会的发布会,接受了中国媒

Linux 基金会透露未来 Linux 内核可能会引入形式验证

本月19日在北京举办的 LC3 大会 (LinuxCon + ContainerCon + CloudOpen)应该是全球最顶级的开源大会了,而这一为期两天的开源盛会过去几年在北美.欧洲和日本都举办过,而此次是其首次来到中国.就在同一天,Linux 发布了 4.12-rc6 的 release,而Linux 基金会在这次大会上也独家透露了一些未来 Linux 内核开发的新特性. Linux 基金会的执行董事 Jim Zemblin 是本次大会的主持人,他同时也出席了本次大会的发布会,接受了中国媒

Linux Malloc分析-从用户空间到内核空间【转】

转自:http://blog.csdn.net/ordeder/article/details/41654509 版权声明:本文为博主(http://blog.csdn.net/ordeder)原创文章,未经博主允许不得转载.   目录(?)[-] 1背景知识 1 进程的用户空间  12 地址映射 malloc 和free 1 用户层 2 内核层 3 虚拟地址与物理地址 总结 参考 附录   本文介绍malloc的实现及其malloc在进行堆扩展操作,并分析了虚拟地址到物理地址是如何实现映射关系

Linux 内核中断内幕【转】

转自:https://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/index.html 本文对中断系统进行了全面的分析与探讨,主要包括中断控制器.中断分类.中断亲和力.中断线程化与 SMP 中的中断迁徙等.首先对中断工作原理进行了简要分析,接着详细探讨了中断亲和力的实现原理,最后对中断线程化与非线程化中断之间的实现机理进行了对比分析. 3评论 苏 春艳, 在读研究生 杨 小华 (normalnotebook@126.com),

Linux内核中断和异常分析(下)

这节,我们继续上,中(以前的日志有)篇目进行分析,结合一个真实的驱动案例来描述linux内核中驱动的中断机制,首先我们先了解一下linux内核中提供的中断接口.      这个接口我们需要包含一个头文件:#include <linux/interrupt.h>      在中断接口中,最重要的是以下的接口函数: 1.这个是请求中断函数 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags,

Linux内核中断和异常分析(上)

中断,通常被定义为一个事件.打个比方,你烧热水,水沸腾了,这时候你要去关掉烧热水的电磁炉,然后再去办之前手中停不下来的事情.那么热水沸腾就是打断你正常工作的一个信号机制.当然,还有其它的情况,我们以后再做分析.       中断也就是这样产生的,中断分为同步中断还有异步中断.       同步中断在Intel的手册中被称为异常,而异步中断被称作中断.打个比方在ARM处理器的异常种类就有不少,有未定义指令异常,软中断异常,快中断异常等等.异常是由程序错误产生的,或者是内核必须处理的异常条件产生的.

linux 内核与用户空间通信之netlink使用方法

Linux中的进程间通信机制源自于Unix平台上的进程通信机制.Unix的两大分支AT&T Unix和BSD Unix在进程通信实现机制上的各有所不同,前者形成了运行在单个计算机上的System V IPC,后者则实现了基于socket的进程间通信机制.同时Linux也遵循IEEE制定的Posix IPC标准,在三者的基础之上实现了以下几种主要的IPC机制:管道(Pipe)及命名管道(Named Pipe),信号(Signal),消息队列(Message queue),共享内存(Shared M

用户空间与内核空间数据交换的方式(9)------netlink【转】

转自:http://www.cnblogs.com/hoys/archive/2011/04/10/2011722.html Netlink 是一种特殊的 socket,它是 Linux 所特有的,类似于 BSD 中的AF_ROUTE 但又远比它的功能强大,目前在最新的 Linux 内核(2.6.14)中使用netlink 进行应用与内核通信的应用很多,包括:路由 daemon(NETLINK_ROUTE),1-wire 子系统(NETLINK_W1),用户态 socket 协议(NETLINK