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");  
原文地址:https://www.cnblogs.com/02xiaoma/p/2830432.html