【韦东山驱动入门实验班】交互流程解读

在驱动入门实验班的课程里讲到了APP使用驱动程序的四种方式。分别是:阻塞、非阻塞、poll、异步通知。

本文是在前面所描述的概念之上,对驱动程序交互流程的解读。

1. 非阻塞

应用程序 open 时,传入O_NONBLOCK 标记位

Alt
对于 if 判断只需要使用is_key_buf_empty()判断环形缓冲区是否有数据

  • 无数据,is_key_buf_empty()为真,立即返回 -EAGAIN
  • 有数据,wait_event_interruptible()函数就不起作用,直接从缓冲区里拷贝数据,然后返回

注意:非阻塞起作用的前提是驱动程序“尊重O_NONBLOCK 标记位。

2. 阻塞

应用程序 open 时,不带 O_NONBLOCK 标记位

Alt
对于 if 判断,直接失效。因为(file->f_flags & O_NONBLOCK)为假

当没有数据时,调用 wait_event_interruptible()函数,进入等待,直到条件!is_key_buf_empty()为真!等待时:

  • 改变程序状态,休眠的程序不参与调度;
  • 把自己记录在 gpio_wait 里,gpio_wait 是等待队列头;
#define wait_event_interruptible(wq_head, condition)				\
({										\
	int __ret = 0;								\
	might_sleep();								\
	if (!(condition))							\
		__ret = __wait_event_interruptible(wq_head, condition);		\
	__ret;									\
})

当有数据时,被唤醒,即被定时器唤醒(按键被按下或松开执行定时器超时处理函数)

//定时器超时处理函数
wake_up_interruptible(&gpio_wait); /* 唤醒等待队列 */

3. POLL

单来说,就是在 read 之前先调用 poll 函数查询一下是否有数据,poll 函数中可以传入 time_out(超时时间),即超时也会返回。

当调用 poll 函数时,APP 有以下几种情况:

  1. 已有数据,即刻返回
  2. 无数据,休眠
  3. 被唤醒
    a. 按下/松开按键
    b. 超时

POLL 函数的内部机制:
Alt
核心是 sys_poll 中的循环,每次循环都先调用驱动程序的 drv_poll 函数,如果(有数据/超时)就返回,否则就休眠。

驱动程序中的 drv_poll():简单来说它只负责返回自己的状态,表明自己是否有数据可读/可写

static unsigned int gpio_drv_poll(struct file *fp, poll_table * wait)
{
	//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	poll_wait(fp, &gpio_wait, wait);	//1.把进程记录在gpio_wait队列里,并没有休眠
	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;	//2.返回状态
}

第 5 步的唤醒,有两种情况:

  1. 被中断程序唤醒,比如按键按下/松开;
    Alt
  2. 超时,被内核唤醒

当醒来之后,sys_poll()函数的循环会再执行一次,再次调用 drv_poll函数查看是否有数据,有数据就返回 ok,没有数据就返回超时。

4. 异步通知

之前我们说,异步通知相当于孩子长大了,自己告诉“妈妈”他醒了。儿子告诉妈妈,“儿子”是主语,“告诉”是谓语,“妈妈”是宾语。在驱动程序中,“儿子”指中断/定时器的处理函数,“告诉”也就是发信号,“妈妈”就是对应的 APP进程。

应用程序中,首先要给信号 SIGIO 某个信号处理函数挂钩,其次需要把自己的进程告诉驱动程序,并使能异步驱动。
Alt

驱动程序中,当我们把 APP 的进程号告诉驱动程序,并且使能异步通知后,就会构造button_fasync变量(struct fasync_struct),可以从它找到 进程的PID

/* 在驱动程序中定义 */
struct fasync_struct *button_fasync;

static int gpio_drv_fasync(int fd, struct file *file, int on)
{
	if (fasync_helper(fd, file, on, &button_fasync) >= 0)
		return 0;
	else
		return -EIO;
}

当按键按下/抬起时,执行中断处理程序,修改定时器。在定时器超时处理函数中,把按键值记录后,就会给 进程发信号。
Alt
以上是本篇文章的全部内容,谢谢观看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cifeng79

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值