Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6921
  • 博文数量: 3
  • 博客积分: 170
  • 博客等级: 入伍新兵
  • 技术积分: 40
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-21 15:06
文章分类
文章存档

2010年(3)

我的朋友
最近访客

分类: LINUX

2010-06-21 20:31:55

Scull源码简单分析

这几天把LDD3第三章看完了,今天把scull源码的主要部分通读了一遍,顺便写了一点注释,还希望大家帮忙指正。

程序中很多内容是后面章节讲解的,所以本文中只注释了第三章涉及的比较重要的地方。

 

//首先是初始化模块

int scull_init_module(void)

{

         int result, i;

         dev_t dev = 0;

/*

 * Get a range of minor numbers to work with, asking for a dynamic

 * major unless directed otherwise at load time.

 */

         if (scull_major) {

                   dev = MKDEV(scull_major, scull_minor);

                   result = register_chrdev_region(dev, scull_nr_devs, "scull");

         } else {

                   result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,

                                     "scull");                      //第一个次设备号是0,4个次设备,名称是scull

                   scull_major = MAJOR(dev);     //获取主设备号

         }

         if (result < 0) {

                   printk(KERN_WARNING "scull: can't get major %d\n", scull_major);

                   return result;

         }

        /*

          * allocate the devices -- we can't have them static, as the number

          * can be specified at load time

          */

         scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);  //分配设备指针

         if (!scull_devices) {

                   result = -ENOMEM;

                   goto fail;  /* Make this more graceful */

         }

         memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));

 

        /* Initialize each device. */

         for (i = 0; i < scull_nr_devs; i++) {

                   scull_devices[i].quantum = scull_quantum;    //设置每个设备的量子集中量子个数澹(4000)

                   scull_devices[i].qset = scull_qset;                     //设置每个设备的量子集的个数(1000)

                   init_MUTEX(&scull_devices[i].sem);

                   scull_setup_cdev(&scull_devices[i], i);             //struct cdev结构初始化并添加到系统中

         }

 

        /* At this point call the init function for any friend device */

         dev = MKDEV(scull_major, scull_minor + scull_nr_devs);

         dev += scull_p_init(dev);

         dev += scull_access_init(dev);

 

#ifdef SCULL_DEBUG /* only when debugging */

         scull_create_proc();

#endif

 

         return 0; /* succeed */

 

  fail:

         scull_cleanup_module();

         return result;

}

 

其中还涉及了cdev结构的初始化

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

{

         int err, devno = MKDEV(scull_major, scull_minor + index);     //将主次设备号转换为邋dev_t类型

    

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

}

 

//open函数

int scull_open(struct inode *inode, struct 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) {                  //如果是只写模式打开,则将设备长度裁剪为0

                   if (down_interruptible(&dev->sem))

                            return -ERESTARTSYS;

                   scull_trim(dev); /* ignore errors */

                   up(&dev->sem);

         }

         return 0;          /* success */

}

 

// scull_trim裁剪设备的长度

int scull_trim(struct scull_dev *dev)

{

         struct scull_qset *next, *dptr;

         int qset = dev->qset;   /* "dev" is not-null */

         int i;

 

         for (dptr = dev->data; dptr; dptr = next) { /* all the list items */    //从第一个量子集开始,遍历所有量子集

                   if (dptr->data) {

                            for (i = 0; i < qset; i++)      //遍历每个量子集中的每个量子

                                     kfree(dptr->data[i]);

                            kfree(dptr->data);

                            dptr->data = NULL;

                   }

                   next = dptr->next;

                   kfree(dptr);

         }

         dev->size = 0;

         dev->quantum = scull_quantum;

         dev->qset = scull_qset;

         dev->data = NULL;

         return 0;

}

 

//release函数

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

{

         return 0;

}

 

//读函数

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;   /* 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_pos >= dev->size)    //已到达文件末尾,返回0

                   goto out;

         if (*f_pos + count > dev->size)          //当前文件剩余的内容没有count

                   count = dev->size - *f_pos;

 

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

         item = (long)*f_pos / itemsize;                 //在第几个量子集

         rest = (long)*f_pos % itemsize;                 //在此量子集中占多少字节

         s_pos = rest / quantum;                            //当前所在量子集的第s_pos个量子

         q_pos = rest % quantum;                                     //当前所在量子集的第s_pos个量子的第邋q_pos个字节

 

         /* 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;

}

 

//写函数,和读函数很像。

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;

}

阅读(935) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~