红外驱动-异步通知

看了很多资料,在阻塞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");

//中断来了,要操作的内容

}

应用层中启用异步通知机制

其实就三个步骤:

1signal(SIGIO, sig_handler);

调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。

2fcntl(fd, F_SET_OWNER, getpid());

指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。

3f_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成功,


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值