字符驱动程序之——异步信号通知

为了使设备支持异步通知机制,驱动程序中涉及以下 3 项工作:
1. 支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。
不过此项工作已由内核完成,设备驱动无须处理。
2. 支持 F_SETFL 命令的处理,每当 FASYNC 标志改变时,驱动程序中的 fasync()函数将得以
执行。
驱动中应该实现 fasync()函数。
3. 在设备资源可获得时,调用 kill_fasync()函数激发相应的信号

应用程序:
fcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁
应用程序会调用“fcntl()”这个函数,把进程的 PID 号告诉给驱动程序。
应用程序还要通过“F_GETFL”读出“flags”,在 flags 上置上“FASYNC”位。
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC); // 改变 fasync 标记, 最终会调用到驱动的 faync >
fasync_helper:初始化/释放 fasync_struct

字符驱动之前的方式:
一,应用程序主动的去查询或 read。
1.查询方式:很占资源。
2.中断机制:虽然有休眠,但在没有按键按下时 read()会一直等待,永远不会返回。
3.poll 机制:指定超时时间。
以上都是“应用程序”主动去读或查询。

今天学习的方式:
二,异步通知:
有按键按下了,驱动程序来提醒(触发)“应用程序”去读键值。用“signal”
进程之间发信号:
kill -9 pid
kill 是信号发送者,
pid 具体进程是信号接收者。
信号值是“9”
“信号”与“中断”差不多。注册中断处理函数时是用“request_irq(中断号,处理函数)”。
信号也是有一个“信号”和“处理函数”。
参数是“信号的值”,和要挂接的“信号处理函数”。

测试信号应用程序:

kill -9 pid: 9 这个信号处理函数就是让这个进程退出来。
1,先注册“信号处理函数”。
2,发送信号。

①,谁来发信号。
②,发给谁。
③,怎么发

三,异步通知功能的驱动函数的应用程序:
目标:按下按键时,驱动程序通知应用程序。(以前是应用程序主动读取按键值)
1,应用程序中要注册“信号处理函数”。因为通知它做什么事情,这要一个函数来做。
2,谁发:是驱动程序发送信号。
3,发给谁:信号发送给应用程序。应用程序要告诉驱动程序它自已的 PID,
4,如何发:驱动程序中调用某个函数(kill_fasync())

操作总结:

我们通过内核发送信号给应用程序,让应用程序在有按键按下的时候执行回调函数去读取按键值。

首先增加文件操作的结构体成员:

这个函数指针原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

/* fifthdrvtest
  */
int fd;

void my_signal_fun(int signum)
{
    unsigned char key_val;
    read(fd, &key_val, 1);//执行了这个read的前提是有按键按下了
    printf("key_val: 0x%x\n", key_val);
}

int main(int argc, char **argv)
{
    unsigned char key_val;
    int ret;
    int Oflags;

    signal(SIGIO, my_signal_fun);

    fd = open("/dev/buttons", O_RDWR);
    if (fd < 0)
    {
        printf("can‘t open!\n");
    }

    fcntl(fd, F_SETOWN, getpid());//告诉内核信号发送给谁?通过PID编号体现

    Oflags = fcntl(fd, F_GETFL); //应用程序读出标志位Oflags

    fcntl(fd, F_SETFL, Oflags | FASYNC);//并把标志位加上异步信息,应用程序调用该函数会触发驱动层去调用我们编写的fifth_drv_fasync函数

    while (1)
    {
        sleep(1000);
    }

    return 0;
}

原文地址:https://www.cnblogs.com/yangguang-it/p/8975707.html

时间: 2024-08-26 05:05:16

字符驱动程序之——异步信号通知的相关文章

字符设备之异步信号通知

应用程序注册信号处理函数 my_signal_fun(); 应用程序获取应用PID并告诉驱动 fcntl(fd, F_SETOWN, getpid()); int oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, oflags|FASYNC); 由驱动程序发出信号: xxx_async结构体在fasync函数中调用return fasync_helper(fd , filp, on, &xxx_button)后初始化; 发信号函数kill_fasyn

Linux设备驱动程序 之 异步通知

