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