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.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面 ...
随机推荐
- hdoj--1864--最大保险额(背包)
最大报销额 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...
- php auto_load mvc 接口框架(原创)
autoload.php <?php function framework_autoload($className){ $className=str_replace('\\','/',$clas ...
- maven nexus memory optimization
#链接地址:https://help.sonatype.com/repomanager3/system-requirements#filehandles While starting Nexus I ...
- Dalvik虚拟机和JVM的对比
Dalvik虚拟机与Java虚拟机有着很多相似的特性,都支持GC,JIT,JNI等等.其主要区别在于文件格式以及指令集不同,下面对两者的特性进行比较与讨论. Difference1:文件格式 Dalv ...
- 09.javaweb简单标签编程
一.简单标签 1, 简介:由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单.便于编写和调用 ...
- 【Oracle】权限
1. 授予权限: GRANT privilege[, privilege...] TO user [, user| role, PUBLIC...]; ①DBA授予用户系统权限 GRANT creat ...
- C#自定义控件实现控件随窗口大小改变
1.新建用户控件,取名MyForm. 2.将默认的UserControl改成Form 3.在类中添加以下代码 private float X, Y; //获得控件的长度.宽度.位置.字体大小的数据 p ...
- Kinect安装与配置(openNI2)
原文链接:http://blog.csdn.net/chenxin_130/article/details/8580636 简介 最近OpenNI2的推出,小斤也要多给博客除除草了,并在闲暇之余做一些 ...
- AI:从游戏引擎--到AI
原文链接:http://blog.csdn.net/left_la/article/details/6358911#t9 这是我在Gameres上看到的一篇文章,文章很长,全文分为11个部分,看后感觉 ...
- (转)shiro权限框架详解05-shiro授权
http://blog.csdn.net/facekbook/article/details/54910606 本文介绍 授权流程 授权方式 授权测试 自定义授权realm 授权流程 开始构造Secu ...