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" ); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!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之间的映射关系