概述
异步通知(fasync)
fasync机制是异步通知机制,当驱动程序向应用程序发送信号量,触发应用程序的信号处理函数,以达到类似中断的效果
驱动程序中:
1、在文件专属的fasync函数中,调用了fasync_helper,将属主信息通知给内核
2、当发生按键中断,进入按键中断服务程序,读取键值,调用kill_fasync,发送信号量给相应进程
应用程序中:
1、使用signal,设置信号处理函数
2、使用fcntl(fd,F_SETOWN,getpid());,指定一个进程作为文件的属主,属主的进程ID号就保存在filp->f_owner中
3、fcntl获取、设置标志,设置标志的时候,最终会调用到文件专属的fasync函数
4、当有按键中断发生,驱动程序发送信号量,触发应用程序的信号处理函数,读取键值
GPIO中断设备驱动
/* Raspberry pi GPIO interrupt processing example
* Light on LED with BUTTON press
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#define SUCCESS (0)
#define ERROR (-1)
static struct fasync_struct *fasync_queue; //异步通知队列
#define BUTTON_PIN 25 /* GPIO 25 */
int flag = 0;
struct cdev *button_dev;//使用cdev结构体来描述字符设备
dev_t devNum;//通过其成员dev_t来定义设备号(分为主、次设备号)以确定字符设备的唯一性
unsigned int subDevNum = 1;//请求的连续设备个数
int reg_major = 501;//主设备号
int reg_minor = 0; //次设备号
static irqreturn_t irq_handler(int irq, void *dev)
{
printk("key pressed");
if (fasync_queue) {
kill_fasync(&fasync_queue, SIGIO, POLL_IN);
}
return IRQ_HANDLED;
}
static int button_fasync(int fd, struct file * filp, int on)
{
int retval;
retval=fasync_helper(fd,filp,on,&fasync_queue);
if(retval<0)
return retval;
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.fasync = button_fasync,
};
static int button_init(void)
{
int err;
devNum = MKDEV(reg_major, reg_minor);//通过主次设备号生成设备号
if(SUCCESS == register_chrdev_region(devNum, subDevNum, "button")){
printk(KERN_INFO "register_chrdev_region ok n");
}
else {
printk(KERN_INFO "register_chrdev_region error n");
return ERROR;
}
printk(KERN_INFO " button driver init n");
button_dev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
cdev_init(button_dev, &dev_fops);
cdev_add(button_dev, devNum, 1);
printk(KERN_INFO "LED initn");
err = gpio_request_one(BUTTON_PIN, GPIOF_IN, "Light Button");
if (err) return err;
enable_irq(gpio_to_irq(BUTTON_PIN));
err = request_irq(gpio_to_irq(BUTTON_PIN), irq_handler,
IRQF_TRIGGER_FALLING, "LED Test", NULL);
if (err < 0) {
printk("irq_request failed!n");
return err;
}
flag = 1;
return 0;
}
static void button_exit(void)
{
printk(KERN_INFO "LED exitn");
if(flag) free_irq(gpio_to_irq(BUTTON_PIN), NULL);
gpio_free(BUTTON_PIN);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("Dual BSD/GPL");
异步通信
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
static int fd;
/* 内核产生异步通知,调用该应用层函数处理 */
void sigterm_handler(int signo)
{
printf("app irq work !!!n");
}
int main(void)
{
int oflags;
fd=open("/dev/button",O_RDWR); //打开设备文件
/* 启动异步通知信号驱动机制 */
signal(SIGIO, sigterm_handler);
fcntl(fd, F_SETOWN, getpid());
oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, oflags | FASYNC);
/*建立一个死循环,防止程序结束 */
while(1)
{
printf("sleepn");
usleep(200000); //2ms
}
close(fd);
return 0;
}
最后
以上就是糟糕大山为你收集整理的Linux GPIO中断异步通知的全部内容,希望文章能够帮你解决Linux GPIO中断异步通知所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复