zoukankan      html  css  js  c++  java
  • Linux驱动开发之LDD3中第三章scull注释详解【转】

      1 #include <linux/module.h>   
      2 #include <linux/moduleparam.h>   
      3 #include <linux/init.h>   
      4 #include <linux/kernel.h> /* printk() */   
      5 #include <linux/slab.h>       /* kmalloc() */   
      6 #include <linux/fs.h>     /* everything... */   
      7 #include <linux/errno.h>  /* error codes */   
      8 #include <linux/types.h>  /* size_t */   
      9 #include <linux/fcntl.h>  /* O_ACCMODE */   
     10 #include <linux/cdev.h>   
     11 #include <asm/system.h>       /* cli(), *_flags */   
     12 #include <asm/uaccess.h>  /* copy_*_user */   
     13 #include "scull.h"      /* local definitions */    
     14 /*   
     15  * Our parameters which can be set at load time.   
     16  */   
     17 //主设备号    
     18 int scull_major =   SCULL_MAJOR;    
     19 //次设备号    
     20 int scull_minor =   0;    
     21 //请求连续设备编号数量    
     22 int scull_nr_devs = SCULL_NR_DEVS;  /* number of bare scull devices */   
     23 //量子大小    
     24 int scull_quantum = SCULL_QUANTUM;    
     25 //量子集大小    
     26 int scull_qset =    SCULL_QSET;    
     27 module_param(scull_major, int, S_IRUGO);    
     28 module_param(scull_minor, int, S_IRUGO);    
     29 module_param(scull_nr_devs, int, S_IRUGO);    
     30 module_param(scull_quantum, int, S_IRUGO);    
     31 module_param(scull_qset, int, S_IRUGO);    
     32 struct scull_dev *scull_devices;    /* allocated in scull_init_module */   
     33 /*   
     34  * Empty out the scull device; must be called with the device   
     35  * semaphore held.   
     36  */   
     37 /*   
     38  * 释放整个数据区,简单遍历列表并且释放它发现的任何量子和量子集。   
     39  * 在scull_open在文件为写而打开时调用。   
     40  * 调用这个函数时必须持有信号量。   
     41  */   
     42 int scull_trim(struct scull_dev *dev)    
     43 {    
     44     struct scull_qset *next, *dptr;    
     45     //量子集大小    
     46     int qset = dev->qset;   /* "dev" is not-null */   
     47     int i;    
     48     for (dptr = dev->data; dptr; dptr = next) { /* all the list items */   
     49         if (dptr->data) {//量子集中有数据    
     50             //遍历释放当前量子集中的每个量子,量子集大小为qset    
     51             for (i = 0; i < qset; i++)    
     52                 kfree(dptr->data[i]);    
     53             //释放量子数组指针    
     54             kfree(dptr->data);    
     55             dptr->data = NULL;    
     56         }    
     57         //next获取下一个量子集,释放当前量子集    
     58         next = dptr->next;    
     59         kfree(dptr);    
     60     }    
     61     //清理struct scull_dev dev中的变量的值    
     62     dev->size = 0;    
     63     dev->quantum = scull_quantum;    
     64     dev->qset = scull_qset;    
     65     dev->data = NULL;    
     66     return 0;    
     67 }    
     68 /*   
     69  * Open and close   
     70  */   
     71 int scull_open(struct inode *inode, struct file *filp)    
     72 {    
     73     struct scull_dev *dev; /* device information */   
     74     dev = container_of(inode->i_cdev, struct scull_dev, cdev);    
     75     filp->private_data = dev; /* for other methods */   
     76     /* now trim to 0 the length of the device if open was write-only */   
     77     //文件以只读模式打开时,截断为0    
     78         if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {    
     79         if (down_interruptible(&dev->sem))    
     80             return -ERESTARTSYS;    
     81         scull_trim(dev); /* ignore errors */   
     82         up(&dev->sem);    
     83     }    
     84     return 0;          /* success */   
     85 }    
     86 int scull_release(struct inode *inode, struct file *filp)    
     87 {    
     88     return 0;    
     89 }    
     90 /*   
     91  * Follow the list   
     92  */   
     93 //返回设备dev的第n个量子集的指针,量子集不够n个就申请新的    
     94 struct scull_qset *scull_follow(struct scull_dev *dev, int n)    
     95 {    
     96     //第一个量子集指针    
     97     struct scull_qset *qs = dev->data;    
     98     /* Allocate first qset explicitly if need be */   
     99     // 如果当前设备还没有量子集,就显示分配第一个量子集    
    100     if (! qs) {    
    101         qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);    
    102         if (qs == NULL)    
    103             return NULL;  /* Never mind */   
    104         memset(qs, 0, sizeof(struct scull_qset));    
    105     }    
    106     /* Then follow the list */   
    107     // 遍历当前设备的量子集链表n步,量子集不够就申请新的    
    108     while (n--) {    
    109         if (!qs->next) {    
    110             qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);    
    111             if (qs->next == NULL)    
    112                 return NULL;  /* Never mind */   
    113             memset(qs->next, 0, sizeof(struct scull_qset));    
    114         }    
    115         qs = qs->next;    
    116         continue;    
    117     }    
    118     return qs;    
    119 }    
    120 /*   
    121  * Data management: read and write   
    122  */   
    123 ssize_t scull_read( struct file *filp, //设备对应的文件结构     
    124                     char __user *buf,  //读到用户空间    
    125                     size_t count,      //字节数    
    126                     loff_t *f_pos)     //要读的位置,在filp私有数据中的偏移    
    127 {    
    128     struct scull_dev *dev = filp->private_data;     
    129     struct scull_qset *dptr;    /* the first listitem */   
    130     //量子、量子集大小    
    131     int quantum = dev->quantum, qset = dev->qset;    
    132     //一个量子集的字节数    
    133     int itemsize = quantum * qset; /* how many bytes in the listitem */   
    134     int item, s_pos, q_pos, rest;    
    135     ssize_t retval = 0;    
    136     if (down_interruptible(&dev->sem))    
    137         return -ERESTARTSYS;    
    138     //要读的位置超过了数据总量    
    139     if (*f_pos >= dev->size)    
    140         goto out;    
    141     //要读的count超出了size,截断count    
    142     if (*f_pos + count > dev->size)    
    143         count = dev->size - *f_pos;    
    144     /* find listitem, qset index, and offset in the quantum */   
    145     //在量子/量子集中定位读写位置:第几个量子集,中的第几个量子,在量子中偏移    
    146     //第几个量子集    
    147     item = (long)*f_pos / itemsize;    
    148     //在量子集中的偏移量    
    149     rest = (long)*f_pos % itemsize;    
    150     //第几个量子,在量子中的偏移    
    151     s_pos = rest / quantum; q_pos = rest % quantum;    
    152     /* follow the list up to the right position (defined elsewhere) */   
    153     //读取要读的量子集的指针    
    154     dptr = scull_follow(dev, item);    
    155     //读取出错处理    
    156     if (dptr == NULL || !dptr->data || ! dptr->data[s_pos])    
    157         goto out; /* don't fill holes */   
    158     /* read only up to the end of this quantum */   
    159     // 只在一个量子中读:如果count超出当前量子,截断count    
    160     if (count > quantum - q_pos)    
    161         count = quantum - q_pos;    
    162     // 将要读位置的内容复制count字节到用户空间buf中    
    163     if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {    
    164         retval = -EFAULT;    
    165         goto out;    
    166     }    
    167     *f_pos += count;    
    168     retval = count;    
    169   out:    
    170     up(&dev->sem);    
    171     return retval;    
    172 }    
    173 ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,    
    174                 loff_t *f_pos)    
    175 {    
    176     struct scull_dev *dev = filp->private_data;    
    177     struct scull_qset *dptr;    
    178     //量子、量子集大小    
    179     int quantum = dev->quantum, qset = dev->qset;    
    180     // 一个量子集总字节数    
    181     int itemsize = quantum * qset;    
    182     int item, s_pos, q_pos, rest;    
    183     ssize_t retval = -ENOMEM; /* value used in "goto out" statements */   
    184     if (down_interruptible(&dev->sem))    
    185         return -ERESTARTSYS;    
    186     /* find listitem, qset index and offset in the quantum */   
    187     //第几个量子集    
    188     item = (long)*f_pos / itemsize;    
    189     //在该量子集中的偏移    
    190     rest = (long)*f_pos % itemsize;    
    191     //在该量子集中的第几个量子,在量子中的偏移    
    192     s_pos = rest / quantum; q_pos = rest % quantum;    
    193     /* follow the list up to the right position */   
    194     //返回该量子集的指针    
    195     dptr = scull_follow(dev, item);    
    196     if (dptr == NULL)    
    197         goto out;    
    198     //如果该量子集数据为NULL,就申请一块新内存    
    199     if (!dptr->data) {    
    200         dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);    
    201         if (!dptr->data)    
    202             goto out;    
    203         memset(dptr->data, 0, qset * sizeof(char *));    
    204     }    
    205     //如果第s_pos个量子是NULL,就申请一块新内存    
    206     if (!dptr->data[s_pos]) {    
    207         dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);    
    208         if (!dptr->data[s_pos])    
    209             goto out;    
    210     }    
    211     /* write only up to the end of this quantum */   
    212     // 只在一个量子中写,如果count超出当前量子就截断    
    213     if (count > quantum - q_pos)    
    214         count = quantum - q_pos;    
    215     //从用户空间拷贝数据到内核空间,失败返回没有拷贝的字节数,成功返回0    
    216     if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {    
    217         retval = -EFAULT;    
    218         goto out;    
    219     }    
    220     *f_pos += count;    
    221     retval = count;    
    222     /* update the size */   
    223     // 更新字节总数大小    
    224     if (dev->size < *f_pos)    
    225         dev->size = *f_pos;    
    226   out:    
    227     up(&dev->sem);    
    228     return retval;    
    229 }    
    230    
    231 struct file_operations scull_fops = {    
    232     .owner =    THIS_MODULE,    
    233     .read =     scull_read,    
    234     .write =    scull_write,    
    235     .open =     scull_open,    
    236     .release =  scull_release,    
    237 };    
    238 /*   
    239  * Finally, the module stuff   
    240  */   
    241 /*   
    242  * The cleanup function is used to handle initialization failures as well.   
    243  * Thefore, it must be careful to work correctly even if some of the items   
    244  * have not been initialized   
    245  */   
    246 void scull_cleanup_module(void)    
    247 {    
    248     int i;    
    249     //主次设备号合成一个dev_t结构,即设备编号    
    250     dev_t devno = MKDEV(scull_major, scull_minor);    
    251     /* Get rid of our char dev entries */   
    252     if (scull_devices) {    
    253         //便利释放每个设备的数据区    
    254         for (i = 0; i < scull_nr_devs; i++) {    
    255             //释放数据区    
    256             scull_trim(scull_devices + i);    
    257             //移除cdev    
    258             cdev_del(&scull_devices[i].cdev);    
    259         }    
    260         //释放scull_devices本身    
    261         kfree(scull_devices);    
    262     }    
    263     /* cleanup_module is never called if registering failed */   
    264     unregister_chrdev_region(devno, scull_nr_devs);    
    265 }    
    266    
    267 /*   
    268  * Set up the char_dev structure for this device.   
    269  */   
    270 // 建立char_dev结构    
    271 static void scull_setup_cdev(struct scull_dev *dev, int index)    
    272 {    
    273     int err, devno = MKDEV(scull_major, scull_minor + index);    
    274         
    275     cdev_init(&dev->cdev, &scull_fops);    
    276     dev->cdev.owner = THIS_MODULE;    
    277 //  dev->cdev.ops = &scull_fops;    
    278     //添加字符设备dev->cdev,立即生效    
    279     err = cdev_add (&dev->cdev, devno, 1);    
    280     /* Fail gracefully if need be */   
    281     if (err)    
    282         printk(KERN_NOTICE "Error %d adding scull%d", err, index);    
    283 }    
    284    
    285 int scull_init_module(void)    
    286 {    
    287     int result, i;    
    288     dev_t dev = 0;    
    289 /*   
    290  * Get a range of minor numbers to work with, asking for a dynamic   
    291  * major unless directed otherwise at load time.   
    292  */   
    293     //申请设备编号,若在加载时没有指定主设备号就动态分配    
    294     if (scull_major) {    
    295         dev = MKDEV(scull_major, scull_minor);    
    296         result = register_chrdev_region(dev, scull_nr_devs, "scull");    
    297     } else {    
    298         result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,    
    299                 "scull");    
    300         scull_major = MAJOR(dev);    
    301     }    
    302     if (result < 0) {    
    303         printk(KERN_WARNING "scull: can't get major %d\n", scull_major);    
    304         return result;    
    305     }    
    306         /*    
    307      * allocate the devices -- we can't have them static, as the number   
    308      * can be specified at load time   
    309      */   
    310     //给scull_dev对象申请内存    
    311     scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);    
    312     if (!scull_devices) {    
    313         result = -ENOMEM;    
    314         goto fail;  /* Make this more graceful */   
    315     }    
    316     memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));    
    317         /* Initialize each device. */   
    318     for (i = 0; i < scull_nr_devs; i++) {    
    319         scull_devices[i].quantum = scull_quantum;    
    320         scull_devices[i].qset = scull_qset;    
    321         //初始化互斥锁,把信号量sem置为1    
    322         sema_init(&scull_devices[i].sem, 1);        
    323         //init_MUTEX(&scull_devices[i].sem);    
    324         //建立char_dev结构    
    325         scull_setup_cdev(&scull_devices[i], i);    
    326         }    
    327     return 0; /* succeed */   
    328   fail:    
    329     scull_cleanup_module();    
    330     return result;    
    331 }    
    332 module_init(scull_init_module);    
    333 module_exit(scull_cleanup_module);    
    334 MODULE_AUTHOR("Tekkamanninja");    
    335 MODULE_LICENSE("Dual BSD/GPL");  
  • 相关阅读:
    <<程序员>> 杂志网站
    插入排序
    冒泡排序
    TCP/IP编程实现远程文件传输
    选择排序
    防止基础表数据变动,导致相关的历史记录数据产生变动的解决方案
    发布一个RSS辅助类
    感谢jquery和firebug,让我也终于敢于写javascript了
    DevExpress ASPxGridView 使用文档四:数据源
    DevExpress ASPxGridView 使用文档六:模板
  • 原文地址:https://www.cnblogs.com/02xiaoma/p/2830432.html
Copyright © 2011-2022 走看看