Template Information

Trang

Program of Pipe

Thứ Bảy, 4 tháng 6, 2011 / 20:40

#include<linux/init.h>
#include<linux/module.h>
#include<linux/types.h>
#include<linux/kdev_t.h>
#include<linux/fs.h>
#include<linux/slab.h>
#include<linux/cdev.h>
#include<asm/uaccess.h>
#include <linux/wait.h>
#include<linux/sched.h>
MODULE_LICENSE("Dual BSD/GPL");
int open1(struct inode *inode, struct file *filp);
int close1(struct inode *inode, struct file *filp);
ssize_t read1(struct file *filp,char __user *buf,size_t count,loff_t *f_pos);
size_t mini (size_t count,size_t siz);
static ssize_t write1(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos);
int major=0;
int minor=0;
int i;
struct file_operations scull_fops =
{
    .owner = THIS_MODULE,
    .open =  open1,
    .read =  read1,
    .write = write1,
    .release=close1,
};

struct scull_pipe
{
        wait_queue_head_t inq;
    wait_queue_head_t outq;
        char *buffer, *end;
        int buffersize;
    int maxsize;
        char *rp, *wp;
        struct cdev cdev;
};

struct scull_pipe dev[4];
static void scull_setup_cdev(struct scull_pipe *dev,int i)
{
     int err, devno = MKDEV(major, minor+i);
     dev->maxsize=5;
     cdev_init(&dev->cdev, &scull_fops);
     dev->cdev.owner = THIS_MODULE;
     dev->cdev.ops = &scull_fops;
     err = cdev_add (&dev->cdev, devno, 1);
    init_waitqueue_head(&(dev->inq));
    init_waitqueue_head(&(dev->outq));
    dev->buffer=kmalloc(dev->maxsize,GFP_KERNEL);
    if(dev->buffer==NULL)
    {
        printk(KERN_ALERT "error");
       
    }
    memset(dev->buffer,0,dev->maxsize);
    dev->rp=dev->buffer;
    dev->wp=dev->buffer;
    dev->end=dev->buffer+dev->maxsize-1;
     if (err)
     printk(KERN_NOTICE "Error %d adding scull", err);
}
static int hello(void)
{   
    int result,devno;
   
    if(major)
    {
    devno=MKDEV(major,minor);
    result=register_chrdev_region(major,1,"pipe");
    }
    else
    {
    result=alloc_chrdev_region(&devno,minor,1,"pipe");
    major=MAJOR(devno);
    }
    if(result<0)
    return -1;
    for(i=0;i<4;i++)
    scull_setup_cdev(&dev[i],i);
    return 0;
}


int open1(struct inode *inode, struct file *filp)
{
    struct scull_pipe *ptr;
    ptr=container_of(inode->i_cdev,struct scull_pipe, cdev);
    filp->private_data=ptr;
    return 0;
}
int close1(struct inode *inode, struct file *filp)
{
     return 0;
}
ssize_t read1(struct file *filp,char __user *buf,size_t count,loff_t *f_pos)
{
    int flag=0;
    struct scull_pipe *dev = filp->private_data;
    while (dev->rp==dev->wp)
    {
        if (wait_event_interruptible(dev->inq,(dev->rp!=dev->wp)))
            return -1;
    }
    if (dev->wp > dev->rp)
       count = mini(count,(size_t)(dev->wp-dev->rp));
    else
       count = mini(count,(size_t)(dev->end-dev->rp));
    if(dev->rp+count==dev->end)
    flag=1;
    if (copy_to_user(buf, dev->rp,(count+flag)))
    {
        return -1;
    }
    dev->rp += count;
    if (dev->rp==dev->end)
    {
        dev->rp = dev->buffer;
    if(dev->wp==dev->end)
        dev->wp=dev->buffer;
    }
    wake_up_interruptible(&dev->outq);
    return (count+flag);
}
static int spacefree(struct scull_pipe *dev)
{
    if (dev->rp == dev->wp)
        return dev->maxsize - 1;
    return ((dev->rp + dev->maxsize - dev->wp) % dev->maxsize) - 1;
}
static ssize_t write1(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
    int flag=0;
    struct scull_pipe *dev = filp->private_data;    
    while (spacefree(dev) == 0)
    {    
         if (wait_event_interruptible(dev->outq, (spacefree(dev)!= 0)))
         return -1;
    }
     count = mini(count, (size_t)spacefree(dev));
    if (dev->wp >= dev->rp)
       count = mini(count, (size_t)(dev->end - dev->wp));
    else
      count = mini(count, (size_t)(dev->rp - dev->wp - 1));
    if(dev->wp+count==dev->end)
    flag=1;
    if (copy_from_user(dev->wp, buf,(count+flag)))
    {     
      return -1;
    }
        dev->wp += count;
    wake_up_interruptible(&dev->inq);
    if (dev->wp == dev->end)
    if(dev->rp!=dev->buffer)
          dev->wp = dev->buffer; 
        return (count+flag);
}


size_t mini (size_t count,size_t siz)
{
    if(count>siz)
        return siz;
    else
        return count;
}

static void exit1(void)

{
    for(i=0;i<4;i++)
    cdev_del(&dev[i].cdev);
    unregister_chrdev(major,"pipe");
}
module_init(hello);
module_exit(exit1);

0 nhận xét:

Đăng nhận xét