异步通知
简单来说就是linux里的signal信号机制。
//include/uapi/asm-generic/signal.h
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29 //驱动常用信号,表示IO事件
#define SIGPOLL SIGIO
驱动程序通知App时,它会发出“SIGIO”信号,表示有“IO事件”要处理。
就App而言,你想处理SIGIO信息,那么需要提供信号处理函数,并且要跟SIGIO挂钩。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
除了注册SIGIO函数,App还需要做:
- App要打开驱动程序的设备节点,把自己的进程IO号告诉驱动程序
- App需要把“异步通知”的意愿告诉驱动,使能flag里的FASYNC位为1
应用编程
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int fd;
char *ev_names[] = {
"EV_SYN ",
"EV_KEY ",
"EV_REL ",
"EV_ABS ",
"EV_MSC ",
"EV_SW ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"NULL ",
"EV_LED ",
"EV_SND ",
"NULL ",
"EV_REP ",
"EV_FF ",
"EV_PWR ",
};
// 编写处理函数
void my_sig_handler(int sig)
{
struct input_event event;
while(read(fd, &event, sizeof(struct input_event)) == sizeof(struct input_event)) {
printf("get event: type=0x%x,code=0x%x,value=0x%x\n",
event.type, event.code, event.value);
}
}
int main(int argc, char *argv[])
{
int err, len, i, bit;
unsigned char byte;
struct input_id id;
struct input_event event;
unsigned int evbit[2];
int count = 0;
int flags = 0;
/* ./app /dev/input/event0 noblock */
if(argc < 2) {
printf("Usage: %s <dev> [noblock]\n", argv[0]);
return -1;
}
signal(SIGIO, my_sig_handler); //注册信号处理函数
if(argc == 3 && !strcmp(argv[2], "noblock")) {
fd = open(argv[1], O_RDWR|O_NONBLOCK);
printf("open block\n");
} else {
fd = open(argv[1], O_RDWR); //打开驱动
printf("open nonblock\n");
}
if(fd < 0) {
printf("open %s err\n", argv[1]);
return -1;
}
err = ioctl(fd, EVIOCGID, &id);
if(err == 0) {
printf("bustype = 0x%x\n", id.bustype);
printf("vendor = 0x%x\n", id.vendor);
printf("product = 0x%x\n", id.product);
printf("version = 0x%x\n", id.version);
}
len = ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
if(len > 0 && len <= sizeof(evbit)) {
printf("support ev type: ");
for(i=0;i<len;i++) {
byte = ((unsigned char *)evbit)[i];
for(bit=0;bit<8;bit++) {
if(byte & (1<<bit)) {
printf("%s ", ev_names[i*8+bit]);
}
}
}
printf("\n");
}
/* tell driver the app id */
fcntl(fd, F_SETOWN, getpid()); //把进程id号告诉驱动
flags = fcntl(fd, F_GETFL); //使能驱动的FASYNC功能
fcntl(fd, F_SETFL, flags|FASYNC);
while(1) {
printf("main loop count = %d\n", count++);
sleep(2);
}
return 0;
}