觉得还是贴代码最直接,以后要用的时候也方便参考。
先是相应驱动的详细代码:
#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;
}