尽管大多数时候阻塞型和非阻塞型操作的组合以及select方法可以有效的查询设备,但是某些时候用这种技术处理就效率不搞了: 例如:一个进程在低优先级执行长的循环计算,但又需要尽可能快的处理输入数据,如果该进程正在响应来自数据收集外设新观测的数据,则应该在新数据可用时理解知晓并处理:我们可以使用poll来检查,但是跟好的做法是通过异步通知,应用程序可以再数据可用时收到一个信号,而不需要不停的使用轮询来关注数据: 从应用程序的角度 启用文件的异步通知机制,用户程序必须执行两个步骤: 1. 需要制定一个

Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]【转】

转自:http://blog.csdn.net/jacobywu/article/details/7475432 阻塞型I/O和非阻塞I/O 阻塞:休眠 非阻塞:异步通知 一 休眠 安全地进入休眠的两条规则: (1) 永远不要在原子上下文中进入休眠,即当驱动在持有一个自旋锁.seqlock或者 RCU锁时不能睡眠:关闭中断也不能睡眠.持有一个信号量时休眠是合法的,但你应当仔细查看代码:如果代码在持有一个信号量时睡眠,任何其他的等待这个信号量的线程也会休眠.因此发生在持有信号量时的休眠必须短暂,而

信号中断与异步信号中断安全编程

1.什么是中断? 1.1.什么是中断 外围设备的速度远低于CPU的速度,所以为提高CPU计算效率,现代计算机变内核主动为硬件主动,只在硬件需要的时候才发送信号,通知内核来处理数据.这样外围设备与内核的协作方式即为中断机制.而设备发送的信号即为中断,其本质为一种特殊的电信号. 硬中断处理流程: 1.各外围设备与中断管理器各输入引脚相连: 2.中断管理器与CPU之间只存在一条中断管线: 3.设备发送一个中断到中断管理器: 4.中断管理器发送对应电信号给CPU. 5.CPU中断当前工作,开始处理中断,

树莓派上的GPIO字符驱动程序

前言 主要是在嵌入式Linux(树莓派)中如何使用已有的函数库编写应用程序操纵GPIO,如何编写字符设备驱动程序在内核程序中使用GPIO 硬件连接图 虚拟文件系统操作GPIO Linux可以通过访问sys/class/gpio下的一些文件,通过对这些文件的读写来实现对于GPIO的访问. 树莓派下面的可用的GPIO如下图所示,需要注意树莓派一代和二代的区别 首先用一个小灯来测试下操作.首先向export中写入18,表示启用18号gpio端口,执行之后,可以看到该目录下多出了一个gpio18的目录.

小白的linux字符驱动程序

关于如何编译一个测试型的字符驱动程序,网上一搜还是很多的在此给出一个不错的教程http://blog.chinaunix.net/uid-11829250-id-337300.html 我主要是在搜索ioctl的时候才有自己编写一个字符驱动的想法,因为刚工作的时候就看到有同事在用ioctl,当时在网上搜了下ioctl也没怎么明白.现在才发现原来ioctl就是对应的设备驱动程序里的ioctl函数.好了,废话就不多说了.写这篇文档的主要意义在于给后来编写驱动程序的新手们提示几个可能会遇到的问题,希望

linux可重入、异步信号安全和线程安全

一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕获到信号时进程正在执行的正常指令序列(这和当一个硬件中断发生是所发生的事情相似.)但是在信号处理器里,我们并不知道当信号被捕获时进程正在执行哪里的代码. 如果进程正使用malloc在它的堆上分配额外的内存,而此时由于捕捉到信号而插入执行该信号处理程序,其中又调用了malloc,这会

函数的可重入性、线程安全函数、异步信号安全函数

重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰.,常见的情况是,程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),这样便发生了所谓的重入.此时如果foo()能够正确的运行,而且处理完

linux 异步信号的同步处理方式

关于代码的可重入性,设计开发人员一般只考虑到线程安全,异步信号处理函数的安全却往往被忽略.本文首先介绍如何编写安全的异步信号处理函数:然后举例说明在多线程应用中如何构建模型让异步信号在指定的线程中以同步的方式处理. 应用中编写安全的信号处理函数 在开发多线程应用时,开发人员一般都会考虑线程安全,会使用 pthread_mutex 去保护全局变量.如果应用中使用了信号,而且信号的产生不是因为程序运行出错,而是程序逻辑需要,譬如 SIGUSR1.SIGRTMIN 等,信号在被处理后应用程序还将正常运