Hasen的linux设备驱动开发学习之旅--支持轮询操作的设备驱动

/**
 * Author:hasen
 * 参考 :《linux设备驱动开发详解》
 * 简介:android小菜鸟的linux
 * 	         设备驱动开发学习之旅
 * 主题:支持轮询操作的设备驱动
 * Date:2014-11-07
 */

在globalfifo的poll()函数中,首先将设备结构体中的r_wait和w_wait等待队列头添加到等待列表,

然后通过判断dev->current_len是否等于0来获取设备的可读状态,通过判断dev->current_len是否等于

GLOBALFIFO_SIZE来获得设备的可写状态。

struct globalfifo_dev{
	struct cdev cdev ;/*cdev结构体*/
	unsigned int current_len ;/*当前fifo的有效长度*/
	unsigned char mem[GLOBALFIFO_SIZE] ;/*全局内存*/
	struct semaphore sem ;/*并发控制用的信号量*/
	wait_queue_head_t r_wait ;/*@@读用的等待队列头*/
	wait_queue_head_t w_wait ;/*@@写用的等待队列头*/
}

/*globalfifo设备驱动的poll()函数*/
static unsigned int globalfifo_poll(struct file *filp,poll_table *wait)
{
	unsigned int mask = 0 ;
	struct globalfifo_dev *dev = filp->private_data ;/*获得设备结构体指针*/
	down(&dev->sem) ;

	poll_wait(filp,&dev->r_wait,wait) ;
	poll_wait(filp,&dev->w_wait,wait) ;
	/*@@fifo非空*/
	if(dev->current_len != 0)
		mask |= POLLIN | POLLRDNORM ; /*@@标示数据可获得*/
	/*@@fifo非满*/
	if(dev->current_len != GLOBALFIFO_SIZE)
		mask |= POLLOUT | POLLWRNORM ;/*@@标示数据可写入*/

	up(&dev->sem) ;
	return mask ;
}

注意,要把globalfifo_poll赋给global_fops的poll成员:

static const file_operations globalfifo_fops = {
		...
		.poll = globalfifo_poll,
		...
} ;

关于global_fops的poll成员参见文章《linux中file_operations结构体详解》,这里也粘贴过来方便查阅

unsigned int (*poll) (struct file *, struct poll_table_struct *);
    //poll 方法是 3 个系统调用的后端: poll, epoll, 和 select, 都用作查询对一个或多个文件描述符的读或写是否会阻塞. poll 方法应当返回一个位掩码指示是否非阻塞的读或写是可能的, 并且, 可能地, 提供给内核信息用来使调用进程睡眠直到 I/O 变为可能. 如果一个驱动的 poll 方法为 NULL, 设备假定为不阻塞地可读可写.

监控globalfifo是否可以非阻塞读写的应用程序

#include ...

#define FIFO_CLEAR 0X1
#define BUFFER_LEN 20
main()
{
	int fd,num ;
	char rd_ch[BUFFER_LEN];
	fd_set rfds , efds ;/*读和写文件描述符集*/

	/*以非阻塞方式打开/dev/globalfifo设备文件*/
	fd = open("/dev/globalfifo",O_RDONLY | O_NONBLOCK) ;
	if(fd != -1){
		/*FIFO清0*/
		if(ioctl(fd,FIFO_CLEAR,0) < 0)
			printf("ioctl command failed\n") ;

		while(1){
			FD_ZERO(&rfds) ;
			FD_ZERO(&wfds) ;
			FD_SET(fd,&rfds) ;
			FD_SET(fd,&wfds) ;

			select(fd+1 ,&rfds, &wfds, NULL, NULL) ;
			/*数据可获得*/
			if(FD_ISSET(fd,&rfds))
				printf("Poll monitor:can be read\n") ;
			/*数据可写入*/
			if(FD_ISSET(fd,&wfds))
				printf("Poll monitor:can be written\n") ;
		}
	}else{
		printf("open device failed !\n") ;
	}
}

运行时看到,到没有任何输入,即FIFO为空时,程序不断地输出"Poll monitor:can be written",当通过

echo向/dev/globalfifo写入一些数据后,将输出"Poll monitor:can be read"和"Poll monitor:can be written",如果

不断地通过echo向/dev/globalfifo写入数据直到写满FIFO,发现pollmonitor程序只输出"Poll monitor:can be read"。

