kill_fasync()异步通知

  阻塞与非阻塞访问、poll函数提供了较好的解决设备访问的机制,但是如果有了异步通知,整套机制则更加完整了。

  异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上“中断”的概念,比较准确的称谓是“信号驱动的异步I/O”。信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
  阻塞I/O意味着一直等待设备可访问后再访问,非阻塞I/O中使用poll()意味着查询设备是否可访问,而异步通知则意味着设备通知用户自身可访问,之后用户再进行I/O处理。由此可见,这几种I/O方式可以相互补充。

使用kill_fasync()异步通知实现按键处理

1、应用层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
  
  
/* fifthdrvtest
  */
int fd;
  
//信号处理函数
void my_signal_fun(int signum)
{
    unsigned char key_val;
    read(fd, &key_val, 1);
    printf("key_val: 0x%x\n", key_val);
}
  
int main(int argc, char **argv)
{
    unsigned char key_val;
    int ret;
    int Oflags;
  
    //在应用程序中捕捉SIGIO信号(由驱动程序发送)
    signal(SIGIO, my_signal_fun);
     
    fd = open("/dev/buttons", O_RDWR);
    if (fd < 0)
    {
        printf("can't open!\n");
    }
  
    //将当前进程PID设置为fd文件所对应驱动程序将要发送SIGIO,SIGUSR信号进程PID
    fcntl(fd, F_SETOWN, getpid());
     
    //获取fd的打开方式
    Oflags = fcntl(fd, F_GETFL);
  
    //将fd的打开方式设置为FASYNC --- 即 支持异步通知
    //该行代码执行会触发 驱动程序中 file_operations->fasync 函数 ------fasync函数调用fasync_helper初始化一个fasync_struct结构体,该结构体描述了将要发送信号的进程PID (fasync_struct->fa_file->f_owner->pid)
    fcntl(fd, F_SETFL, Oflags | FASYNC);
  
  
    while (1)
    {
        sleep(1000);
    }
     
    return 0;
}

2、驱动层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>
  
  
static struct class *fifthdrv_class;
static struct class_device  *fifthdrv_class_dev;
  
//volatile unsigned long *gpfcon;
//volatile unsigned long *gpfdat;
  
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
  
/* 中断事件标志, 中断服务程序将它置1,fifth_drv_read将它清0 */
static volatile int ev_press = 0;
  
static struct fasync_struct *button_async;
  
  
struct pin_desc{
    unsigned int pin;
    unsigned int key_val;
};
  
  
/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
static unsigned char key_val;
  
/*
 * K1,K2,K3,K4对应GPG0,GPG3,GPG5,GPG6
 */
  
struct pin_desc pins_desc[4] = {
    {S3C2410_GPG0, 0x01},
    {S3C2410_GPG3, 0x02},
    {S3C2410_GPG5, 0x03},
    {S3C2410_GPG6, 0x04},
};
  
  
/*
  * 确定按键值
  */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    struct pin_desc * pindesc = (struct pin_desc *)dev_id;
    unsigned int pinval;
     
    pinval = s3c2410_gpio_getpin(pindesc->pin);
  
    if (pinval)
    {
        /* 松开 */
        key_val = 0x80 | pindesc->key_val;
    }
    else
    {
        /* 按下 */
        key_val = pindesc->key_val;
    }
  
    ev_press = 1;                  /* 表示中断发生了 */
    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     
        //发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用程序的SIGIO信号处理函数
    kill_fasync (&button_async, SIGIO, POLL_IN);
     
    return IRQ_RETVAL(IRQ_HANDLED);
}
  
static int fifth_drv_open(struct inode *inode, struct file *file)
{
    /* GPG0,GPG3,GPG5,GPG6为中断引脚: EINT8,EINT11,EINT13,EINT14 */
    request_irq(IRQ_EINT8,  buttons_irq, IRQT_BOTHEDGE, "K1", &pins_desc[0]);
    request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "K2", &pins_desc[1]);
    request_irq(IRQ_EINT13, buttons_irq, IRQT_BOTHEDGE, "K3", &pins_desc[2]);
    request_irq(IRQ_EINT14, buttons_irq, IRQT_BOTHEDGE, "K4", &pins_desc[3]);  
  
    return 0;
}
  
ssize_t fifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    if (size != 1)
        return -EINVAL;
  
    /* 如果没有按键动作, 休眠 */
    wait_event_interruptible(button_waitq, ev_press);
  
    /* 如果有按键动作, 返回键值 */
    copy_to_user(buf, &key_val, 1);
    ev_press = 0;
     
    return 1;
}
  
  
int fifth_drv_close(struct inode *inode, struct file *file)
{
    free_irq(IRQ_EINT8,  &pins_desc[0]);
    free_irq(IRQ_EINT11, &pins_desc[1]);
    free_irq(IRQ_EINT13, &pins_desc[2]);
    free_irq(IRQ_EINT14, &pins_desc[3]);
    return 0;
}
  
static unsigned fifth_drv_poll(struct file *file, poll_table *wait)
{
    unsigned int mask = 0;
    poll_wait(file, &button_waitq, wait); // 不会立即休眠
  
    if (ev_press)
        mask |= POLLIN | POLLRDNORM;
  
    return mask;
}
  
static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
    printk("driver: fifth_drv_fasync\n");
    //初始化/释放 fasync_struct 结构体 (fasync_struct->fa_file->f_owner->pid)
    return fasync_helper (fd, filp, on, &button_async);
}
  
  
static struct file_operations sencod_drv_fops = {
    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open    =  fifth_drv_open,    
    .read    =  fifth_drv_read,   
    .release =  fifth_drv_close,
    .poll    =  fifth_drv_poll,
    .fasync  =  fifth_drv_fasync,
};
  
  
int major;
static int fifth_drv_init(void)
{
    major = register_chrdev(0, "fifth_drv", &sencod_drv_fops);
  
    fifthdrv_class = class_create(THIS_MODULE, "fifth_drv");
  
    fifthdrv_class_dev = class_device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
  
//  gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
//  gpfdat = gpfcon + 1;
  
    return 0;
}
  
static void fifth_drv_exit(void)
{
    unregister_chrdev(major, "fifth_drv");
    class_device_unregister(fifthdrv_class_dev);
    class_destroy(fifthdrv_class);
//  iounmap(gpfcon);
    return 0;
}
  
  
module_init(fifth_drv_init);
  
module_exit(fifth_drv_exit);
  
MODULE_LICENSE("GPL");

  

  

posted @   轻轻的吻  阅读(1297)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2021-04-14 在samba共享文件夹建立软件链接,在window下的共享文件夹没有权限访问软链接
2021-04-14 编译OpenWrt虚拟机镜像文件
2020-04-14 串口下载连接
2018-04-14 修改Linux主机名与IP之间的映射关系
点击右上角即可分享
微信分享提示