Chinaunix首页 | 论坛 | 博客
  • 博客访问: 490860
  • 博文数量: 154
  • 博客积分: 746
  • 博客等级: 入伍新兵
  • 技术积分: 1129
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-20 09:20
个人简介

此生既入苦寒山,何妨再攀险峰!

文章分类

全部博文(154)

文章存档

2017年(1)

2016年(2)

2015年(25)

2014年(24)

2013年(8)

2012年(15)

2011年(79)

分类:

2011-08-24 11:39:39

对于字符型驱动中经常会碰到应用程序和底层硬件数据交换的问题,常用的做法有:
 
1.阻塞:
通过读写函数中内嵌阻塞代码(信号量,等待队列)来实现不满足条件时的睡眠,等到满足条件了应用程序从睡眠中唤醒,继续下面的操作。
关于信号量和等待队列可以参考以前的ppt和之前的文章。
 
2.非阻塞:
非阻塞就是应用程序即使得不到硬件数据也不会睡眠,而是直接返回。当然真实的操作不会就这样返回推出了,而是先通过轮询的方式,也就是上一篇文章的select,(虽然这里说是非阻塞,但是select本身就有点阻塞的味道,如果加入的文件描述符都不满足,select会休眠,一旦下层驱动有变化则会通知select再次调用poll函数,这其实是一种改良的轮询,非常好的一种机制),通过select来实现轮询的方式,只要select能通过则表明可以进行读或者写了。
 
3.异步IO
一旦实现异步IO,底层的一旦有数据变化,就会像产生一个中断一样通知上层应用.异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序就根本不需要查询设备状态(非常像中断吧!)
1.2之前都有提到怎么写,所以这里不多说了,谈一下怎么用异步io。
 
(1)首先在结构体中添加异步结构体指针:
struct fifodev
{   
 unsigned char buf[MAX_FIFO_BUF];   //按键缓冲区 
 unsigned int current_len;
 wait_queue_head_t r_wait;            //等待队列
 wait_queue_head_t w_wait;
 struct cdev cdev;
 ……
 struct fasync_struct *async_queue;
} ;
 
(2)驱动设备的fasync()函数
static int sep4020_fifo_fasync(int fd, struct file *flip, int mode)
{
 return fasync_helper(fd, flip, mode, &fifo_dev->async_queue);
}
 
(3)在相应的资源可以获得的地方添加释放sigio信号,比如在中断,读函数,写函数中,这里举例写函数中:
static ssize_t sep4020_fifo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
……
 wake_up_interruptible(&fifo_dev->r_wait);
 if(fifo_dev->async_queue)
   kill_fasync(&fifo_dev->async_queu,SIGIO, POLL_IN);//这里是写函数释放,当然是表示可以读了,同理在读中释放就要用poll_out了
out:
 return ret; 
}
 
(4)在文件关闭时,将文件从异步通知队列中删除。
static int sep4020_fifo_release(struct inode *inode, struct file *filp)
{
//调用之前写的fasync函数
 sep4020_fifo_fasync(-1,flip, 0);
 return 0;
}
 
/****************************************************************************/
下面是应用程序需要做的工作:
#include ……
 
void input_handler(int signum)
{
 相应的处理,比如说程序中异步读通知的话,这里就可以实现读的操作
} 
 
main()
{
 int fd, oflags;
 fd = open("dev/fifo, O_RDWR, S_IRUSR | S_IWUSR");
 if(fd == -1)
 {
   printf("wrong\r\n");
   exit(-1);
 }
 signal(SIGIO,input_handler);//让input_handler()处理SIGIO信号
 fcntl(fd, F_SETOWN, getpid());//第二个参数的定义是设置异步io所有权,所以这句话的意思是设置本进程为fd文件的所有者
oflags = fcntl(fd, F_GETFL);//获得文件状态标志
fcntl(fd, F_SETFL, oflags | FASYNC);//用户程序必须对访问的设备文件设置FASYNC标志。F_SETFL命令表示设置文件状态标志位.
 while(1)
 {
  sleep(100);
 }
}
 
以下是网上摘录的:

驱动程序的实现需要:

当用户程序操作时,从内核驱动的角度来看:

(1)    当用户程序调用F_SETOWN命令时(通过fnctl系统调用),所设置的值保存在了驱动程序中的filp->f_owner结构体。

(2)    当用户程序调用F_SETFL命令设置FASYNC标志时,驱动中的fasync方法相应的被调用。fasync方法的实现样例如下:

static int scull_p_fasync(int fd, struct file *filp, int mode)

{

        struct scull_pipe *dev = filp->private_data;

 

        return fasync_helper(fd, filp, mode, &dev->async_queue);//

}

(3)    当设备驱动准备好访问数据后,向所有注册异步通知的进程发送SIGIO信号。它的实现样例如下:

        if (dev->async_queue)

                kill_fasync(&dev->async_queue, SIGIO, POLL_IN);//POLL_IN指设备此时准备好供用户可读的数据;如果要对设备可写,这里应该用POLL_OUT

(4)    当设备文件被关闭时,应当将设备文件从内核维护的活动异步读列表中删掉。它的实现样例如下:

/* remove this filp from the asynchronously notified filp's */

scull_p_fasync(-1, filp, 0);

 

 

阅读(510) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~