堵塞 / 非堵塞 IO
IO:是指對於內存的讀寫操作,很多時候讀跟寫存在互斥性不能同時進行,亦或者沒法多個線程實現同時讀寫
堵塞:對應線程獲取不到資源則被掛起,優勢讓出 CPU 資源
非堵塞:一直輪循等待
堵塞方式打開文件: fd = open("xx", O_RDWR);
非堵塞方式打開文件: fd = open("xx", O_RDWR | O_NONBLOCK);
堵塞IO
1. 等待隊列
1.1 等待隊列頭
在驅動中使用等待隊列,必須創建一個等待隊列頭,使用 wait_queue_head_t 表示 (include/linux/wait.h)
函數 | 描述 |
---|---|
void init_waitqueue_head(wait_queue_head_t *q); | 初始化等待隊列頭 |
DECLARE_WAIT_QUEUE_HEAD() | 一次性完成定義和初始化 |
1.2 等待隊列項
每個設備的進程都是一個隊列項,當設備不可用的時候需要將它們的等待隊列項加入到等待隊列裏
DECLARE_WAITQUEUE(name, tsk); 完成定義和初始化一個等待隊列項
1.3 添加/移除等待隊列頭
函數 | 描述 |
---|---|
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) | 等待隊列添加 |
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) | 等待隊列移除 |
void wake_up(wait_queue_head_t *q) | 喚醒進程 TASK_INTERRUPTIBLE 和 TASK_UNINTERRUPTIBLE |
void wake_up_interruptible(wait_queue_head_t *q) | 只能喚醒 TASK_INTERRUPTIBLE 進程 |
void wait_event(wq, condition) | 等待 wq 爲等待隊列頭的等待隊列被喚醒,前提滿足 condition 爲true,否則一直堵塞(狀態:TASK_UNINTERRUPTIBLE) |
int wait_event_timeout(wq, condition, timeout) | 可以添加超時時間,返回0:false && 超時; 返回1:true 條件滿足 |
void wait_event_interruptible(wq, condition) | 將狀態設置爲 TASK_INTERRUPTIBLE 可以被信號打斷狀態 |
int wait_event_interruptible_timeout(wq, condition, timeout) | 同上面類似 |
非堵塞 IO
2. 輪詢
程序可用通過 poll / epoll / select 來查詢設備是否可以操作
2.1 select(單個線程中默認能夠監視最多 1024 個,可以通過修改內核增大,但會降低效率)
函數 | 描述 |
---|---|
void FD_ZERO(fd_set* set) | 將所有 fd_set 變量所有位清零 |
void FD_SET(int fd, fd_set* set) | 將某個位置 1 |
void FD_CLR(int fd, fd_set* set) | 置0 |
int FD_ISSET(int fd, fd_set* set) | 可以判斷進行操作 |
EG
int ret, fd;
fd_set readfds;
struct timeval timeout;
fd = open("xxx", O_RDWR | O_NONBLOCK);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
//超時
timeout.tv_sec = 0;
timeout.tv_usec = 500000; //500ms
ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
switch(ret) {
case 0:
printf("timeout \n"); break;
case -1:
printf("error \n"); break;
default:
if (FD_ISSET(fd, &readfds)) {
//使用 read 讀數據
}
break;
}
2.2 poll 函數(與 select 效果相似,但是沒有最大文件描述符數量限制)
void poll_wait(struct file* filp, wait_queue_head_t* wait_address, poll_table* p); //將 應用程序加入到 poll_table 中
POLLIN 有數據可讀
POLLPRI 有緊急數據需要讀取
POLLOUT 可以寫數據
POLLERR 指定文件描述符發送錯誤
POLLHUP 制定文件描述符掛起
POLLNVAL 無效請求
POLLRDNORM 等同於 POLLIN
int ret, fd;
struct pollfd fds;
fd = open(filename, O_RDWR | O_NONBLOCK);
fds.fd = fd;
fds.events = POLLIN;
ret = poll(&fds, 1, 500);
if (ret) {
//讀取設備
} else if (ret == 0) {
//超時
} else if (ret < 0) {
//錯誤
}
2.3 epoll 爲處理大併發,網絡編程常用 epoll
int epoll_create(0); //創建一個 epoll 句柄
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout); //等待事件發生
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //向 epoll 加入監視文件描述符及監視事件
op: 操作設置
EPOLL_CTL_ADD 添加
EPOLL_CTL_MOD 修改
EPOLL_CTL_DEL 刪除
events:
EPOLLIN 有數據可讀
EPOLLOUT 寫數據
EPOLLPRI 有緊急數據需要讀取
EPOLLERR 指定文件描述符發生錯誤
EPOLLHUP 指定的文件描述符掛起
EPOLLET 設置 epoll 爲邊沿觸發,默認爲水平觸發
EPOLLONESHOT 一次性的監視
程序講解
堵塞 IO
DECLARE_WAITQUEUE(wait, current);
if (atomic_read(&dev->releasekey) == 0) {
add_wait_queue(&dev->r_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE); //設置任務狀態
schedule(); //進程調度,令進程進度進入休眠
if (signal_pending(current)) { //若由信號喚醒則報錯
ret = -ERESTARTSYS;
goto wait_error;
}
}
remove_wait_queue(&dev->r_wait, &wait); //移除隊列
wait_error:
set_current_state(TASK_RUNNING); //運行狀態
remove_wait_queue(&dev->r_wait, &wait);//從隊列去除
return ret;
非堵塞 IO
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;
}
}
//由應用程序調用 select 或 poll 時調用, 調用 poll_wait 將等待隊列加入到 poll_table 中
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;
}
堵塞IO 例程
//堵塞方式IO
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME "blockio"
#define KEY0VLAUE 0x01 //按鍵值
#define INVAKEY 0xFF //無效按鍵值
#define KEY_NUM 1
//中斷 IO 描述結構體
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;
//10ms 並激活定時器
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 (0 == value) {
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 (NULL == imx6uirq.nd) {
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 %d \n", 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
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
printk("key%d: gpio = %d, irqnum = %d \n", i, imx6uirq.irqkeydesc[i].gpio,
imx6uirq.irqkeydesc[i].irqnum);
}
//申請中斷
imx6uirq.irqkeydesc[0].handler = key0_handler;
imx6uirq.irqkeydesc[0].value = KEY0VLAUE;
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 (0 > ret) {
printk("irq %d request failed! \n", 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, releasekey = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data;
#if 0
ret = wait_event_interruptible(dev->r_wait, atomic_read(&dev->releasekey));
if (ret) {
goto wait_error;
}
#endif
DECLARE_WAITQUEUE(wait, current);
if (atomic_read(&dev->releasekey) == 0) {
add_wait_queue(&dev->r_wait, &wait);
__set_current_state(TASK_INTERRUPTIBLE); //設置任務狀態
schedule(); //進行一次進程調度,令進程進入休眠
if (signal_pending(current)) { //判斷是否因爲信號而被喚醒,是則報錯
ret = -ERESTARTSYS;
goto wait_error;
}
}
remove_wait_queue(&dev->r_wait, &wait);
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:
set_current_state(TASK_RUNNING); //運行狀態
remove_wait_queue(&dev->r_wait, &wait);//從隊列去除
return ret;
data_error:
return -EINVAL;
}
static struct file_operations imx6uirq_fops = {
.owner = THIS_MODULE,
.open = imx6uirq_open,
.read = imx6uirq_read,
};
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 int 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");
MODULE_AUTHOR("zzz");
//APP 堵塞讀 IO
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/ioctl.h>
int main(int argc, char* argv[])
{
int fd, ret = 0;
char* filename;
unsigned char data;
if (argc != 2) {
printf("Error Usage! \n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if (fd < 0) {
printf("file %s open failed ! \n", argv[1]);
return -1;
}
while(1) {
ret = read(fd, &data, sizeof (data));
if (0 > ret) {
//數據異常
} else {
if (data)
printf("key value = %#X \n", data);
}
}
ret = close(fd);
if (ret < 0) {
printf("file %s close failed !\n", argv[1]);
return -1;
}
return 0;
}
非堵塞IO 例程
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME "noblockio"
#define KEY0VLAUE 0x01 //按鍵值
#define INVAKEY 0xFF //無效按鍵值
#define KEY_NUM 1
//中斷 IO 描述結構體
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;
//10ms 並激活定時器
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 (0 == value) {
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 (NULL == imx6uirq.nd) {
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 %d \n", 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
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
printk("key%d: gpio = %d, irqnum = %d \n", i, imx6uirq.irqkeydesc[i].gpio,
imx6uirq.irqkeydesc[i].irqnum);
}
//申請中斷
imx6uirq.irqkeydesc[0].handler = key0_handler;
imx6uirq.irqkeydesc[0].value = KEY0VLAUE;
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 (0 > ret) {
printk("irq %d request failed! \n", 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, 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 int 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");
MODULE_AUTHOR("zzz");
//非堵塞IO 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 <linux/poll.h>
#include <linux/ioctl.h>
int main(int argc, char* argv[])
{
int fd, ret = 0;
char* filename;
struct pollfd fds;
fd_set readfds;
struct timeval timeout;
unsigned char data;
if (argc != 2) {
printf("Error Usage! \n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR | O_NONBLOCK);
if (fd < 0) {
printf("file %s open failed ! \n", argv[1]);
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 \n", 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 = %d \n", data);
}
}
break;
}
}
ret = close(fd);
if (ret < 0) {
printf("file %s close failed !\n", argv[1]);
return -1;
}
return 0;
}
編譯方式
KERNELDIR := /home/xza/workspace/01_linux_kernel/test/imx_4.1.15_2.0.0_ga_rc3/
CURRENT_PATH := $(shell pwd)
obj-m := blockio.o
build: kernel_modules
kernel_modules:
$(MAKE) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- EXTRA_CFLAGS=-fno-pic -C $(KERNELDIR) M=`pwd` modules
clean:
$(MAKE) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERNELDIR) M=`pwd` clean
驅動:make
APP: arm-linux-gnueabihf-gcc blockio_app.c -o blockio
測試: ./blockio /dev/imx6uirq & 查看 top 可以看到 CPU 佔用率很低