查询方式
调用open函数时,传入“O_NONBLOCK”参数;
调用read函数时,若驱动程序中有数据,则read函数返回数据;否则返回错误;
休眠-唤醒方式
调用open函数时,不要传入“O_NONBLOCK”参数;
调用read函数时,若驱动程序中有数据,则read函数返回数据;否则在内核态中休眠;
当出现数据时,驱动程序会将APP唤醒,read函数恢复执行并将数据返回;
#include <linux/input.h>
#include <sys/types.h> //open()头文件
#include <sys/stat.h> //open()头文件
#include <fcntl.h> //open()头文件
#include <sys/ioctl.h> //ioctl()头文件
#include <stdio.h> //print()头文件
#include <string.h> //strcmp()头文件
#include <unistd.h> //read()头文件
/* input:./01_get_input_info /dev/input/event0 nonblock*/
int main(int argc, char **argv)
{
int fd;
int err;
int len;
int i;
unsigned char byte;
int bit;
struct input_id id;
unsigned int evbit[2];
struct input_event event;
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 ",
};
if (argc < 2)
{
printf("Usage: %s <dev> [nonblock]\n", argv[0]); //< >代表必选项 [ ]代表可省略项
return -1;
}
if (argc == 3 && !(strcmp(argv[2], "nonblock")))
{
fd = open(argv[1], O_RDWR | O_NONBLOCK); //O_NONBLOCK 查询方式
}
else
{
fd = open(argv[1], O_RDWR); //休眠-唤醒方式
}
if (fd < 0) //无法打开
{
printf("open %s err\n", argv[1]);
return -1;
}
err = ioctl(fd, EVIOCGID, &id); //get id,需传入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); //get 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)) { //byte里的低bit位为1
printf("%s ", ev_names[i*8 + bit]);
}
}
}
printf("\n");
}
while(1)
{
len = read(fd, &event, sizeof(event));
if(len == sizeof(event))
{
print("get event: type = 0x%x, code = 0x%x, value = 0x%x\n", event.type, event.code, event.value)
}
else
{
print("read err %d\n", len);
}
}
return 0;
}
在lecture7的代码基础上进行修改,加入可选项“nonblock”
若输入中含“nonblock”,则以查询(非阻塞)方式读取驱动程序中的数据,返回数据或“read err”;
若输入中不含“nonblock”,则以休眠-唤醒(阻塞)方式读取驱动程序中的数据,返回数据或进入休眠等待数据;
POLL/SELECT方式
(POLL和SELECT的机制一致,但APP接口函数不同)
![]()
#include <linux/input.h>
#include <sys/types.h> //open()头文件
#include <sys/stat.h> //open()头文件
#include <fcntl.h> //open()头文件
#include <sys/ioctl.h> //ioctl()头文件
#include <stdio.h> //print()头文件
#include <string.h> //strcmp()头文件
#include <unistd.h> //read()头文件
#include <poll.h> //poll()头文件
/* input:./01_get_input_info /dev/input/event0 */
int main(int argc, char **argv)
{
int fd;
int err;
int len;
int ret;
int i;
unsigned char byte;
int bit;
struct input_id id;
unsigned int evbit[2];
struct input_event event;
struct pollfd fds[1];
nfds_t nfds = 1;
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 ",
};
if (argc != 2)
{
printf("Usage: %s <dev>[nonblock]\n", argv[0]);
return -1;
}
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if (fd < 0) //无法打开
{
printf("open %s err\n", argv[1]);
return -1;
}
err = ioctl(fd, EVIOCGID, &id); //get id,需传入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); //get 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)) { //byte里的低bit位为1
printf("%s ", ev_names[i*8 + bit]);
}
}
}
printf("\n");
}
while(1)
{
fds[0].fd = fd;
fds[0].event = POLLIN;
fds[0].revents = 0;
ret = poll(fds, nfds, 5000);
if(ret > 0)
{
if(fds[0].revents == POLLIN)
{
while(read(fd, &event, sizeof(event) == sizeof(event))
{
print("get event: type = 0x%x, code = 0x%x, value = 0x%x\n", event.type, event.code, event.value)
}
}
}
else if(ret == 0)
{
print("time out\n");
}
else
{
print("poll err \n");
}
}
return 0;
}
异步通知方式
流程:注册信号处理函数--打开驱动程序--把APP的进程号告诉驱动程序--使能"异步通知”
#include <linux/input.h>
#include <sys/types.h> //open()头文件
#include <sys/stat.h> //open()头文件
#include <fcntl.h> //open()头文件
#include <sys/ioctl.h> //ioctl()头文件
#include <stdio.h> //print()头文件
#include <string.h> //strcmp()头文件
#include <unistd.h> //read()头文件
#include <signal.h> //signal()头文件
#include <sys/types.h> //getpid()头文件
#include <unistd.h> //getpid()头文件 sleep()头文件
int fd;
void my_sig_handler(int sig)
{
struct input_event event;
while(read(fd, &event, sizeof(event)) == sizeof(event))
{
print("get event: type = 0x%x, code = 0x%x, value = 0x%x\n", event.type, event.code, event.value)
}
}
/* input:./05_input_read_faycn /dev/input/event0 */
int main(int argc, char **argv)
{
int err;
int len;
int ret;
int i;
unsigned char byte;
int bit;
struct input_id id;
unsigned int evbit[2];
unsigned int flags;
int count = 0;
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 ",
};
if (argc != 2)
{
printf("Usage: %s <dev>[nonblock]\n", argv[0]);
return -1;
}
/*注册信号处理函数*/
signal(SIGIO, my_sig_handler)
/*打开驱动程序*/
fd = open(argv[1], O_RDWR | O_NONBLOCK);
if (fd < 0) //无法打开
{
printf("open %s err\n", argv[1]);
return -1;
}
err = ioctl(fd, EVIOCGID, &id); //get id,需传入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); //get 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)) { //byte里的低bit位为1
printf("%s ", ev_names[i*8 + bit]);
}
}
}
printf("\n");
}
/*把APP的进程号告诉驱动程序*/
fcntl(fd, F_SETOWN, getpid());
/*使能"异步通知”*/
flags = fcntl(fd, F_GETFL)
fcntl(fd, F_SETFL, flags | FASYNC);
while(1)
{
print("main loop count = %d\n", count++);
sleep(2); //间隔2s
}
return 0;
}