linux驱动之poll操作
POLL操作
1、POLL运行过程:
poll是一个系统调用,其内核入口函数为sys_poll,sys_poll差点儿不做不论什么处理直接调用do_sys_poll,do_sys_poll的运行过程能够分为三个部分:
1,将用户传入的pollfd数组复制到内核空间,由于拷贝操作和数组长度相关。时间上这是一个O(n)操作,这一步的代码在do_sys_poll中包含从函数開始到调用do_poll前的部分。
2,查询每一个文件描写叙述符相应设备的状态,假设该设备尚未就绪,则在该设备的等待队列中增加一项并继续查询下一设备的状态。
查询全然部设备后假设没有一个设备就绪,这时则须要挂起当前进程等待。直到设备就绪或者超时,挂起操作是通过调用schedule_timeout执行的。设备就绪后进程被通知继续执行,这时再次遍历全部设备,以查找就绪设备。这一步由于两次遍历全部设备。时间复杂度也是O(n),这里面不包含等待时间。相关代码在do_poll函数中。
3,将获得的数据传送到用户空间并运行释放内存和剥离等待队列等善后工作,向用户空间拷贝数据与剥离等待队列等操作的的时间复杂度相同是O(n),详细代码包含do_sys_poll函数中调用do_poll后到结束的部分。
2、代码编写
1、在file_operations结构体中加入 poll
- static struct file_operations button_sdv_fops =
- {
- .owner = THIS_MODULE,
- .open = button_dev_open,
- .read = button_dev_read,
- .release = button_dev_close,
- .poll = button_dev_poll,
- };
2、完毕 button_dev_poll函数
- static unsigned int button_dev_poll(struct file *file, poll_table * wait)
- {
- unsigned int mask =0;
- poll_wait(file, &button_wait_q, wait);//把当前进程挂到队列里面,不会立马休眠
- if(ev_press)
- mask |=POLLIN |POLLRDNORM;
- return mask;
- }
当中ev_press是上一篇博文中的中断事件发生标志,假设中断动作发生,则mask值将被告诉内核。当中 mask的值的含义:
常量
|
说明
|
POLLIN
|
普通或优先级带数据可读
|
POLLRDNORM
|
普通数据可读
|
POLLRDBAND
|
优先级带数据可读
|
POLLPRI
|
高优先级数据可读
|
POLLOUT
|
普通数据可写
|
POLLWRNORM
|
普通数据可写
|
POLLWRBAND
|
优先级带数据可写
|
POLLERR
|
错误发生
|
POLLHUP
|
发生挂起
|
POLLNVAL
|
描写叙述字不是一个打开的文件
|
3、測试程序编写
ret = poll(fds, 1, 3000);
poll函数原型:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
当中:pollfd结构体为:
- struct pollfd {
- int fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
- };
fd是要查询的设备。events是期望获得的事件,这里我们将他设置为:POLLIN
fds定义一个数组,存放须要poll的全部设备。poll操作会同一时候查询这些设备。
nfds为查询的文件数量
timeout为超时时间
驱动程序完整代码:
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <asm/io.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <linux/irq.h>
- #include <asm/uaccess.h>
- #include <asm/irq.h>
- #include <mach/regs-gpio.h>
- #include <mach/irqs.h>//这个在/opt/EmbedSky/linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach 路径
- #include <linux/interrupt.h>
- #include <linux/poll.h>
- MODULE_LICENSE("Dual BSD/GPL");
- static struct class *buttondrv_class;
- static struct class_devices *buttondrv_class_dev;
- /* */
- static DECLARE_WAIT_QUEUE_HEAD(button_wait_q);
- /*中断事件标志,中断服务程序将他置1,read函数将他置0*/
- static volatile int ev_press =0;
- volatile unsigned long *gpfcon = NULL;
- volatile unsigned long *gpfdat = NULL;
- static unsigned keyval;
- struct pin_desc{
- unsigned int pin;
- unsigned int key_value;
- };
- /*按键按下时是:0x01 0x02 0x03 0x04*/
- /*按键松开时是:0x81 0x82 0x83 0x84*/
- struct pin_desc pins_desc[4] =
- {
- {S3C2410_GPF1,0x01},
- {S3C2410_GPF4,0x02},
- {S3C2410_GPF2,0x03},
- {S3C2410_GPF0,0x04},
- };
- /*
- * 确定按键值
- */
- static irqreturn_t buttons_irq(int irq,void *dev_id)
- {
- struct pin_desc * pindesc = (struct pin_desc *) dev_id;
- unsigned int pinval;
- pinval = s3c2410_gpio_getpin(pindesc -> pin);
- if(pinval)//松开
- {
- keyval = 0x80|pindesc->key_value;
- }
- else
- {
- keyval = pindesc->key_value;
- }
- ev_press =1;//中断发生
- wake_up_interruptible(&button_wait_q);
- printk("button is pressed : %d \n",irq);
- return IRQ_HANDLED;
- }
- static int button_dev_open(struct inode *inode ,struct file* file)
- {
- //配置按键的引脚 GPF0,1,2,4为输入引脚
- request_irq(IRQ_EINT1,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key1",&pins_desc[0]);
- request_irq(IRQ_EINT4,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key2",&pins_desc[1]);
- request_irq(IRQ_EINT2,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key3",&pins_desc[2]);
- request_irq(IRQ_EINT0,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key4",&pins_desc[3]);
- return 0;
- }
- ssize_t button_dev_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
- {
- if(size !=1)
- {
- return -EINVAL;
- }
- /*假设没有按键动作发生 就休眠*/
- wait_event_interruptible(button_wait_q,ev_press);
- /*假设有按键动作发生,直接返回*/
- copy_to_user(buf,&keyval,1);
- ev_press = 0;
- return 0;
- }
- int button_dev_close(struct inode* inode ,struct file *file)
- {
- free_irq(IRQ_EINT1,&pins_desc[0]);
- free_irq(IRQ_EINT4,&pins_desc[1]);
- free_irq(IRQ_EINT2,&pins_desc[2]);
- free_irq(IRQ_EINT0,&pins_desc[3]);
- return 0;
- }
- static unsigned int button_dev_poll(struct file *file, poll_table * wait)
- {
- unsigned int mask =0;
- poll_wait(file, &button_wait_q, wait);//把当前进程挂到队列里面,不会立马休眠
- if(ev_press)
- mask |=POLLIN |POLLRDNORM;
- return mask;
- }
- static struct file_operations button_sdv_fops =
- {
- .owner = THIS_MODULE,
- .open = button_dev_open,
- .read = button_dev_read,
- .release = button_dev_close,
- .poll = button_dev_poll,
- };
- int major;
- static int button_dev_init(void)//入口函数
- {
- major = register_chrdev(0,"button_drv",&button_sdv_fops);
- buttondrv_class = class_create(THIS_MODULE,"button_drv");
- if(IS_ERR(buttondrv_class))
- return PTR_ERR(buttondrv_class);
- buttondrv_class_dev= device_create(buttondrv_class,NULL,MKDEV(major,0),NULL,"wq_button");
- if(unlikely(IS_ERR(buttondrv_class_dev)))
- return PTR_ERR(buttondrv_class_dev);
- /*映射物理地址*/
- gpfcon = (volatile unsigned long *) ioremap(0x56000050 ,16);
- gpfdat = gpfcon + 1;
- return 0;
- }
- static void button_dev_exit(void)
- {
- unregister_chrdev(major,"button_drv");
- device_unregister(buttondrv_class_dev);
- class_destroy(buttondrv_class);
- iounmap(gpfcon);
- }
- module_init(button_dev_init);
- module_exit(button_dev_exit);
測试程序完整代码:
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <poll.h>
- int main(int argc, char **argv)
- {
- int ret=0;
- int cnt=0;
- int fd;
- unsigned char key_val;
- struct pollfd fds[1];
- fd = open("/dev/wq_button", O_RDWR);
- if(fd<0)
- {
- printf("can't open \n");
- }
- fds[0].fd = fd;
- fds[0].events = POLLIN;
- while(1)
- {
- ret = poll(fds, 1, 3000);
- if(ret == 0)
- {
- printf("time out \n");
- }
- else
- {
- read(fd,&key_val,1);
- printf("key_val = 0x%x\n",key_val);
- }
- }
- return 0;
- }
linux驱动之poll操作的更多相关文章
- Linux驱动之poll机制的理解与简单使用
之前在Linux驱动之按键驱动编写(中断方式)中编写的驱动程序,如果没有按键按下.read函数是永远没有返回值的,现在想要做到即使没有按键按下,在一定时间之后也会有返回值.要做到这种功能,可以使用po ...
- (十二)Linux内核驱动之poll和select
使用非阻塞 I/O 的应用程序常常使用 poll, select, 每个允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞. 这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写. ...
- 嵌入式Linux驱动学习之路(十二)按键驱动-poll机制
实现的功能是在读取按键信息的时候,如果没有产生按键,则程序休眠在read函数中,利用poll机制,可以在没有退出的情况下让程序自动退出. 下面的程序就是在读取按键信息的时候,如果5000ms内没有按键 ...
- linux驱动编写之poll机制
一.概念 1.poll情景描述 以按键驱动为例进行说明,用阻塞的方式打开按键驱动文件/dev/buttons,应用程序使用read()函数来读取按键的键值.这样做的效果是:如果有按键按下了,调用该re ...
- Linux驱动学习步骤(转载)
1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ls ...
- 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...
- Linux驱动设计——字符设备驱动(一)
Linux字符设别驱动结构 cdev结构体 struct cdev { struct kobject kobj; struct module *owner; const struct file_ope ...
- Linux驱动开发学习的一些必要步骤
1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ...
- 【Linux驱动】字符设备驱动
一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面 ...
随机推荐
- Linux - 设置光盘,开机自动挂载。
设置光盘,开机自动挂载. 挂载, 在linux操作系统中, 挂载是指将一个设备(通常是存储设备)挂接到一个已存在的目录上. 我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的目录上, ...
- 深入解析Dropout——基本思想:以概率P舍弃部分神经元,其它神经元以概率q=1-p被保留,舍去的神经元的输出都被设置为零
深度学习网络大杀器之Dropout——深入解析Dropout 转自:https://yq.aliyun.com/articles/68901 摘要: 本文详细介绍了深度学习中dropout技巧的思想 ...
- [ZJOI 2010] 数字计数
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1833 [算法] 数位DP [代码] #include <algorithm&g ...
- 2017-3-11 leetcode 217 219 228
ji那天好像是周六.....吃完饭意识到貌似今天要有比赛(有题解当然要做啦),跑回寝室发现周日才开始233333 =========================================== ...
- Serializable-源码分析
package java.io; public interface Serializable { } 代码很简单,功能也很简单,对象通过这个接口来实现序列化和反序列的.下面来看看小例子. import ...
- 【BZOJ3218】【UOJ#77】a + b Problem
题目 题目在这里 思路&做法 明显的最小割(其实是之前做过一道类似的题) S向每一个格子连容量为\(b_i\)的边 每一个格子向T连容量为\(w_i\)的边 对于格子\(i\)向满足条件的格子 ...
- A - Vile Grasshoppers
Problem description The weather is fine today and hence it's high time to climb the nearby pine and ...
- 第六课: - GroupBy函数
第 6 课 让我们看一看 groupby 函数. In [1]: # Import libraries import pandas as pd import sys In [2]: print(' ...
- vue 脚手架 使用步骤
当我知道搭建脚手架得使用命令行的时候.我就崩溃了.所以写一篇记录以后留着自己用也方便大家. 首先要安装一个node 环境, 1.打开cmd 进到你要建项目的目录: E: ...
- SQL Server将数据导出到SQL脚本文件
http://www.studyofnet.com/news/list-8883.2-1-4.html 一.SQL Server 2008将数据导出到SQL脚本文件 1.打开SQL Server200 ...