[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作

简介:

《[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()函数原型:


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()函数原型:    

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

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

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)内核程序模板

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)测试程序模板

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、 非阻塞内核按键驱动。

//“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、测试应用程序

#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

本文转自lilin9105 51CTO博客,原文链接:http://blog.51cto.com/7071976/1392082,如需转载请自行联系原作者

相关文章
|
3天前
|
Linux
Linux(1)arm64根目录扩容
Linux(1)arm64根目录扩容
8 0
|
18天前
|
存储 安全 数据管理
探索Linux的挂载操作🌈
在Linux这个强大的操作系统中,挂载操作是一个基本而重要的概念。它涉及到文件系统、设备和数据访问,对于理解Linux的工作方式至关重要。那么,挂载操作究竟是什么,为什么我们需要它,如果没有它,我们将面临什么问题呢?让我们一起深入探讨。
探索Linux的挂载操作🌈
|
28天前
|
Linux Windows
Linux之基本指令操作
Linux之基本指令操作
|
1月前
|
传感器 数据采集 存储
ARM Linux摄像头传感器数据处理全景视野:从板端编码视频到高级应用(一)
ARM Linux摄像头传感器数据处理全景视野:从板端编码视频到高级应用
75 0
|
1月前
|
Linux C语言
Linux系统下C语言的队列操作
Linux系统下C语言的队列操作
23 0
|
1月前
|
存储 算法 Shell
【Shell 命令集合 磁盘维护 】Linux 对软盘进行格式化操作 fdformat命令使用指南
【Shell 命令集合 磁盘维护 】Linux 对软盘进行格式化操作 fdformat命令使用指南
32 0
|
1月前
|
Shell Linux C语言
【Shell 命令集合 磁盘管理 】Linux 控制光驱或可移动媒体设备的弹出和关闭操作 eject命令使用教程
【Shell 命令集合 磁盘管理 】Linux 控制光驱或可移动媒体设备的弹出和关闭操作 eject命令使用教程
36 1
|
1月前
|
传感器 Linux 数据处理
ARM Linux摄像头传感器数据处理全景视野:从板端编码视频到高级应用(二)
ARM Linux摄像头传感器数据处理全景视野:从板端编码视频到高级应用
46 1
|
1月前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
67 0
|
1天前
|
Ubuntu Linux
Linux(Ubuntu)系统临时IP以及静态IP配置(关闭、启动网卡等操作)
请注意,以上步骤是在临时基础上进行配置的。如果要永久保存静态IP地址,通常还需要修改 `/etc/network/interfaces`文件,以便在系统重启后保持配置。同时,确保备份相关配置文件以防止出现问题。
6 1