异步通知读取输入事件

异步通知

简单来说就是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还需要做:

  1. App要打开驱动程序的设备节点,把自己的进程IO号告诉驱动程序
  2. 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;
}
上一篇:网页|JS实现3D旋转相册


下一篇:JavaScript 事件委托、事件代理详解