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.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面 ...
随机推荐
- Android通过百度地图API用Service和Alarm在后台定时获取地理位置信息
本文主要介绍了Android项目集成百度地图API,使用AlarmManager定时调用Service,在Service中请求坐标更新,并通过坐标得到省.市和县三级地理位置信息的方法. 程序结构很简单 ...
- java网络编程之socket(1)
网络编程是什么 网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机.数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后接受另外一个设备反馈的数据. ...
- [oracle] 递归追溯完整部门名称 函数
create or replace function fn_DeptWholeName2(objectid in number) return nvarchar2 is wholename nvarc ...
- 【技术累积】【点】【java】【5】Random和shuffle()
闲聊 妈耶,又这么久没写了..不过最近写其他文章有点多啊... 今天用到Random这个类,竟然还要去查了下... 基本概念 Random类,背后是伪随机数(数学上的东西): 不是很理解,但是基本上而 ...
- Juery实现选项卡
选项卡是一种很常用的组件.比如3个选项的选项卡,比较笨的一种办法是,把3个状态写成3个独立页面,互相链接.这样做的问题也显而易见,切换的时候url会变.如果是手机端网页,加载慢一点,给人的感觉是不断的 ...
- JS 蓝球弹起的高度 100 米 第几次高度小于1米
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- hibernate简单集合映射和获取
简单集合映射(可以直接获取) // javabean设计 public class User { private int userId; private String userName; // 一个用 ...
- 路飞学城Python-Day151
sprapy框架能够在pycharm中调试的方式 需要在配置文件中加上一个文件,文件的内容为 start.py #!/usr/bin/env python # -*- coding:utf-8 -*- ...
- 路飞学城Python-Day53
01-jquery的介绍 JS在做项目或者是实现功能的时候,用JS去操作DOM元素非常复杂,代码量大,重复性代码也多 多个元素使用for循环遍历也是非常麻烦的,对于JS使用来说加大了难度 jQuery ...
- Performance Co-Pilot
Install Performance Co-Pilot 提前安装依赖 [root@iZrj97j6t7ih9hgz1me35hZ ~]# cat install.sh yum install -y ...