非阻塞式IO可通过以下方式实现:
select 、poll 、 epoll
select:
在APP中
select的使用,需要按照以下四部进行
(1)fd_set readfds ; int fd; (2)FD_ZERO(&readfds);//清空所有fd_set的所有位,每个位对应一个描述符(也就是关心的事件) (3)FD_SET(fd, &readfds);//设置fd_set中的某一位 (4)select(fd + 1, &readfds, NULL, NULL, &timeout); //函数原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); //通过返回值,可判断是否有事件发生 (5)FD_ISSET(fd, &readfds);//查看具体哪个事件发生,如果实现要的某个事件,则进行下一步操作
在驱动中:
需加入下边语句
if (filp->f_flags & O_NONBLOCK) {
if(atomic_read(&dev->releasekey) == 0)
return -EAGAIN;
}
poll
驱动中有个结构体
struct file_operations {
int (*open) (struct inode *, struct file *);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);**
...
}
这个函数指针 (*poll) (struct file *, struct poll_table_struct *);需要自己去实现,然后在申请字符设备时使用。。
在APP中,poll需要做以下操作:
(1)struct pollfd fds;
struct pollfd {
int fd;
short events;
short revents;
};
(2)初始化fds的成员;
fds.fd = fd;//想要监视的描述符
fds.events = POLLIN;//事件类型
(3)poll(&fds, 1, 500);//函数原型如下
int poll(struct pollfd *fds, nfds_t nfds, int timeout);//三个参数分别为,pollfd结构体,描述符数量,超时时间
通过判断返回值(事件发生时,对应的描述符就会被返回),就可知道是否有对应事件发生
当对应事件发生时,驱动会自动调函数指针unsigned int (*poll) (struct file *, struct poll_table_struct *);
例程:
//驱动 #include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IMX6UIRQ_CNT 1 #define IMX6UIRQ_NAME "noblockio" #define KEY0VALUE 0x01 #define INVAKEY 0xFF #define KEY_NUM 1 struct irq_keydesc { int gpio; int irqnum; unsigned char value; char name[10]; irqreturn_t (*handler)(int, void *); }; struct imx6uirq_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; atomic_t keyvalue; atomic_t releasekey; struct timer_list timer; struct irq_keydesc irqkeydesc[KEY_NUM]; unsigned char curkeynum; wait_queue_head_t r_wait; }; struct imx6uirq_dev imx6uirq; static irqreturn_t key0_handler(int irq, void *dev_id) { struct imx6uirq_dev *dev = (struct imx6uirq_dev*)dev_id; dev->curkeynum = 0; dev->timer.data = (volatile long)dev_id; mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10)); return IRQ_RETVAL(IRQ_HANDLED); } void timer_function(unsigned long arg) { unsigned char value; unsigned char num; struct irq_keydesc *keydesc; struct imx6uirq_dev *dev = (struct imx6uirq_dev *)arg; num = dev->curkeynum; keydesc = &dev->irqkeydesc[num]; value = gpio_get_value(keydesc->gpio); if(value == 0){ atomic_set(&dev->keyvalue, keydesc->value); } else{ atomic_set(&dev->keyvalue, 0x80 | keydesc->value); atomic_set(&dev->releasekey, 1); } if(atomic_read(&dev->releasekey)) { wake_up_interruptible(&dev->r_wait); } } static int keyio_init(void) { unsigned char i = 0; char name[10]; int ret = 0; imx6uirq.nd = of_find_node_by_path("/key"); if (imx6uirq.nd== NULL){ printk("key node not find!rn"); return -EINVAL; } for (i = 0; i < KEY_NUM; i++) { imx6uirq.irqkeydesc[i].gpio = of_get_named_gpio(imx6uirq.nd ,"key-gpio", i); if (imx6uirq.irqkeydesc[i].gpio < 0) { printk("can't get key%drn", i); } } for (i = 0; i < KEY_NUM; i++) { memset(imx6uirq.irqkeydesc[i].name, 0, sizeof(name)); sprintf(imx6uirq.irqkeydesc[i].name, "KEY%d", i); gpio_request(imx6uirq.irqkeydesc[i].gpio, name); gpio_direction_input(imx6uirq.irqkeydesc[i].gpio); imx6uirq.irqkeydesc[i].irqnum = irq_of_parse_and_map(imx6uirq.nd, i); #if 0 imx6uirq.irqkeydesc[i].irqnum = gpio_to_irq(imx6uirq.irqkeydesc[i].gpio); #endif } imx6uirq.irqkeydesc[0].handler = key0_handler; imx6uirq.irqkeydesc[0].value = KEY0VALUE; for (i = 0; i < KEY_NUM; i++) { ret = request_irq(imx6uirq.irqkeydesc[i].irqnum, imx6uirq.irqkeydesc[i].handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, imx6uirq.irqkeydesc[i].name, &imx6uirq); if(ret < 0){ printk("irq %d request failed!rn", imx6uirq.irqkeydesc[i].irqnum); return -EFAULT; } } init_timer(&imx6uirq.timer); imx6uirq.timer.function = timer_function; init_waitqueue_head(&imx6uirq.r_wait); return 0; } static int imx6uirq_open(struct inode *inode, struct file *filp) { filp->private_data = &imx6uirq; return 0; } static ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { int ret = 0; unsigned char keyvalue = 0; unsigned char releasekey = 0; struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data; if (filp->f_flags & O_NONBLOCK) { if(atomic_read(&dev->releasekey) == 0) return -EAGAIN; } else { ret = wait_event_interruptible(dev->r_wait, atomic_read(&dev->releasekey)); if (ret) { goto wait_error; } } keyvalue = atomic_read(&dev->keyvalue); releasekey = atomic_read(&dev->releasekey); if (releasekey) { if (keyvalue & 0x80) { keyvalue &= ~0x80; ret = copy_to_user(buf, &keyvalue, sizeof(keyvalue)); } else { goto data_error; } atomic_set(&dev->releasekey, 0); } else { goto data_error; } return 0; wait_error: return ret; data_error: return -EINVAL; } unsigned int imx6uirq_poll(struct file *filp, struct poll_table_struct *wait) { unsigned int mask = 0; struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data; poll_wait(filp, &dev->r_wait, wait); if(atomic_read(&dev->releasekey)) { mask = POLLIN | POLLRDNORM; } return mask; } static struct file_operations imx6uirq_fops = { .owner = THIS_MODULE, .open = imx6uirq_open, .read = imx6uirq_read, .poll = imx6uirq_poll, }; static int __init imx6uirq_init(void) { if (imx6uirq.major) { imx6uirq.devid = MKDEV(imx6uirq.major, 0); register_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT, IMX6UIRQ_NAME); } else { alloc_chrdev_region(&imx6uirq.devid, 0, IMX6UIRQ_CNT, IMX6UIRQ_NAME); imx6uirq.major = MAJOR(imx6uirq.devid); imx6uirq.minor = MINOR(imx6uirq.devid); } cdev_init(&imx6uirq.cdev, &imx6uirq_fops); cdev_add(&imx6uirq.cdev, imx6uirq.devid, IMX6UIRQ_CNT); imx6uirq.class = class_create(THIS_MODULE, IMX6UIRQ_NAME); if (IS_ERR(imx6uirq.class)) { return PTR_ERR(imx6uirq.class); } imx6uirq.device = device_create(imx6uirq.class, NULL, imx6uirq.devid, NULL, IMX6UIRQ_NAME); if (IS_ERR(imx6uirq.device)) { return PTR_ERR(imx6uirq.device); } atomic_set(&imx6uirq.keyvalue, INVAKEY); atomic_set(&imx6uirq.releasekey, 0); keyio_init(); return 0; } static void __exit imx6uirq_exit(void) { unsigned i = 0; del_timer_sync(&imx6uirq.timer); for (i = 0; i < KEY_NUM; i++) { free_irq(imx6uirq.irqkeydesc[i].irqnum, &imx6uirq); } cdev_del(&imx6uirq.cdev); unregister_chrdev_region(imx6uirq.devid, IMX6UIRQ_CNT); device_destroy(imx6uirq.class, imx6uirq.devid); class_destroy(imx6uirq.class); } module_init(imx6uirq_init); module_exit(imx6uirq_exit); MODULE_LICENSE("GPL");
//APP
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "poll.h"
#include "sys/select.h"
#include "sys/time.h"
#include "linux/ioctl.h"
int main(int argc, char *argv[])
{
int fd;
int ret = 0;
char *filename;
struct pollfd fds;
fd_set readfds;
struct timeval timeout;
unsigned char data;
if (argc != 2) {
printf("Error Usage!rn");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR | O_NONBLOCK);
if (fd < 0) {
printf("Can't open file %srn", filename);
return -1;
}
#if 0
fds.fd = fd;
fds.events = POLLIN;
while (1) {
ret = poll(&fds, 1, 500);
if (ret) {
ret = read(fd, &data, sizeof(data));
if(ret < 0) {
} else {
if(data)
printf("key value = %d rn", data);
}
} else if (ret == 0) {
} else if (ret < 0) {
}
}
#endif
while (1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
switch (ret) {
case 0:
break;
case -1:
break;
default:
if(FD_ISSET(fd, &readfds)) {
ret = read(fd, &data, sizeof(data));
if (ret < 0) {
} else {
if (data)
printf("key value=%drn", data);
}
}
break;
}
}
close(fd);
return ret;
}



