文章目录
异步信号通知应用程序编程
异步信号通知: 当有数据到时候,驱动会发送信号(SIGIO)给应用,就可以异步去读写数据,不用主动去读写
a,应用–处理信号,主要是读写数据
void catch_signale(int signo)
{
if(signo == SIGIO)
{
printf(“we got sigal SIGIO”);
// 读取数据
read(fd, &event, sizeof(struct key_event));
if(event.code == KEY_ENTER)
{
if(event.value)
{
printf(“APP__ key enter pressed\n”);
}else
{
printf(“APP__ key enter up\n”);
}
}
}
}
// 1,设置信号处理方法
signal(SIGIO,catch_signale);
// 2,将当前进程设置成SIGIO的属主进程
fcntl(fd, F_SETOWN, getpid());
// 3,将io模式设置成异步模式
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC );
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>
struct key_event{
int code; // 表示按键的类型: home, esc, Q,W,E,R,T, ENTER
int value; // 表示按下还是抬起 1 / 0
};
#define KEY_ENTER 28
static int fd;
static struct key_event event;
void catch_signale(int signo)
{
if(signo == SIGIO)
{
printf("we got sigal SIGIO\n");
// 读取数据
read(fd, &event, sizeof(struct key_event));
if(event.code == KEY_ENTER)
{
if(event.value)
{
printf("APP__ key enter pressed\n");
}else
{
printf("APP__ key enter up\n");
}
}
}
}
int main(int argc, char *argv[])
{
int ret;
fd = open("/dev/key0", O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
// 1,设置信号处理方法
signal(SIGIO,catch_signale);
// 2,将当前进程设置成SIGIO的属主进程
fcntl(fd, F_SETOWN, getpid());
// 3,将io模式设置成异步模式
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC );
while(1)
{
// 可以做其他的事情
printf("I am waiting......\n");
sleep(1);
}
close(fd);
return 0;
}
异步信号的驱动编程实现
b,驱动–发送信号
1,需要和进程进行关联–记录信号该发送给谁
实现一个fasync的接口
int key_drv_fasync(int fd, struct file *filp, int on)
{
//只需要调用一个函数记录信号该发送给谁
return fasync_helper(fd, filp, on, &key_dev->faysnc);
}
2,在某个特定的时候去发送信号,在有数据的时候
//发送信号
kill_fasync(&key_dev->faysnc, SIGIO, POLLIN);
1.实现fasync接口
struct key_desc{
unsigned int dev_major;
struct class *cls;
struct device *dev;
int irqno;
void *reg_base;
struct key_event event;
wait_queue_head_t wq_head;
int key_state;
//定义fasync结构体
struct fasync_struct *faysnc;
};
//实现fasync接口
int key_drv_fasync(int fd, struct file *filp, int on)
{
//只需要调用一个函数记录信号该发送给谁
return fasync_helper(fd, filp, on, &key_dev->faysnc);
}
const struct file_operations key_fops = {
.open = key_drv_open,
.read = key_drv_read,
.write = key_drv_write,
.release = key_drv_close,
.poll = key_drv_poll,
//声明fasync接口
.fasync = key_drv_fasync,
};
2.在有数据的时候(中断中)发送信号
完整代码
key_async_app.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <signal.h>
struct key_event
{
int code;
int value;
};
struct key_event event;
#define KEY_ENTER 28
static int fd;
void catch_signal(int signo)
{
if (signo = SIGIO)
{
printf("we got signal SIGIO\n");
read(fd, &event, sizeof(struct key_event));
if (event.code == KEY_ENTER)
{
if (event.value)
{
printf("__APP__ key enter pressed\n");
}
else
{
printf("__APP__ key enter up\n");
}
}
}
}
int main(void)
{
int ret;
fd = open("/dev/key0", O_RDWR);
if (fd < 0)
{
perror("open");
exit(-1);
}
signal(SIGIO, catch_signal);
fcntl(fd, F_SETOWN, getpid());
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);
while (1)
{
printf("I am waiting...\n");
sleep(1);
}
close(fd);
return 0;
}
key_async_driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#define GPXCON_REG 0x11000C20
#define KEY_ENTER 28
//6.2.设计一个描述按键的数据的对象
struct key_event
{
int code;//表示按键的类型
int value;//表示按下还是抬起
};
//1.设定一个全局的设备对象
struct key_desc
{
unsigned int dev_major;
struct class *cls;
struct device *dev;
int irqno;
void *reg_base;
//按键
struct key_event event;
//7.1.定义等待队列头
wait_queue_head_t wq_head;
//7.3.表示是否有数据
int key_state;
//定义fasync结构体
struct fasync_struct *fasync;
};
struct key_desc *key_dev;
int get_irqno_from_node(void)
{
//4.1.1获取设备树中的节点
struct device_node *np = of_find_node_by_path("/key_int_node");
if (np)
{
printk("find node ok\n");
}
else
{
printk("find node failed\n");
}
//4.1.2通过节点获取中断号
int irqno = irq_of_parse_and_map(np, 0);
printk("irqno = %d\n", irqno);
return irqno;
}
//4.2.1.实现中断回调函数
irqreturn_t key_irq_handler(int irqno, void *devid)
{
printk("-------%s-------\n", __FUNCTION__);
//6.3.读取数据寄存器(获取硬件数据)
int value = readl(key_dev->reg_base + 4) & (1<<2);