本文转载自:http://7071976.blog.51cto.com/7061976/1392082

《[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作》涉及内核驱动函数二个,内核结构体零个,分析了内核驱动函数二个;可参考的相关应用程序模板或内核驱动模板二个,可参考的相关应用程序模板或内核驱动一个

一、概念:Poll是非阻塞IO----轮询操作
   非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞.

Tip:select()和poll(),epoll查询是否可对设备进行无阻塞的访问,这几个系统调用最终又会引发设备驱动中的poll()函数被执行

PS:看到这感觉晕了,暂且不理会
二、使用场景:
   它们常常用在必须使用多输入输出流的应用程序(如调用read,write字符设备驱动文件/dev/****)。因为这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写.
三、相关函数
1、内核函数
内核驱动函数一)a)poll()函数原型:

1
unsigned int (*poll) (struct file *filp, poll_table *wait);

  作用:调用poll_wait(),将可能引起设备文件状态变化的等待队列头添加到poll_table.
返回值:返回是否能对设备进行无阻塞读写访问的掩码

放回值mask常量及函数

常量    说明
           POLLIN    普通或优先级带数据可读
           POLLRDNORM    普通数据可读
           POLLRDBAND    优先级带数据可读
           POLLPRI    高优先级数据可读
           POLLOUT    普通数据可写
           POLLWRNORM    普通数据可写
           POLLWRBAND    优先级带数据可写
           POLLERR    发生错误
           POLLHUP    发生挂起
           POLLNVAL    描述字不是一个打开的文件

内核驱动函数二)b)poll_wait()函数原型:

1
void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);

作用:将可能引起设备文件状态变化的等待队列头添加到poll_table
2、应用程序poll函数

1
int poll(struct pollfd *fds, nfds_t nfds, int timeout)

a) 参数:
fds 指向 struct pollfd 数组
   nfds 指定 pollfd 数组元素的个数,也就是要监测几个 pollfd
   timeout 时间参数,单位ms,1000ms=1s
   Tip:fds可以是很多个文件(如网卡,按键),poll可以论寻fds[n]

   b)结构体pollfd
   struct pollfd {
       int fd;
       short events;
       short revents;
   };

3、总结:从应用程序的调用来看,并不需要理会内核函数中的参数poll_table *wait是什么,只需要调用poll_wait()

四、使用模板
模板一)a)内核程序模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static DECLARE_WAIT_QUEUE_HEAD(waitq);//定义结构体名称为waitq
poll(struct file *file, poll_table *wait){//返回mask
     unsigned int mask = 0;
    poll_wait(file, &waitq, wait);
     if(...)//可读
    
          mask |= POLLIN | POLLRDNORM;    //标识数据可获得
     
    if(...)//可写
    
          mask |= POLLOUT | POLLRDNORM;    //标识数据可写入
     
    return mask;
}

模板二)b)测试程序模板

1
2
3
4
struct pollfd fds[n];
fds[0].fd     = fd;
fds[0].events = POLLIN;
poll(fds, n, 5000);

c)再次理解下面几句
   fds 指向 struct pollfd 数组
   nfds 指定 pollfd 数组元素的个数,也就是要监测几个 pollfd
   timeout 时间参数,单位ms,1000ms=1s
   Tip:fds可以是很多个文件(如网卡,按键),poll可以论寻fds[n]

实例一)五、案例jz2440中断非阻塞驱动实例

1、 非阻塞内核按键驱动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//“irq_drv”,"irq_","irq"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//定义结构体名称为button_waitq
static struct class *irq_class;
static struct class_device    *irq_class_dev;
static int ev_press = 0;
static unsigned char key_val;
struct pin_desc{
    unsigned int pin;
    unsigned int key_val;
};
struct pin_desc pins_desc[3] = {
    {S3C2410_GPF0, 0x01},
    {S3C2410_GPF2, 0x02},
    {S3C2410_GPG3, 0x03},
};
static irqreturn_t irq_handle(int irq, void *dev__id){
    //printk("irq = %d\n", irq);
    int pinval;
    struct pin_desc *pindesc = (struct pin_desc *)dev__id;
    pinval = s3c2410_gpio_getpin(pindesc->pin);
    if(!pinval){//按下
    key_val = pindesc->key_val;
    }else{//松开
    key_val = 0x80 | pindesc->key_val;
    }
    ev_press = 1;
    wake_up_interruptible(&button_waitq);
    return IRQ_RETVAL(IRQ_HANDLED);//warn:返回IRQ_HANDLED
}
static unsigned irq_drv_poll(struct file *file, poll_table *wait)
{
    unsigned int mask = 0;
    poll_wait(file, &button_waitq, wait); // 不会立即休眠
    if (ev_press)
        mask |= POLLIN | POLLRDNORM;
    return mask;
}
static int irq_drv_open(struct inode *inode, struct file *file)
{
    printk("irq_dev read\n");
//    request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char * devname, void * dev_id); dev_id随意
    request_irq(IRQ_EINT0, irq_handle, IRQ_TYPE_EDGE_BOTH, "s2", &pins_desc[0]);
    request_irq(IRQ_EINT2, irq_handle, IRQ_TYPE_EDGE_BOTH, "s3", &pins_desc[1]);
    request_irq(IRQ_EINT11, irq_handle, IRQ_TYPE_EDGE_BOTH, "s4", &pins_desc[2]);
    return 0;
}
static ssize_t irq_drv_read (struct file *file, char __user *buf, size_t count, loff_t *ppos){
    if(count != 1)return -EINVAL;
    wait_event_interruptible(button_waitq, ev_press);//ev_press标志(if!(ev_press)),那么一直休眠
    copy_to_user(buf, &key_val, 1);//一个 char 0xff
    ev_press = 0;
    return 1;//warn :return the size of val
}
static ssize_t irq_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
    printk("irq_dev write\n");
    return 0;
}
static ssize_t irq_drv_release(struct inode *inode, struct file *file){
    free_irq(IRQ_EINT0, &pins_desc[0]);
    free_irq(IRQ_EINT2, &pins_desc[1]);
    free_irq(IRQ_EINT11, &pins_desc[2]);
    return 0;
}
static struct file_operations irq_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   irq_drv_open,
    .write =    irq_drv_write,
    .read = irq_drv_read,
    .release = irq_drv_release,
    .poll = irq_drv_poll,
};
int major;
static int irq_drv_init(void)
{
    major = register_chrdev(0, "irq_drv", &irq_drv_fops); // 注册, 告诉内核
    if (major < 0) {
      printk(" can't register major number\n");
      return major;
    }
    irq_class = class_create(THIS_MODULE, "irq_drv");
    if (IS_ERR(irq_class))
        return PTR_ERR(irq_class);
    irq_class_dev = class_device_create(irq_class, NULL, MKDEV(major, 0), NULL, "irq"); /* /dev/xyz */
    if (IS_ERR(irq_class_dev))
        return PTR_ERR(irq_class_dev);
    return 0;
}
static void irq_drv_exit(void)
{
    unregister_chrdev(major, "irq_drv"); // 卸载
    class_device_unregister(irq_class_dev);
    class_destroy(irq_class);
}
module_init(irq_drv_init);
module_exit(irq_drv_exit);
MODULE_LICENSE("GPL");

2、测试应用程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
/* irq
  */
int main(int argc, char **argv)
{
    int fd;
    unsigned char key_val;
    int cnt = 0;
    int ret;
    struct pollfd fds[1];
    fd = open("/dev/irq", O_RDWR);
    if (fd < 0)
    {
        printf("can't open!\n");
        exit(1);
    }
    fds[0].fd = fd;
    fds[0].events = POLLIN;
    while (1)
    {
        ret = poll(fds, 1, 5000);
        if(ret == 0){
        printf("time out!\n");
        }else{
        read(fd, &key_val, 1);
        printf("key_Vals = 0x%x\n", key_val);
            }
    }
    return 0;
}
Makefile
#myirq.bin
objs := $(patsubst %c, %o, $(shell ls *.c))
myarmgcc := /workspacearm/armlinuxgcc2626/bin/arm-linux-gcc
myirq.bin:$(objs)
    $(myarmgcc) -o $@ $^
    cp *.bin /opt/fsmini/
%.o:%.c
    $(myarmgcc) -c -o $@ $<
clean:
    rm -f  *.bin *.o

[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作【转】的更多相关文章

  1. arm驱动linux异步通知与异步IO【转】

    转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO> ...

  2. 嵌入式Linux内核开发工程师必须掌握的三十道题

    如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师. 1. Linux中主要有哪几种内核锁?(进程同步与互斥) (1)自旋锁:非睡眠锁 (2)信号量: ...

  3. 嵌入式系统Linux内核开发工程师必须掌握的三十道题(转)

    嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...

  4. linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

      IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...

  5. 🍛 餐厅吃饭版理解 IO 模型:阻塞 / 非阻塞 / IO 复用 / 信号驱动 / 异步

    IO 概念 一个基本的 IO,它会涉及到两个系统对象,一个是调用这个 IO 的进程对象,另一个就是系统内核 (kernel).当一个 read 操作发生时,它会经历两个阶段: 通过 read 系统调用 ...

  6. 编码风格——linux内核开发的coding style

    总结linux内核开发的coding style, 便于以后写代码时参考. 下面只是罗列一些规则, 具体说明可以参考: 内核源码(Documentation/CodingStyle) 01 - 缩进 ...

  7. 如何参与Linux内核开发(转)

    本文来源于linux内核代码的Document文件夹下的Hoto文件.Chinese translated version of Documentation/HOWTO If you have any ...

  8. 如何参与linux 内核开发

    如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者.   英文版维护者: Gre ...

  9. Linux内核开发进阶书籍推荐(不适合初学者)

    Linux内核开发进阶书籍推荐(不适合初学者) 很早之前就想写一篇文章总结一下Linux Kernel开发的相关资料,项目的原因,再加上家里的一些事情,一直没能找到闲暇,今天终于有些时间,希望可以完成 ...

随机推荐

  1. cf725F Family Photos

    Alice and Bonnie are sisters, but they don't like each other very much. So when some old family phot ...

  2. Bichrome Tree

    Bichrome Tree 时间限制: 1 Sec  内存限制: 128 MB 题目描述 We have a tree with N vertices. Vertex 1 is the root of ...

  3. [Hihocoder 1289] 403 Forbidden (微软2016校园招聘4月在线笔试)

    传送门 #1289 : 403 Forbidden 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi runs a web server. Someti ...

  4. Laravel5.1的控制器分组

    Laravel5.1的控制器分组 默认的控制器时直接在app\Http\Controllers下,创建分组名字,路由配置使用:分组名\控制器名@方法名.

  5. 2017-10-28-morning-清北模拟赛

    T1 立方数(cubic) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK定义了一个数叫“立方数”,若一个数可以被写作是一个正整数的3次方,则这个数就是 ...

  6. cef network-settings

    Network Settings 目录 1 System network settings 2 Preference service for network settings 3 Command-li ...

  7. Setup and Teardown Thread Group in Jmeter

    setup和teardown有点类似于每个测试用例开始和结束时要做的动作 A Thread Group is the starting point of any Jmeter Test Plan. A ...

  8. scss - 语法

    1.在一个样式导入另一个样式(@import "example.css") 2.scss单行注释不会显示出来 3.强大的变量(定义后,全局可使用) 4.全局默认变量(加!defau ...

  9. java解析xml的方式DOM,SAX,DOM4J,JDOM,StAX

    1)DOM(JAXP Crimson解析器)DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找 特定信息. ...

  10. c#中的多态 c#中的委托

    C#中的多态性          相信大家都对面向对象的三个特征封装.继承.多态很熟悉,每个人都能说上一两句,但是大多数都仅仅是知道这些是什么,不知道CLR内部是如何实现的,所以本篇文章主要说说多态性 ...