IMX6ULL嵌入式Linux驱动开发学习
以下内容是我在学习正点原子IMX6ULL
开发板alpha
中记录的笔记,部分摘录自正点原子IMX6ULL开发手册
。
一、异步通知简介
1.1 硬件中断
中断是处理器提供的一种异步机制,配置好中断以后就可以让处理器去处理其他的事情了,当中断发生以后会触发事先设置好的中断服务函数,在中断服务函数中做具体的处理。
1.2 信号
信号类似于我们硬件上使用的“中断”,信号是软件层次上对中断机制的一种模拟,也叫作软中断信号。和软中断不是一个概念。
驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了,应用程序获取到信号以后就可以从驱动设备中读取或者写入数据。整个过程就相当于应用程序收到了驱动发送过来了的一个中断,然后应用程序去响应这个中断。
异步通知的核心就是信号,在arch/xtensa/include/uapi/asm/signal.h
中定义了Linux
所持的信号,如下所示。
1 |
|
这些信号中,除了 SIGKILL(9)
和 SIGSTOP(19)
这两个信号不能被忽略外,其他的信号都可以忽略。这些信号就相当于中断号,不同的中断号代表了不同的中断,不同的中断所做的处理不同,因此,驱动程序可以通过向应用程序发送不同的信号来实现不同的功能。
1.3 信号处理函数
使用中断的时候需要设置中断处理函数,同样的,如果要在应用程序中使用信号,那么就必须设置信号所使用的信号处理函数,在应用程序中使用 signal
函数来设置指定信号的处理函数, signal
函数原型如下所示
1 | /** |
1.4 驱动中对异步通知的处理
需要在驱动程序中定义一个
fasync_struct
结构体指针变量,fasync_struct
结构体内容如下:1
2
3
4
5
6
7
8>struct fasync_struct {
>spinlock_t fa_lock;
>int magic;
>int fa_fd;
>struct fasync_struct *fa_next;
>struct file *fa_file;
>struct rcu_head fa_rcu;
>};一般将
fasync_struct
结构体指针变量定义到设备结构体中。1
2
3
4
5
6
7
8
9>struct imx6uirq_dev {
>struct device *dev;
>struct class *cls;
>struct cdev cdev;
......
struct fasync_struct *async_queue; /* 异步相关结构体 */
>};要实现
file_operations
里面的fasync
函数。要使用异步通知,需要在设备驱动中实现
file_operations
操作集中的fasync
函数,格式如下所示1
int (*fasync) (int fd, struct file *filp, int on);
fasync
函数里面一般通过调用fasync_helper
函数来初始化前面定义的fasync_struct
结构体指针,fasync_helper
函数原型如下:1
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp);
当应用程序通过
fcntl(fd, F_SETFL, flags | FASYNC)
改变fasync
标记的时候,驱动程序file_operations
操作集中的fasync
函数就会执行。向应用程序发送信号,
kill_fasync
函数当设备可以访问的时候,驱动程序需要向应用程序发出信号,相当于产生“中断”。
kill_fasync
函数负责发送指定的信号,kill_fasync
函数原型如下所示1
2
3
4
5
6>/**
>* @param fp 要操作的 fasync_struct。
>* @param sig 要发送的信号
>* @param band 可读时设置为 POLL_IN,可写时设置为 POLL_OUT。
>*/
>void kill_fasync(struct fasync_struct **fp, int sig, int band);关闭驱动时,需要删除信号。
关闭驱动文件的时候需要在
file_operations
操作集中的release
函数中释放fasync_struct
,fasync_struct
的释放函数同样为fasync_helper
。1
2
3
4static int xxx_release(struct inode *inode, struct file *filp)
{
return xxx_fasync(-1, filp, 0); /* 删除异步通知 */
}驱动中
fasync
函数参考示例
1 | struct xxx_dev { |
1.5 应用程序对异步通知的处理
注册信号处理函数
使用
signal()
函数来设置指定信号的处理函数。1
2>/* 设置信号处理函数 */
>signal(SIGIO, sigio_signal_func);将本应用程序的进程号告诉给内核
使用
fcntl(fd, F_SETOWN, getpid());
将本应用程序的进程号告诉给内核。开启异步通知
使用如下两行程序开启异步通知
1
2
3/* 开启异步通知 */
flags = fcntl(fd, F_GETFL); /* 获取当前的进程状态 */
fcntl(fd, F_SETFL, flags | FASYNC); /* 开启当前进程异步通知功能 */重点就是通过
fcntl
函数设置进程状态为FASYNC
,经过这一步,驱动程序中的fasync
函数就会执行。
二、实验驱动编写
2.1 驱动程序
1 |
|
2.2 测试APP程序
1 |
|
- 本文作者: 路痴的兔子
- 本文链接: https:/proudrabbit.gitee.io/IMX6ULL嵌入式Linux驱动学习笔记(十一).html
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!