【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)

学完了休眠唤醒机制、poll机制、异步通知、定时器、tasklet、工作队列、mmap、input子系统后,该沉淀沉淀了

一、睡眠机制

案例:APP程序读取按键值 - 睡眠机制(阻塞或非阻塞)
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第1张图片
1.等待队列头创建

static DECLARE_WAIT_QUEUE_HEAD(key_waitqueue);

2.等待队列

wait_event_interruptible(wq, condition);

等待wq队列,当condition条件为真时表示等到,则返回

3.唤醒队列

wake_up_interruptible(wq);

4.非阻塞机制
上面的方式是阻塞方式,想要非阻塞,打开文件时加上 O_NONBLOCK 标志

fd = open(argv[1], O_RDWR | O_NONBLOCK);

驱动程序也要改,读取时判断文件的 flag 是否有 O_NONBLOCK

if (!key_status && (filp->f_flags & O_NONBLOCK))  
	return -EAGAIN;  
wait_event_interruptible(key_waitqueue, key_status);

“!key_status” 表示此时没有按键值可读,那么如果此时设置了 O_NONBLOCK 标志的话,则不需要等待队列了,直接返回 EAGAIN


二、poll 机制 (闹钟)

案例:APP程序读取按键值 - poll 机制(非阻塞的话直接定时0即可)

poll机制流程细节图
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第2张图片
代码流程图
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第3张图片


三、fasync异步通知

案例:APP程序读取按键值 - fasync异步通知(建议使用)
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第4张图片
fasync异步通知代码流程:

  1. APP程序打开文件,定义 signal 函数(SIGIO信号)
  2. 使用 fcntl 函数设置文件的flag,记录进程pid,设置 FASYNC/O_ASYNC 标志(会触发调用驱动层的 fasync 函数)
  3. 驱动层实现 fasync 函数,使用 fasync_helper 函数初始化 fasync_struct 结构体(保存了文件的标志位)
  4. 按下按键后调用 kill_fasync(&button_fasync, SIGIO, POLL_IN),会从 button_fasync->fa_file 中取出 pid,然后发送 SIGIO 信号
  5. 应用程序执行信号处理函数

PS:如果想要禁止 fasync 功能,屏蔽 FASYNC/O_ASYNC 标志位即可

fcntl(key_fd, F_SETFL, flags & ~O_ASYNC);

关键代码部分:
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第5张图片
在这里插入图片描述
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第6张图片
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第7张图片
【IMX6ULL驱动开发学习】16.睡眠机制_poll机制_fasync异步通知(按键控制LED)_第8张图片
应用程序关键代码

/* F_SETOWN: 设置将接收SIGIO和SIGURG信号的进程id */
fcntl(key_fd, F_SETOWN, getpid());

/*  F_GETFL: 取得fd的文件状态标志 */
flags = fcntl(key_fd, F_GETFL);

/* O_ASYNC: 当I/O可用的时候,允许SIGIO信号发送到进程组,
   例如:当有数据可以读的时候 */
fcntl(key_fd, F_SETFL, flags | O_ASYNC);  //启动驱动的fasync功能

驱动层关键代码:

struct fasync_struct *button_fasync;

...
...

static int key_fasync (int fd, struct file *filp, int on)
{
	int retval;
	retval = fasync_helper(fd, filp, on, &button_fasync);
	if (retval < 0)
		return retval;

	return 0;
}

static struct file_operations key_ops = {
	......
	.fasync		=   key_fasync,
};

...
...

static irqreturn_t key_irq_handler(int irq, void *dev)
{
	......
	kill_fasync(&button_fasync, SIGIO, POLL_IN);
}

你可能感兴趣的:(IMX6ULL,驱动开发,imx6ull,poll,fasync,异步通知,睡眠机制,非阻塞)