首页 > 代码库 > Hasen的linux设备驱动开发学习之旅--支持轮询操作的设备驱动

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》中轮询部分。



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