看了很多资料,在阻塞io等待红外中断的基础上,添加了异步通知,完美解决主线程不能阻塞的问题。
原来的测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <sys/ioctl.h>
int main()
{
int fd;
if((fd = open("/dev/infrared",O_RDWR)) < 0)
{
perror("open:");
return -1;
}
int readbye, buf;
while(1){
readbye = read(fd,&buf,sizeof(buf));
printf("buf = %d\n",buf);
if(buf == 0)
{
printf("OK...\n");
}
else
printf("XXXXXXXXXXX\n");
sleep(1);
}
close(fd);
}
*********************************************************************************************
使用异步通知,改进后
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <fcntl.h>
void sig_handler(int sig)
{
if(sig == SIGIO)
{
printf("Receive io signal from kernel!\n");
}
}
int main()
{
int fd;
if((fd = open("/dev/infrared",O_RDWR)) < 0)
{
perror("open:");
return -1;
}
signal(SIGIO, sig_handler); /* 启动信号驱动机制 */
fcntl(fd, F_SETOWN, getpid()); //设置本进程为STDIN_FILENO文件的拥有者,没有这一步内核不会知道应该将信号发送给哪个进程
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);//启动异步通知机制
printf("waiting key interrupt:\n");
while(1) //这个死循环,为了不让程序退出,可以去掉,接着写,,,
{
}
close(fd);
}
/
红外驱动代码:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-adc.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#include <mach/gpio.h>
#include <linux/irq.h>
#define DEVICE_NAME "infrared"
static struct fasync_struct *async; //声明fasync_struct
// XEINT0/GPH0_0
static int infrared_fasync(int fd, struct file *filp, int mode)
{
printk("application fasync!\n");
return fasync_helper(fd, filp, mode, &async);//注册上层调用进程的信息,上层调用fcntl设置FASYNC会调用这个系统调用
}
volatile int interrup = 1;
static int irq;
static irqreturn_t irq_handler(int irq, void *dev_id)
{
printk("Eint0...\n");
interrup = 0;
kill_fasync(&async, SIGIO, POLL_IN); //向打开设备文件的进程发出SIGIO信号
printk("iqr = %d\n",irq);
return IRQ_HANDLED;
}
static int infrared_open(struct inode *inode, struct file *file)
{
return 0;
}
static int infrared_close(struct inode *inode, struct file *file)
{
return infrared_fasync(-1, file, 0);
}
static ssize_t infrared_read(struct file *file,char __user *buf,
size_t const count,loff_t *offset)
{
unsigned long err;
err = copy_to_user((void *)buf, &interrup, sizeof(interrup));
// printk("err = %ld\n",err);
if(err)
{
printk("copy from user fail \n");
return -EFAULT;
}
interrup = 1;
return err ? -EFAULT : min(sizeof(interrup), count);
}
static struct file_operations gec210_infrared_dev_fops = {
.owner = THIS_MODULE,
.read = infrared_read,
.open = infrared_open,
.release = infrared_close,
.fasync = infrared_fasync,
};
static struct miscdevice gec210_infrared_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &gec210_infrared_dev_fops,
};
static int __init gec210_infrared_dev_init(void) {
int ret;
int err = 0;
s3c_gpio_cfgpin(S5PV210_GPH0(0), S3C_GPIO_SFN(0XF));
gpio_set_value(S5PV210_GPH0(0), 0);
s3c_gpio_setpull(S5PV210_GPH0(0), S3C_GPIO_PULL_NONE);
set_irq_type(IRQ_EINT0, IRQ_TYPE_EDGE_FALLING);
err = request_irq(IRQ_EINT0, irq_handler, IRQ_TYPE_EDGE_FALLING, DEVICE_NAME, NULL); //EINT0 注册
if(err)
{
printk("request irq %d failed for infrared, %d\n", irq, err);
return -EBUSY;
}
ret = misc_register(&gec210_infrared_dev);
printk(DEVICE_NAME"\tinitialized\n");
return ret;
}
static void __exit gec210_infrared_dev_exit(void) {
free_irq(IRQ_EINT0, NULL);
misc_deregister(&gec210_infrared_dev);
}
module_init(gec210_infrared_dev_init);
module_exit(gec210_infrared_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gec Lab.");
**********************************************************************************************
应用层:红外接口说明
该驱动包含open(),close(),sig_handler(),signal(),fcntl(),5个函数
1.open()函数说明:
fd = open("/dev/infrared",O_RDWR))
成功打开返回0;
2.close()函数说明:
close(fd);
关闭文件(描述符)
3.sig_handler()函数说明:
void sig_handler(int sig) //中断处理函数
{
printf("Receive io signal from kernel!\n");
//中断来了,要操作的内容
}
应用层中启用异步通知机制
其实就三个步骤:
1)signal(SIGIO, sig_handler);
调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。
2)fcntl(fd, F_SET_OWNER, getpid());
指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。
3)f_flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, f_flags | FASYNC);
在设备文件中添加FASYNC标志,驱动中就会调用将要实现的test_fasync函数。
三个步骤执行后,一旦有信号产生,相应的进程就会收到。
注:【fcntl系统调用】
运行程序,然后来触摸红外传感器,kill=》应用程序处理函数=》sig_handler()=》printf("Receive io signal from kernel!\n"); ok成功,