首页 > 代码库 > Linux内核中断引入用户空间(异步通知机制)【转】

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)功能

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