Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2705564
  • 博文数量: 505
  • 博客积分: 1552
  • 博客等级: 上尉
  • 技术积分: 2514
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-23 18:24
文章分类

全部博文(505)

文章存档

2019年(12)

2018年(15)

2017年(1)

2016年(17)

2015年(14)

2014年(93)

2013年(233)

2012年(108)

2011年(1)

2009年(11)

分类: LINUX

2013-11-12 22:02:12

觉得还是贴代码最直接,以后要用的时候也方便参考。
先是相应驱动的详细代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define FIFO_MAJOR 252          //主设备号
#define MAX_FIFO_BUF 16         //按键缓冲区的大小
        
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 fifodev *fifo_dev;     //键盘结构体
 
//返回读到的字节数
static ssize_t sep4020_fifo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
 int ret;
// 第二个参数condition必须满足,否则阻塞
 wait_event_interruptible(fifo_dev->r_wait, fifo_dev->current_len != 0);
 
 if(size > fifo_dev->current_len)
  size = fifo_dev->current_len;
 
 if(copy_to_user(buf, fifo_dev->buf, size))
 {
  ret = -EFAULT;
  goto out;
 }
 else
 {
  memcpy(fifo_dev->buf, fifo_dev->buf+size, fifo_dev->current_len-size);
  fifo_dev->current_len = fifo_dev->current_len - size;
  wake_up_interruptible(&fifo_dev->w_wait);
  ret = size;
 }
out:
 return ret;
}
 
//返回写入的字节数
static ssize_t sep4020_fifo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
 int ret;
 wait_event_interruptible(fifo_dev->w_wait, fifo_dev->current_len != MAX_FIFO_BUF);
 if(size > (MAX_FIFO_BUF-fifo_dev->current_len))
 {
  size = MAX_FIFO_BUF-fifo_dev->current_len;
 }
 if(copy_from_user(fifo_dev->buf+fifo_dev->current_len, buf, size))
 {
  ret = -EFAULT;
  goto out;
 }
 else
 {
  fifo_dev->current_len += size;
  ret = size;
  
 }
 
 wake_up_interruptible(&fifo_dev->r_wait);
out:
 return ret; 
}
 
 
//在使用echo或者cat的时候都会调用open函数
static int sep4020_fifo_open(struct inode *inode, struct file *filp)
{
 //memset(fifo_dev->buf, 0, MAX_FIFO_BUF);
 //fifo_dev->current_len = 0;
 return 0;
}
 
static int sep4020_fifo_release(struct inode *inode, struct file *filp)
{
 return 0;
}
 
 

static unsigned int sep4020_fifo_poll(struct file *filp, poll_table *wait)
{
 unsigned int mask = 0;
//加入这两句话是为了在读写状态发生变化的时候,通知核心层,让核心层重新调用poll函数查询信息。也就是说这两句只会在select阻塞的时候用到
//当利用select函数发现既不能读又不能写时,select函数会阻塞,但是此时的阻塞并不是轮询,而是睡眠,通过下面两个队列发生变化时通知select
 poll_wait(filp, &fifo_dev->r_wait, wait);
 poll_wait(filp, &fifo_dev->w_wait, wait);
 
 if(fifo_dev->current_len != 0)
 {
  mask |= POLLIN | POLLRDNORM;//可读,同时写上POLLRDNORM
 }

 if(fifo_dev->current_len != MAX_FIFO_BUF)
 {
  mask |= POLLOUT | POLLWRNORM;//可写,同时写上POLLWRNORM
 } 
 
 return mask;
}
 
 
static struct file_operations sep4020_fifo_fops = 
{
 .owner = THIS_MODULE,
 .read  = sep4020_fifo_read,
 .write = sep4020_fifo_write,
 .poll  = sep4020_fifo_poll,
 .open  = sep4020_fifo_open,
 .release = sep4020_fifo_release,
};
 
 
static int __init sep4020_fifo_init(void)
{
 int err,result;
 dev_t devno;

 devno = MKDEV(FIFO_MAJOR, 0);
 result = register_chrdev_region(devno, 1, "sep4020_fifo");   //向系统静态申请设备号
 if (result < 0)
 {
  return result;
 }
 
 fifo_dev = kmalloc(sizeof(struct fifodev), GFP_KERNEL);
 if (fifo_dev == NULL)
 {
  result = -ENOMEM;
  unregister_chrdev_region(devno, 1);
  return result;
 }
 memset(fifo_dev,0,sizeof(struct fifodev));  //初始化
 
 cdev_init(&fifo_dev->cdev, &sep4020_fifo_fops);
 fifo_dev->cdev.owner = THIS_MODULE;
 
//初始化等待对列
 init_waitqueue_head(&fifo_dev->r_wait);
 init_waitqueue_head(&fifo_dev->w_wait);
 
 //向系统注册该字符设备
 err = cdev_add(&fifo_dev->cdev, devno, 1);
 if (err)
 {
  printk("fifo adding err\r\n");
  unregister_chrdev_region(devno,1);
  kfree(fifo_dev);
  return err;
 } 
 return 0;
}
static void __exit sep4020_fifo_exit(void)
{
 cdev_del(&fifo_dev->cdev);
 kfree(fifo_dev);
 unregister_chrdev_region(MKDEV(FIFO_MAJOR, 0), 1);
}
module_init(sep4020_fifo_init);
module_exit(sep4020_fifo_exit);
MODULE_AUTHOR("Leeming Zhang");
MODULE_LICENSE("GPL");

 


接下来是相应的应用程序:
#include
#include
#include
#include
int main(int argc, char **argv)
{
 int fd;
 char buf[16];
 fd_set rfds,wfds; //读写描述符集合
 
 unsigned char w_buf[7] = {'a','b','c','d','e','f','g'};
 //open的标志位有:O_RDONLY O_WRONLY O_RDWR O_NONBLOCK O_NDELAY O_SYNC O_NOCTY
 fd = open("/dev/fifo",O_RDWR);
 if(fd == -1)
 {
   printf("wrong\r\n");
   exit(-1);
 }
 
 while(1)
 {
  //初始化文件描述符集合
  //清零
  FD_ZERO(&rfds);
  FD_ZERO(&wfds);
  //将文件描述符加入文件描述符集合中,利用函数FD_CLR(int fd,fd_set *set)将一个文件描述符从文件描述符集中清除
  FD_SET(fd, &rfds);
  FD_SET(fd, &wfds);
  //函数原型:int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  //readfds writefds exceptfds分别是被select监视的读,写和异常处理的文件描述符集合,numfds是需要检查的文件描述符加1。
  select(fd+1, &rfds, &wfds, NULL, NULL);
  
  //判断是否被置位,通过select函数调用驱动poll函数的返回值,来判断是否可读,还是可写,还是又能读又能写;当然如果驱动又不能读又不能写,在select那儿会阻塞,直到能读或者能写为止
  if(FD_ISSET(fd, &rfds))
  {
   printf("Poll monitor: can be read\n");
  }
  
  if(FD_ISSET(fd, &wfds))
  {
   printf("Poll monitor: can be written\n");
  }
 }
 return 0;
}
阅读(2460) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~