scull字符驱动的读

1.scull.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define DEV_NAME "scull"

static struct file_operations scull_fops;
static dev_t dev;
static int scull_major = 0;
static int scull_minor;
static int scull_dvnum;

struct scull_dev {
        struct scull_qset *data;
        int quantum;
        int qset;
        unsigned long size;
        unsigned int access_key;
        struct semaphore sem;
        struct cdev cdev;
};

struct scull_qset {
        void **data;
        struct scull_qset *next;
};

struct scull_dev scull_dev;

static int scull_trim(struct scull_dev *dev)
{
        struct scull_qset *next, *dptr;
        int qset = dev->qset;
        int i;

        for(dptr=dev->data; dptr; dptr=next)
        {
                if(dptr->data)
                {
                        for(i=0; idata[i]);
                        kfree(dptr->data);
                        dptr->data = NULL;
                }

                next = dptr->next;

                kfree(dptr);
        }

        return 0;
}

static struct scull_qset *scull_follow(struct scull_dev *dev, int item)
{
        struct scull_qset *next, *dptr;
        int i;

        dptr=dev->data;

        for(i=0; inext;
                dptr = next;
        }

        return dptr;
}

int scull_open(struct inode *inode, struct file *filp)
{
        struct scull_dev *dev;

        dev = container_of(inode->i_cdev, struct scull_dev, cdev);
        filp->private_data = dev;

        if((filp->f_flags && O_ACCMODE) == O_WRONLY)
        {
                scull_trim(dev);
        }

        printk(KERN_NOTICE "opened the file[%p]\n", filp);

        return 0;
}

int scull_release(struct inode *inode, struct file *filp)
{
        printk(KERN_NOTICE "closed the file[%p]\n", filp);

        return 0;
}

//读scull字符设备
ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
        struct scull_dev *dev = filp->private_data;
        struct scull_qset *dptr;
        int quantum = dev->quantum;
        int qset = dev->qset;
        int itemsize = quantum * qset;
        int item, s_pos, q_pos, rest;
        ssize_t retval = 0;

        //if(down_interruptible(&dev->sem))
        //      return -ERESTARTSYS;

        if(*f_pos >= dev->size)
                goto out;

        if(*f_pos + count > dev->size)
                count = dev->size - *f_pos;

        item = (long)*f_pos / itemsize;
        rest = (long)*f_pos % itemsize;
        s_pos = rest / quantum;
        q_pos = rest % quantum;

        dptr = scull_follow(dev, item);

        if(dptr==NULL || !dptr->data || !dptr->data[s_pos])
        {
                goto out;
        }

        if(count > quantum - q_pos)
        {
                count = quantum - q_pos;
        }

        if(copy_to_user(buf, dptr->data[s_pos]+q_pos, count))
        {
                retval = -EFAULT;
                goto out;
        }

        *f_pos += count;
        retval = count;

out:
        //up(&dev->sem);

        printk(KERN_NOTICE "read the file[%p]\n", filp);

        return retval;
}

static void scull_setup_cdev(dev_t devno, struct scull_dev *dev, int index)
{
        //int devno;
        int err;

        //devno = MKDEV(scull_major, scull_minor);

        scull_fops.open = scull_open;
        scull_fops.release = scull_release;
        scull_fops.read = scull_read;
        cdev_init(&dev->cdev, &scull_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &scull_fops;

        err = cdev_add(&dev->cdev, devno, 1);

        if(err)
                printk(KERN_NOTICE "Error %d adding scull%d\n", err, index);
}

static int __init scull_init(void)
{
        int ret;

        printk("init module\n");

        if(scull_major)
        {
                dev = MKDEV(scull_major, scull_minor);
                ret = register_chrdev_region(dev, scull_dvnum, DEV_NAME);
        }
        else
        {
                scull_dvnum = 4;
                scull_minor = 0;
                ret = alloc_chrdev_region(&dev, scull_minor, scull_dvnum, DEV_NAME);
                scull_major = MAJOR(dev);
        }

        if(ret < 0)
        {
                printk("scull: can't get major %d\n", scull_major);
        }

        scull_setup_cdev(dev, &scull_dev, 0);

        return 0;
}

static void __exit scull_exit(void)
{
        cdev_del(&scull_dev.cdev);

        unregister_chrdev_region(dev, scull_dvnum);

        printk("exit module, major=[%d]\n", scull_major);
}

module_init(scull_init);
module_exit(scull_exit);

2.编译模块

$ make

3.安装模块

# insmod

4.创建设备

# ./scull_load

5.打开, 读和关闭设备

# cat /dev/scull0

6.查看打印日志

# tail -n 4 /var/log/messages
Nov  6 00:02:41 linux kernel: [ 5831.619786] init module
Nov  6 00:02:45 linux kernel: [ 5835.560676] opened the file[ffff8800452738c0]
Nov  6 00:02:45 linux kernel: [ 5835.560687] read the file[ffff8800452738c0]
Nov  6 00:02:45 linux kernel: [ 5835.560692] closed the file[ffff8800452738c0]

你可能感兴趣的:(scull字符驱动的读)