驱动层
struct fifo{
dev_t num;
struct cdev cdev;
wait_queue_head_t readqueue;
//queue property
char *qbuf;
int start; //pos
int end; //pos
int cursize;
int maxsize;
}FIFO;
static ssize_t fifo_read (struct file *f, char __user *p, size_t n, loff_t *off)
{
int size;
if(FIFO.cursize == 0)
//let this procss go to sleep
wait_event_interruptible(FIFO.readqueue, FIFO.cursize != 0);
size = n>FIFO.cursize?FIFO.cursize:n;
// return 0;
int len1, len2;
if(FIFO.start <= FIFO.end)// copy once
{
if(copy_to_user(p, FIFO.qbuf, size))
{
printk("copy to user fail1\n");
return -EINVAL;
}
}
else
{
len1 = FIFO.maxsize-FIFO.start;
if(copy_to_user(p, &FIFO.qbuf[FIFO.start], len1))
{
printk("copy to user fail2\n");
return -EINVAL;
}
len2 = size-len1;
if(copy_to_user(p+len1, FIFO.qbuf, len2))
{
printk("copy to user fail3\n");
return -EINVAL;
}
}
FIFO.start = (FIFO.start+size)%FIFO.maxsize;
FIFO.cursize -= size;
return size;
}
static ssize_t fifo_write (struct file *f, const char __user *p, size_t n, loff_t *off)
{
int space = FIFO.maxsize - FIFO.cursize;
int size = n>space?space:n;
int len1 = (FIFO.maxsize-1 - FIFO.end);
int len2;
if(!space)
return 0;
// copy_from_user(&FIFO.qbuf[end+1], p, size);
if(len1 >= size)//copy once
{
if(copy_from_user(&FIFO.qbuf[FIFO.end+1], p, size))
{
printk("copy from user fail1\n");
return -EINVAL;
}
}
else
{
if(copy_from_user(&FIFO.qbuf[FIFO.end+1], p, len1))
{
printk("copy from user fail2\n");
return -EINVAL;
}
len2 = size-len1;
if(copy_from_user(FIFO.qbuf, p+len1, len2))
{
printk("copy from user fail3\n");
return -EINVAL;
}
}
FIFO.end = (FIFO.end+size)%FIFO.maxsize;
FIFO.cursize += size;
//woke up processes
wake_up_interruptible(&FIFO.readqueue);
// wake_up(&FIFO.readqueue);
return size;
}
static long fifo_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
return 0;
}
static int fifo_release(struct inode *inodep, struct file *filep)
{
// printk("fifo closed\n");
return 0;
}
int fifo_mmap(struct file *f, struct vm_area_struct *vma)
{
return remap_pfn_range(vma, vma->vm_start, virt_to_phys(FIFO.qbuf)>>PAGE_SHIFT,
vma->vm_end-vma->vm_start,
vma->vm_page_prot);
}
unsigned int fifo_poll(struct file *filep, struct poll_table_struct *wait)
{
int mask = 0;
poll_wait(filep, &FIFO.readqueue, wait);
if(FIFO.cursize)
mask |= POLLIN | POLLRDNORM; /* readable */
return mask;
}
应用层:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
if(4 != argc)
{
printf("Usage: %s <file1> <file2> <file3>\n", argv[0]);
return -1;
}
char buf[100] = {0};
int fd1 = open(argv[1], O_RDWR);
int fd2 = open(argv[2], O_RDWR);
int fd3 = open(argv[3], O_RDWR);
fd_set myfds;
FD_ZERO(&myfds);
FD_SET(fd1, &myfds);
FD_SET(fd2, &myfds);
FD_SET(fd3, &myfds);
while(1)
{
fd_set tem = myfds;
select(fd3+1, &tem, NULL, NULL, NULL);
if(FD_ISSET(fd1, &tem))
{
read(fd1, buf, 100);
printf("read1: %s\n", buf);
}
if(FD_ISSET(fd2, &tem))
{
read(fd2, buf, 100);
printf("read2: %s\n", buf);
}
if(FD_ISSET(fd3, &tem))
{
read(fd3, buf, 100);
printf("read3: %s\n", buf);
}
}
}