异步通知基础:
信号:是一种类似中断的机制,当驱动程序可以访问的时候主动告诉应用程序
异步通知的核心就是信号,在arch/xtensa/include/uapi/asm/signal.h文件中,就有Linux所支持的所有信号,例如我们常用的kill -9、CTRL+C
#define SIGHUP 1 /* 终端挂起或控制进程终止 */
#define SIGINT 2 /* 终端中断(Ctrl+C 组合键) */
#define SIGQUIT 3 /* 终端退出(Ctrl+\组合键) */
#define SIGILL 4 /* 非法指令 */
#define SIGTRAP 5 /* debug 使用,有断点指令产生 */
#define SIGABRT 6 /* 由 abort(3)发出的退出指令 */
#define SIGIOT 6 /* IOT 指令 */
#define SIGBUS 7 /* 总线错误 */
#define SIGFPE 8 /* 浮点运算错误 */
#define SIGKILL 9 /* 杀死、终止进程 */
#define SIGUSR1 10 /* 用户自定义信号 1 */
#define SIGSEGV 11 /* 段违例(无效的内存段) */
#define SIGUSR2 12 /* 用户自定义信号 2 */
#define SIGPIPE 13 /* 向非读管道写入数据 */
#define SIGALRM 14 /* 闹钟 */
#define SIGTERM 15 /* 软件终止 */
#define SIGSTKFLT 16 /* 栈异常 */
#define SIGCHLD 17 /* 子进程结束 */
#define SIGCONT 18 /* 进程继续 */
#define SIGSTOP 19 /* 停止进程的执行,只是暂停 */
使用中断的时候需要设置中断处理函数,同样的,应用程序中使用信号,也要设置信号处理函数。
信号处理函数:sighandler_t signal(int signum, sighandler_t handler)
signum:要设置处理函数的信号
handler:信号的处理函数名称
成功的话,返回前一个函数,失败的话返回SIG_ERR
驱动中的信号处理
fasynv_struct结构体位于/include/linux/fs.h文件中,该结构体是使用异步通知必须的
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;
};
1.kill_fasync函数void kill_fasync(struct fasync_struct **fp, int sig, int band)
fp:要操作的 fasync_struct。
sig: 要发送的信号。
band: 可读时设置为 POLL_IN,可写时设置为 POLL_OUT。
返回值: 无。
应用程序中的信号处理
第一步:注册信号处理函数
第二步:将本应用程序的进程号告诉给内核
第三步:开启异步通知
-----------------------------------------驱动实验编写开始 ----------------------------------
1.添加需要用到的头文件
#include <linux/poll.h>
#include <linux/fcntl.h>
2.在设备结构体中添加fasynv_struct结构体
/* imx6uirq设备结构体 */
struct imx6uirq_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
struct device_node *nd; /* 设备节点 */
atomic_t keyvalue; /* 有效的按键键值 */
atomic_t releasekey; /* 标记是否完成一次完成的按键,包括按下和释放 */
struct timer_list timer;/* 定义一个定时器*/
struct irq_keydesc irqkeydesc[KEY_NUM]; /* 按键描述数组 */
unsigned char curkeynum; /* 当前的按键号 */
struct fasync_struct *fasync_queue;
};
3.在设备操作函数中添加fasync和release
/* 设备操作函数 */
static struct file_operations imx6uirq_fops = {
.owner = THIS_MODULE,
.open = imx6uirq_open,
.read = imx6uirq_read,
.fasync = imx6uirq_fasync,
.release = imx6uirq_release,
};
4,添加imx6uirq_fasync和imx6uirq_release函数,因为在上一步我们已经添加了这2个操作集函数。至此驱动函数方面的便添加完了。
static int imx6uirq_fasync(int fd, struct file *filp, int on)
{
struct imx6uirq_dev *dev = filp->private_data;
return fasync_helper(fd, filp, on, &dev->fasync_queue);
}
int imx6uirq_release(struct inode *inode, struct file *filp)
{
return imx6uirq_fasync(-1, filp, 0);
}
6.应用程序修改:添加sigio_signal_func函数
static void sigio_signal_func(int num)
{
int err;
unsigned int keyvalue =0;
err = read(fd, &keyvalue, sizeof(keyvalue)