我是靠谱客的博主 可耐外套,最近开发中收集的这篇文章主要介绍Linux Device Driver: char device ,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在内部,scull使用一个struct scull_dev类型的结构表示每个设备,定义如下:

struct scull_dev{

struct scull_qset *data;     /*Pointer to first quantum set*/

int quantum;                      /*the current quantum size*/

int qset;                             /*the current array size*/

unsigned long size;           /*amount of data stored here*/

unsigned int access_key;  /*used by sculluid and scullpriv*/

struct semaphore sem;     /*mutual exclusion semaphore*/

 

struct cdev cdev;               /*Char device structure*/

};

 

scull驱动的设备注册

struct cdev是内核内部的设备表示类型,在scull中对其进行初始化如下,

static void scull_setup_cdev(struct scull_dev *dev, int index)

{

int err, devno = MKDEV(scull_major, scull_minor+index);

 

cdev_init(&dev->cdev, &scull_fops);

dev->cdev.owner = THIS MODULE;

dev->cdev.ops = &scull_fops;

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

/*Fail gracefully if need be*/

if(err)

printk(KERN_NOTICE "Error %d adding scull%d", err, index);

}

注册一个字符设备的经典方法是使用:

int register_chrdev(unsigned int major, const char *name, struct file_operation *fops);

int unregister_chrdev(unsigned int major, const char *name);

 

 

open方法:

open方法提供给驱动来做任何的初始化来准备后续的操作,在大部分驱动中,open应当进行下面的工作

  • 检查设备特定的错误(例如设备没准备好,或者类似的硬件错误)
  • 如果它第一次打开,初始化设备
  • 如果需要,更新f_op指针
  • 分配并填充要放进filp->private_data的任何数据结构

open原型: int (*open)(struct inode *inode, struct file *filp);

int scull_open(struct inode *inode, strcut file *filp)

{

struct scull_dev *dev;                /*device information*/

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

filp->private_data = dev;           /*for other methods*/

 

/*now trim to 0 the length of the device if open was write-only*/

if( (filp->f_flags & O_ACCMODE) == O_WRONLY)

{

scull_trim(dev);        /*ignore errors*/

}

return 0;  /*success*/

}

 

 

release方法:

release方法是open方法的反面,在任何实现方式下,设备方法应当进行下面的任务,

  • 释放open分配在filp->private_data中的任何东西
  • 在最后的close关闭设备

int scull_release(struct inode *inode, struct file *filp)

{

return 0;

}

 

 

读和写:

ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp);

ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp);

filp,文件指针;count,请求传输的数据大小;buff,指向持有被写入数据的缓存或者放入新数据的缓存;offp,指向一个'long offset type'对象,指出用户正在存取的文件位置。

ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)

{
struct scull_dev *dev = filp->private_data;

struct scull_qset *dptr;  /*the first listitem*/

int quantum = dev->quantum, qset = dev->qset;

int itemsize = quantum *qset;  /*how many bytes in the listitem*/

int item, s_pos, q_pos, rest;

ssize_t retval = 0;

 

if(down_interruptible(&dev->sem))

    return -ERESTARTSYS;

if(*f_ops >= dev->size)

    goto out;

if(*f_ops + count > dev->size)

    count = dev->size - *f_pos;

 

/*find listitem, qset index, and offset in the quantum*/

item = (long)*f_ops / itemsize;

rest = (long)*f_ops % itemsize;

s_pos = rest/quantum;

q_pos = rest%quantum;

 

/*follow the list up to the right position (defined elsewhere)*/

dptr = scull_follow(dev,item);

if(dptr == NULL || !dptr->data||!dptr->data[s_pos])

    goto out; /*don't fill holes*/

 

/*read only up to the end of this quantum*/

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);

return retval;

}

 

 

 

write方法:

ssize_t scull_write(struct file *filp, const 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, qset = dev->qset;
        int itemsize = quantum * qset;
        int item, s_pos, q_pos, rest;
        ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
        if (down_interruptible(&dev->sem))
                return -ERESTARTSYS;

        /* find listitem, qset index and offset in the quantum */
        item = (long)*f_pos / itemsize;
        rest = (long)*f_pos % itemsize;
        s_pos = rest / quantum;
        q_pos = rest % quantum;
        /* follow the list up to the right position */
        dptr = scull_follow(dev, item);
        if (dptr == NULL)
                goto out;
        if (!dptr->data)
        {
                dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
                if (!dptr->data)
                        goto out;
                memset(dptr->data, 0, qset * sizeof(char *));
        }
        if (!dptr->data[s_pos])
        {
                dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
                if (!dptr->data[s_pos])

                        goto out;
        }
        /* write only up to the end of this quantum */
        if (count > quantum - q_pos)

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

        }
        *f_pos += count;
        retval = count;

        /* update the size */
        if (dev->size < *f_pos)
                dev->size = *f_pos;

out:
        up(&dev->sem);
        return retval;

}

 

 

矢量操作的原型是:

ssize_t (*readv) (struct file *filp, const struct iovec *iov, unsigned long count, loff_t *ppos);
ssize_t (*writev) (struct file *filp, const struct iovec *iov, unsigned long count, loff_t *ppos);

最后

以上就是可耐外套为你收集整理的Linux Device Driver: char device 的全部内容,希望文章能够帮你解决Linux Device Driver: char device 所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部