营销企业网站建设步骤,学互联网以后能干什么,云工厂网站建设,网站锚点怎么用嵌入式Linux应用开发-基础知识-第十九章驱动程序基石② 第十九章 驱动程序基石②19.3 异步通知19.3.1 适用场景19.3.2 使用流程19.3.3 驱动编程19.3.4 应用编程19.3.5 现场编程19.3.6 上机编程19.3.7 异步通知机制内核代码详解 19.4 阻塞与非阻塞19.4.1 应用编程19.4.2 驱动编程… 嵌入式Linux应用开发-基础知识-第十九章驱动程序基石② 第十九章 驱动程序基石②19.3 异步通知19.3.1 适用场景19.3.2 使用流程19.3.3 驱动编程19.3.4 应用编程19.3.5 现场编程19.3.6 上机编程19.3.7 异步通知机制内核代码详解 19.4 阻塞与非阻塞19.4.1 应用编程19.4.2 驱动编程19.4.3 驱动开发原则 第十九章 驱动程序基石② 19.3 异步通知
使用 GIT命令载后本节源码位于这个目录下
01_all_series_quickstart\
05_嵌入式 Linux驱动开发基础知识\source\
06_gpio_irq\ 05_read_key_irq_poll_fasync 19.3.1 适用场景
在前面引入中断时我们曾经举过一个例子
妈妈怎么知道卧室里小孩醒了 ① 时不时进房间看一下查询方式 简单但是累 ② 进去房间陪小孩一起睡觉小孩醒了会吵醒她休眠-唤醒 不累但是妈妈干不了活了 ③ 妈妈要干很多活但是可以陪小孩睡一会定个闹钟poll方式 要浪费点时间但是可以继续干活。 妈妈要么是被小孩吵醒要么是被闹钟吵醒。 ④ 妈妈在客厅干活小孩醒了他会自己走出房门告诉妈妈异步通知 妈妈、小孩互不耽误 使用休眠-唤醒、POLL机制时都需要休眠等待某个事件发生时它们的差别在于后者可以指定休眠的时长。 在现实生活中妈妈可以不陪小孩睡觉小孩醒了之后可以主动通知妈妈。 如果 APP不想休眠怎么办也有类似的方法驱动程序有数据时主动通知APPAPP收到信号后执行信息处理函数。 什么叫“异步通知” 你去买奶茶 你在旁边等着眼睛盯着店员生怕别人插队他一做好你就知道你是主动等待他做好这叫“同步”。 你付钱后就去玩手机了店员做好后他会打电话告诉你你是被动获得结果这叫“异步”。
19.3.2 使用流程
驱动程序怎么通知 APP发信号这只有 3个字却可以引发很多问题 ① 谁发驱动程序发 ② 发什么信号 ③ 发什么信号SIGIO ④ 怎么发内核里提供有函数 ⑤ 发给谁APPAPP要把自己告诉驱动 ⑥ APP收到后做什么执行信号处理函数 ⑦ 信号处理函数和信号之间怎么挂钩APP注册信号处理函数 小孩通知妈妈的事情有很多饿了、渴了、想找人玩。 Linux系统中也有很多信号在 Linux内核源文件 include\uapi\asm-generic\signal.h中有很多信号的宏定义
就 APP而言你想处理 SIGIO信息那么需要提供信号处理函数并且要跟 SIGIO挂钩。这可以通过一个 signal函数来“给某个信号注册处理函数”用法如下
APP还要做什么事想想这几个问题 ① 内核里有那么多驱动你想让哪一个驱动给你发 SIGIO信号 APP要打开驱动程序的设备节点。 ② 驱动程序怎么知道要发信号给你而不是别人 APP要把自己的进程 ID告诉驱动程序。 ③ APP有时候想收到信号有时候又不想收到信号 应该可以把 APP的意愿告诉驱动。 驱动程序要做什么发信号。 ① APP设置进程 ID时驱动程序要记录下进程 ID ② APP还要使能驱动程序的异步通知功能驱动中有对应的函数 APP打开驱动程序时内核会创建对应的 file结构体file中有 f_flags f_flags中有一个 FASYNC位它被设置为 1时表示使能异步通知功能。 当 f_flags中的 FASYNC位发生变化时驱动程序的 fasync函数被调用。 ③ 发生中断时有数据时驱动程序调用内核辅助函数发信号。 这个辅助函数名为 kill_fasync。 完美 APP收到信号后是怎么执行信号处理函数的 这个很难有兴趣的话就看本节最后的文档。初学者没必要看。 综上所述使用异步通知也就是使用信号的流程如下图所示
重点从②开始 ② APP给 SIGIO这个信号注册信号处理函数 func以后 APP收到 SIGIO信号时这个函数会被自动调用 ③ 把 APP的 PID(进程 ID)告诉驱动程序这个调用不涉及驱动程序在内核的文件系统层次记录 PID ④ 读取驱动程序文件 Flag ⑤ 设置 Flag里面的 FASYNC位为 1当 FASYNC位发生变化时会导致驱动程序的 fasync被调用 ⑥⑦ 调用 faync_helper它会根据 FAYSNC的值决定是否设置 button_async-fa_file驱动文件filp 驱动文件 filp结构体里面含有之前设置的 PID。 ⑧ APP可以做其他事 ⑨⑩ 按下按键发生中断驱动程序的中断服务程序被调用里面调用 kill_fasync发信号 ⑪⑫⑬ APP收到信号后它的信号处理函数被自动调用可以在里面调用 read函数读取按键。
19.3.3 驱动编程
使用异步通知时驱动程序的核心有 2
① 提供对应的 drv_fasync函数 ② 并在合适的时机发信号。 drv_fasync函数很简单调用 fasync_helper函数就可以如下
static struct fasync_struct *button_async;
static int drv_fasync (int fd, struct file *filp, int on)
{ return fasync_helper (fd, filp, on, button_async);
} fasync_helper函数会分配、构造一个 fasync_struct结构体 button_async ① 驱动文件的 flag被设置为 FAYNC时
button_async-fa_file filp; // filp表示驱动程序文件里面含有之前设置的 PID ② 驱动文件被设置为非 FASYNC时
button_async-fa_file NULL; 以后想发送信号时使用 button_async作为参数就可以它里面“可能”含有 PID。 什么时候发信号呢在本例中在 GPIO中断服务程序中发信号。 怎么发信号呢代码如下
kill_fasync (button_async, SIGIO, POLL_IN); 第 1个参数button_async-fa_file非空时可以从中得到 PID表示发给哪一个 APP 第 2个参数表示发什么信号SIGIO 第 3个参数表示为什么发信号POLL_IN有数据可以读了。(APP用不到这个参数)
19.3.4 应用编程
应用程序要做的事情有这几件 ① 编写信号处理函数
static void sig_func(int sig)
{ int val; read(fd, val, 4); printf(get button : 0x%x\n, val); } ② 注册信号处理函数
signal(SIGIO, sig_func); ③ 打开驱动
fd open(argv[1], O_RDWR); ④ 把进程 ID告诉驱动
fcntl(fd, F_SETOWN, getpid()); ⑤ 使能驱动的 FASYNC功能
flags fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC); 19.3.5 现场编程
19.3.6 上机编程
19.3.7 异步通知机制内核代码详解
还没写
19.4 阻塞与非阻塞
所谓阻塞就是等待某件事情发生。比如调用 read读取按键时如果没有按键数据则 read函数不会返回它会让线程休眠等待。 使用 poll时如果传入的超时时间不为 0这种访问方法也是阻塞的。
使用 poll时可以设置超时时间为 0这样即使没有数据它也会立刻返回这就是非阻塞方式。能不能让 read函数既能工作于阻塞方式也可以工作于非阻塞方式可以 APP调用 open函数时传入 O_NONBLOCK就表示要使用非阻塞方式默认是阻塞方式。 注意对于普通文件、块设备文件O_NONBLOCK不起作用。 注意对于字符设备文件O_NONBLOCK起作用的前提是驱动程序针对 O_NONBLOCK做了处理。 只能在 open时表明 O_NONBLOCK吗在 open之后也可以通过 fcntl修改为阻塞或非阻塞。 使用 GIT命令载后本节源码位于这个目录下
01_all_series_quickstart\
05_嵌入式 Linux驱动开发基础知识\source\
06_gpio_irq\ 06_read_key_irq_poll_fasync_block 19.4.1 应用编程
open时设置
int fd open(“/dev/xxx”, O_RDWR | O_NONBLOCK); /* 非阻塞方式 */ int fd open(“/dev/xxx”, O_RDWR ); /* 阻塞方式 */ open之后设置
int flags fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); /* 非阻塞方式 */
fcntl(fd, F_SETFL, flags ~O_NONBLOCK); /* 阻塞方式 */ 19.4.2 驱动编程
以 drv_read为例
static ssize_t drv_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) if (queue_empty(as-queue) fp-f_flags O_NONBLOCK) return -EAGAIN; wait_event_interruptible(apm_waitqueue, !queue_empty(as-queue)); …… 从驱动代码也可以看出来当 APP打开某个驱动时在内核中会有一个 struct file结构体对应这个驱动这个结构体中有 f_flags就是打开文件时的标记位可以设置 f_flasgs的 O_NONBLOCK位表示非阻塞也可以清除这个位表示阻塞。 驱动程序要根据这个标记位决定事件未就绪时是休眠和还是立刻返回。
19.4.3 驱动开发原则
驱动程序程序“只提供功能不提供策略”。就是说驱动程序可以提供休眠唤醒、查询等等各种方式驱动程序只提供这些能力怎么用由 APP决定。