#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GLOBALFIFO_SIZE 0x1000
#define MEM_CLEAR 0x1
#define GLOBALFIFO_MAJOR 234
static int globalfifo_major=GLOBALFIFO_MAJOR;
struct globalfifo_dev
{
struct cdev cdev;
unsigned int current_len;
unsigned char mem[GLOBALFIFO_SIZE];
struct semaphore sem;
wait_queue_head_t r_wait;
wait_queue_head_t w_wait;
};
struct globalfifo_dev *globalfifo_devp;//设备结构体指针
static ssize_t globalfifo_read(struct file *filp,char __user
*buf,size_t count,loff_t *ppos)
{
int ret;
struct globalfifo_dev *dev=filp->private_data;
//获得设备结构体
DECLARE_WAITQUEUE(wait,current); //定义等待队列
down(&dev->sem); //获得信号量
add_wait_queue(&dev->r_wait,&wait);
//进入读等待队列头
if(dev->current_len == 0)
{
if(filp->f_flags &
O_NONBLOCK)
{
ret=-EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
up(&dev->sem);
schedule(); //调度其他进程执行
if(signal_pending(current))
//如果是因为信号唤醒
{
ret=-ERESTARTSYS;
goto out2;
}
down(&dev->sem);
}
if(count >
dev->current_len)
count=dev->current_len;
if(copy_to_user(buf,dev->mem,count))
{
ret=-EFAULT;
goto out;
}
else
{
memcpy(dev->mem,dev->mem+count,dev->current_len
- count);//fifo数据前移
dev->current_len-=count; //有效数据长度减少
printk(KERN_INFO "read %d
bytes(s),current_len:%d\n",count,dev->current_len);
wake_up_interruptible(&dev->w_wait);
//唤醒写等待列队
ret=count;
}
out:up(&dev->sem);
//释放信号量
out2:remove_wait_queue(&dev->w_wait,&wait);
//从附属的等待队列移除
set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t globalfifo_write(struct file *filp,const char
__user *buf,size_t count,loff_t *ppos)
{
struct globalfifo_dev
*dev=filp->private_data;//获得设备结构体指针
int ret;
DECLARE_WAITQUEUE(wait,current); //定义等待队列头
down(&dev->sem); //获得信号量
add_wait_queue(&dev->w_wait,&wait);
//进入写等待队列头
if(dev->current_len==GLOBALFIFO_SIZE)
{
if(filp->f_pos
&O_NONBLOCK)
//如果是非阻塞访问
{
ret=-EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);//改变进程状态为睡眠
up(&dev->sem);
schedule(); //调度其他进程执行
if(signal_pending(current))
//如果是因为信号唤醒
{
ret=-ERESTARTSYS;
goto out2;
}
down(&dev->sem);//释放信号量
}
if(count > GLOBALFIFO_SIZE -
dev->current_len)
count=GLOBALFIFO_SIZE -dev->current_len;
if(copy_from_user(dev->mem+dev->current_len,buf,count))
{
ret=-EFAULT;
goto out;
}
else
{
dev->current_len+=count;
printk(KERN_INFO "written %d
bytes(s),current_len:%d\n",count,dev->current_len);
wake_up_interruptible(&dev->r_wait);
//唤醒读等待队列
ret=count;
}
out:up(&dev->sem);
//释放信号量
out2:remove_wait_queue(&dev->w_wait,&wait);
//从附属的等待队列头移除
set_current_state(TASK_RUNNING);
return ret;
}
int globalfifo_open(struct inode *inode,struct file
*filp)
{
filp->private_data =
globalfifo_devp;//将设备结构体指针赋值给文件私有数据指针
return 0;
}
int globalfifo_release(struct inode *inode,struct file
*filp)
{
return 0;
}
static int globalfifo_ioctl(struct inode *inode,struct file
*filp,unsigned int cmd,unsigned long arg)
{
struct globalfifo_dev
*dev=filp->private_data;
switch(cmd)
{
case MEM_CLEAR:
if(down_interruptible(&dev->sem))
//获得信号量
{
return - ERESTARTSYS;
}
memset(dev->mem,0,GLOBALFIFO_SIZE);
up(&dev->sem); //释放信号量
printk(KERN_INFO "globalfifo is set to zero\n");
break;
default:
return - EINVAL;
}
return 0;
}
static const struct file_operations globalfifo_fops =
{
.owner = THIS_MODULE,
.read = globalfifo_read,
.write = globalfifo_write,
.release = globalfifo_release,
.open = globalfifo_open,
.ioctl = globalfifo_ioctl,
};
static void globalfifo_setup_cdev(struct globalfifo_dev
*dev,int index)
{
int err,devno=MKDEV(globalfifo_major,index);
cdev_init(&dev->cdev,&globalfifo_fops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&globalfifo_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d adding LED%d",err,index);
}
int globalfifo_init(void)
{
int ret;
dev_t devno=MKDEV(globalfifo_major,0);
if(globalfifo_major)
ret=register_chrdev_region(devno,1,"globalfifo");
else
{
ret=alloc_chrdev_region(&devno,0,1,"globalfifo");
globalfifo_major=MAJOR(devno);
}
if (ret<0)
return ret;
globalfifo_devp=kmalloc(sizeof(struct
globalfifo_dev),GFP_KERNEL);
if(!globalfifo_devp)
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(globalfifo_devp,0,sizeof(struct globalfifo_dev));
globalfifo_setup_cdev(globalfifo_devp,0);
init_MUTEX(&globalfifo_devp->sem);
init_waitqueue_head(&globalfifo_devp->r_wait);
init_waitqueue_head(&globalfifo_devp->w_wait);
return 0;
fail_malloc: unregister_chrdev_region(devno,1);
return ret;
}
void globalfifo_exit(void)
{
cdev_del(&globalfifo_devp->cdev);
kfree(globalfifo_devp);//释放结构体内存
unregister_chrdev_region(MKDEV(globalfifo_major,0),1);//释放设备号
}
MODULE_AUTHOR("Cynicholas");
MODULE_LICENSE("Dual BSD/GPL");
module_param(globalfifo_major,int,S_IRUGO);
module_init(globalfifo_init);
module_exit(globalfifo_exit);
//All rights reserved to Song Baohua.