Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1680886
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: LINUX

2010-08-18 11:49:24

觉得还是贴代码最直接,以后要用的时候也方便参考。
先是相应驱动的详细代码:
/* linux/drivers/char/sep4020_char/sep4020_fifo.c
 *
* Copyright (c) 2009 leeming
*
* sep4020 fifo driver.
*
* Changelog:
* 12-Aug-2009 leeming Initial version
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#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->r_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;
}
 
 
/*
#define POLLIN   0x0001  //有数据可以读入,read不会阻塞,注意:select的请情况下,即使到EOF也是ready的.
#define POLLPRI  0x0002 //紧急数据,比如TCP,或者packet模式的peseudo-terminal发现slave的状态有变化.
#define POLLOUT  0x0004 //写入不会阻塞.
#define POLLERR  0x0008 //输出出错
#define POLLHUP  0x0010 //Hang up (output only).
#define POLLNVAL  0x0020 //Invalid request: fd not open (output only).
The rest seem to be more-or-less nonstandard. Check them!
#define POLLRDNORM 0x0040 //POLLIN.
#define POLLRDBAND 0x0080 //高优先级的数据read for read (generally unused on Linux).
#define POLLWRNORM 0x0100 //Equivalent to POLLOUT.
#define POLLWRBAND 0x0200 //Priority data may be written.
#define POLLMSG  0x0400
#define POLLREMOVE 0x1000
*/

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;
}
阅读(1099) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~