总览
本文使用 linux-2.6.22.6 内核, 使用jz2440开发板.
异步通知范例
范例源码
#include <stdio.h> #include <signal.h>
void get_signal(int signum) { static int cnt = 0; printf("signal=%d, %d times\n", signum, ++cnt); }
int main(int argc, char **argv) { printf("main start\n"); signal(SIGUSR1, get_signal); printf("wait signal\n"); while (1) { sleep(1000); } return 0; }
|
范例测试
$ arm-linux-gcc signal.c -o signal
$ ./signal & main start wait signal $ ps 790 0 1312 S ./signal $ kill -SIGUSR1 790 signal=10, 1 times $ kill -10 790 signal=10, 1 times
$ man kill $ kill -l 10) SIGUSR1
|
异步机制核心点
- 异步机制使得应用层代码可以获得有如”中断”处理一般的能力!
- 注册好signal和函数
- 主代码始终自己管自己运行
- signal触发后, 系统会自动调用注册好的函数.
- 异步通知的四个要点:
- 注册处理函数: 应用程序中注册
- 谁来发? 驱动来发
- 发给谁? 驱动发给应用程序
- 怎么发? 驱动调用
kill_fasyn()
驱动源码
驱动源码基于 驱动之基于中断设计按键驱动
增加fasync函数, 发送SIGIO信号.
然后应用层的测试文件改动较大.
drv_key_async.c
为了使设备支持异步通知机制, 驱动程序涉及以下3项工作:
- 应用程序调用
fcntl(fd, F_SETOWN, pid)
时. 能在这个控制命令处理中设置 filp->f_owner为对应进程ID. 此工作已由内核完成
- 应用程序调用
fcntl(fd, F_SETFL, oflags | FASYNC)
后, FASYNC标志改变, 会调用驱动的fasync函数. 驱动需要实现fasync.
- 在设备资源可获得时, 调用
kill_fasync()
函数触发信号.
#include"drv_key_async.h" #define DRV_KEY_INT_NODE_NAME "key_async"
static struct fasync_struct *keys_async;
static irqreturn_t keys_irq(int irq, void *dev_id) { ......
ev_press = 1; wake_up_interruptible(&key_waitq); kill_fasync(&keys_async, SIGIO, POLL_IN); return IRQ_RETVAL(IRQ_HANDLED); }
static int drv_key_fasync (int fd, struct file *filp, int on) { PINFO("drv_key_fasync\n"); return fasync_helper (fd, filp, on, &keys_async); }
static const struct file_operations drv_key_int_fops= { .owner = THIS_MODULE, .open = drv_key_int_open, .release = drv_key_int_release, .read = drv_key_int_read, .fasync = drv_key_fasync, };
|
drv_key_async.h
#define DRIVER_NAME "drv_key_async"
|
Makefile
测试文件 test_drv_key_async.c
为了使设备支持异步通知机制, 应用层程序涉及以下工作:
- 调用
fcntl(fd, F_SETOWN, getpid())
, 告诉内核, 发给谁
- 调用
fcntl(fd, F_SETFL, oflags | FASYNC)
, 改变fasync标记.
- 此时, 内核会调用驱动的fasync函数, 通过
fasync_helper
完成初始化.
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <unistd.h>
int fd;
void keys_signal_handler(int signum) { unsigned char key_val = 0; read(fd,&key_val,1); printf("key_val: 0x%x\n",key_val); }
int main(int argc, char **argv) { int ret; int oflags;
fd = open("/dev/key_async0", O_RDWR); if (fd < 0) { printf("can't open!\n"); return 0; }
signal(SIGIO, keys_signal_handler); fcntl(fd,F_SETOWN,getpid()); oflags = fcntl(fd,F_GETFL); printf("before fcntl\n"); fcntl(fd, F_SETFL, oflags | FASYNC); printf("after fcntl\n");
while(1) { sleep(1000); } return 0; }
|
编译并测试
Ubuntu主机端
$ make clean $ make modules
$ arm-linux-gcc test_drv_key_async.c -o test_drv_key_async
|
开发板端
$ insmod drv_key_async.ko drv_key_async:INIT
$ ./test_drv_key_async drv_key_async:In char driver open() function before fcntl drv_key_async:drv_key_fasync after fcntl
|