我是靠谱客的博主 糟糕大山,最近开发中收集的这篇文章主要介绍Linux GPIO中断异步通知,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

异步通知(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中断异步通知所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(110)

评论列表共有 0 条评论

立即
投稿
返回
顶部