Linux內核中斷引入用戶空間(異步通知機制)

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

發佈了141 篇原創文章 · 獲贊 108 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章