对于globalfifo而言,不会出现既不能读,又不能写的情况。

代码中调用的函数详解,请参考文章《Hasen的linux设备驱动开发学习之旅--阻塞与非阻塞I/O》中轮询部分。

时间: 2024-11-14 11:29:47

Hasen的linux设备驱动开发学习之旅--支持轮询操作的设备驱动的相关文章

Hasen的linux设备驱动开发学习之旅--异步通知

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:异步通知 * Date:2014-11-05 */ 一.异步通知的概念和作用 阻塞和非阻塞访问.poll()函数提供了较好地解决设备访问的机制,但是如果有了异步通知整套机制就更 加完整了. 异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这 一点非常类似于硬件上"中断"的概

Hasen的linux设备驱动开发学习之旅--时钟

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:时钟 * Date:2014-11-15 */ 一.内核定时器 1.内核定时器编程 软件意义上的定时器最终依赖硬件定时器来是实现,内核在时钟中断发生后执行检测各定时器是否到期, 到期后的定时器处理函数将作为软中断在底半部执行.实质上,时钟中断处理程序会唤起TIMER_SOFTIRQ 软中断,运行当前处理器上到期的所有定时器. Linu

Hasen的linux设备驱动开发学习之旅--异步I/O

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:异步I/O * Date:2014-11-11 */ linux中最常用的输入/输出(I/O)模型是同步I/O.在这个模型中,请求发出后,应用就会阻塞,知道请求满足 为止.但是在某些情况下,I/O请求可能需要与其他的进程进行交叠.可移植操作系统接口(POSIX)异步I/O(AIO) 应用程序接口(API)就提供了这种功能. AIO基本

Hasen的linux设备驱动开发学习之旅--中断

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:中断 * Date:2014-11-13 */ 一.中断和定时器 所谓中断是指CPU在执行程序的过程中,出现了某些突发事件急待处理,CPU必须暂停执行当前的程序, 转而去处理突发事件,处理完毕后CPU又返回原程序被中断的位置并继续执行. 下图是中断的分类 嵌入式系统以及X86 PC中大多包含可编程中断控制器(PIC),许多MCU内部就

Hasen的linux设备驱动开发学习之旅--linux设备驱动中的并发与竞态

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:linux设备驱动中的并发与竞态 * Date:2014-11-04 */ 1.并发与竞态 并发(concurrency)指的是多个执行单元同时.并行被执行,而并发的执行单元对共享资源(软件上的全 局变量,静态变量等)的访问则很容易导致竞态(race conditions). 主要的竞态发生在以下几种情况: (1)对称多处理(SMP)

Hasen的linux设备驱动开发学习之旅--阻塞与非阻塞I/O

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:阻塞与非阻塞I/O * Date:2014-11-05 */ 阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作.被 挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足.而非阻塞操作的进程在不能 进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到条件满足以进行操作为止.

Linux设备驱动开发学习(1):前言

虽然网络上已经有很多Linux设备驱动开发学习的文章和博客,更是有很多经典的Linux设备驱动开 发的书籍,写这些博文似乎意义不大,但把自己的学习过程.学习心得记录下来,一方面有着强化巩固的 意义,另一方面也是把所学知识转化为自己所得的必要途径之一,这是我写这些的博客的原始动力.

Android深度探索(卷1)HAL与驱动开发学习笔记(4)

Android深度探索(卷1)HAL与驱动开发学习笔记(4) 第四章  源代码的下载与编译 一.源代码配置Android源代码下载环境 1.建一个用于存放下载脚本文件(repo)的目录 # mkdir ~/bin # PATH=~.bin:$PATH 2.下载repo脚本文件 # curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo #chmod a+x ~/bin/repo 3.创建用于存放Andro

Android深度探索(卷1)HAL与驱动开发学习笔记(6)

Android深度探索(卷1)HAL与驱动开发学习笔记(6) 第六章 第一个Linux驱动程序 统计单词个数   Linux系统将每一个驱动都映射成一个文件.这些文件称为设备文件或驱动文件,都保存在/dev目录中.这种设计理念使得与Linux驱动进行交互就像与普通文件进行交互一样容易.虽然C语言里没有事件的概念,但却有与事件类似的概念,这就是回调(c a l l b a c k)函数.因此,编写Lin u x驱动最重要的一步就是编写阴调函数,否则与设备文件交互的数据将无法得到处理. 6.1编写L