LINUX驱动编程 scull 字符驱动 第一个可以使用的驱动(源码)

代码说明:通过修改函数中file_operations 来实现不同结构dev结构

三种分别是  小型结构   dev结构只接了 一个字符数组(量子)(测试通过 可以读写)

                中型结构   dev结构接链表(量子表)(测试通过 可以读写)

                大型结构   dev结构接链表(量子集)(测试不通过    是LDD3 原版代码 自行查找修改 根据修改小型结构的经验问题出在第一次open时trim函数的初始化)

 

 编译会产生 warning 因为 选择一种结构 另外两个结构就是未使用,有兴趣可以自行修改成参数选择的方式。(位于544 546两行 修改对应的 xx_fops就可以使用  前面的代码命名很乱,尽量不要修改底层)

驱动在 内核3.160-30下编译通过

 

  1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 
  4 #include <linux/errno.h>// error code
  5 #include <linux/types.h>//for struct dev_t
  6 #include <linux/kdev_t.h>
  7 #include <linux/fs.h>//for register major and minor
  8 #include <linux/cdev.h>//for [zi fu] device , struct cdev
  9 #include <linux/kernel.h>//for open()
 10 #include <linux/slab.h>//for kfree()
 11 #include <asm/uaccess.h>//for copy()
 12 #include <linux/mutex.h>
 13 #include <asm/switch_to.h>
 14 
 15 
 16 #ifndef DF_QUANTUM
 17 #define DF_QUANTUM 1024
 18 #endif // DF_QUANTUM 自己使用 完整代码
 19 
 20 #ifndef DF_QSET
 21 #define DF_QSET 1000 
 22 #endif // DF_QSET 自己使用 完整代码
 23 
 24 #ifndef SCLL_DEV_MEM_LEN
 25 #define SCLL_DEV_MEM_LEN 4000
 26 #endif
 27 
 28 
 29 MODULE_LICENSE("Dual BSD/GPL");
 30 
 31 
 32 
 33 int maj=0,minx=0;// for unregister 
 34 
 35 int pk_times=0;
 36 
 37 
 38 int pk_add(int n)
 39 {
 40     
 41      printk(KERN_ALERT"p_w\n");
 42     if(n>=2048)
 43     {
 44         printk(KERN_ALERT"write 2048! \n");
 45         return 0;
 46     }
 47     else
 48         return n+1;
 49 }
 50 
 51 
 52 
 53 //---------------struct for cde---------------------------------------------
 54 struct scull_qset{
 55     void **data;
 56     struct scull_qset *next;
 57 };
 58 struct sc_qset//中级结构 二级测试使用
 59 {
 60     char *data;
 61     struct sc_qset *next;
 62 };
 63 struct Hello_dev{
 64     struct scull_qset *data;//大型复杂结构 未测
 65     char *test_data;//小型简单结构 测试通过 可以使用(未测试bug 数据量超过 4/8 * 4000 可能崩溃)
 66     struct sc_qset *head;//中级结构 测试通过
 67     int quantum;
 68     int qset;
 69     unsigned long size;
 70     unsigned long access_key;
 71     struct semaphore sem;
 72     struct cdev cdev;
 73 };
 74 
 75 struct Hello_dev *my_dev;
 76 
 77 
 78 //==========================================================================                 
 79 //--------------------------functions for fops-------------------------------
 80 int char_data_trim(struct Hello_dev *dev)
 81 {
 82     if (!dev)
 83         return -1;
 84 
 85     printk(KERN_ALERT"do kfree  %p\n",dev->test_data);
 86 
 87     if(dev->test_data)
 88         kfree(dev->test_data);
 89 
 90     printk(KERN_ALERT"finish kfree \n");
 91 
 92     dev->size = 0 ;
 93     dev->quantum = DF_QUANTUM ;
 94     dev->qset = DF_QSET ;
 95     dev->data = NULL ;
 96     dev->test_data = NULL ;
 97 
 98     printk(KERN_ALERT"finish trim \n");
 99     return 0;
100 
101 }
102 
103 int zj_trim(struct Hello_dev *dev)
104 {
105     
106     struct sc_qset *dir,*temp;//指针代换
107     
108 
109     if(!dev)
110         return 0;
111 
112     dir = dev->head;
113 
114     while(dir) //清除链表
115     {
116         if(dir->data)
117         kfree(dir->data);//如果分配了量子 那么清除
118 
119         temp=dir;  //下一个循环
120         dir=dir->next;
121         kfree(temp);//清除当前量子集
122     }
123 
124     dev->size = 0 ;
125     dev->quantum = DF_QUANTUM ;
126     dev->qset = DF_QSET ;
127     dev->data = NULL ;
128     dev->test_data = NULL ;
129     dev->head = NULL;
130     return 0;
131 }
132 
133 int h_trim(struct Hello_dev *dev)
134 {
135     struct scull_qset *next,*dptr;
136     int qset = dev->qset;
137     int i;
138     for (dptr=dev->data;dptr;dptr=next)
139         {
140             if(dptr->data)
141             {
142                 for(i=0;i<qset;i++)
143                     kfree(dptr->data[i]);
144                 kfree(dptr->data);
145                 dptr->data = NULL;
146             }
147             next = dptr->next;
148             kfree(dptr);
149         }
150     dev->size = 0;
151     dev->quantum = DF_QUANTUM;
152     dev->qset = DF_QSET;
153     dev->data = NULL;
154     return 0;
155     
156 }
157 static struct sc_qset *zj_follow(struct Hello_dev *dev,int n)
158 {
159     struct sc_qset *qs;
160 
161     qs =dev->head;
162 
163     if(!qs)
164     {
165         qs = dev->head = kmalloc(sizeof(struct sc_qset),GFP_KERNEL);
166         if(!qs)
167             return NULL;
168         memset(qs,0,sizeof(struct sc_qset));
169     }
170     while (n--)
171     {
172         if(!qs->next)
173         {
174             qs->next = kmalloc(sizeof(struct sc_qset),GFP_KERNEL);
175             if(!qs)
176                 return NULL;
177             memset(qs->next,0,sizeof(struct sc_qset));
178         }
179         qs=qs->next;
180         continue;
181     }
182     return qs;
183 
184 }
185 static struct scull_qset *h_follow(struct Hello_dev *dev,int n)
186 {
187     struct scull_qset *qs = dev->data;
188 
189     if(!qs)//if qs dont exist
190     {
191         qs = dev->data = kmalloc(sizeof(struct scull_qset),GFP_KERNEL);
192         if(qs==NULL)
193             return NULL;
194         memset(qs,0,sizeof(struct scull_qset));
195     }
196     while(n--)
197     {
198         if(!qs->next)
199         {
200             qs->next = kmalloc(sizeof(struct scull_qset),GFP_KERNEL);
201             if(qs->next == NULL)
202                 return NULL;
203             memset(qs->next,0,sizeof(struct scull_qset));
204         }
205         qs = qs->next;
206         continue;
207     }
208     return qs;
209 }
210 
211 //************************************
212 // Method:    h_open
213 // FullName:  h_open
214 // Access:    public static 
215 // Returns:   int
216 // Qualifier: for Hello_module , fix it later
217 // Parameter: struct inode * inode
218 // Parameter: struct file * filp
219 //************************************
220 static int h_open(struct inode *inode,struct file *filp)
221 {
222     struct Hello_dev *temp_h_dev;
223     temp_h_dev = container_of(inode->i_cdev,struct Hello_dev,cdev);
224     filp->private_data = temp_h_dev;// for other methods
225     if((filp->f_flags & O_ACCMODE) == O_WRONLY)
226     {
227         
228         h_trim(temp_h_dev); 
229 
230     }
231     return 0;
232 }
233 
234 static int sc_open(struct inode *inode,struct file *filp)
235 {
236     struct Hello_dev *temp_h_dev;
237     temp_h_dev = container_of(inode->i_cdev,struct Hello_dev,cdev);
238     filp->private_data = temp_h_dev;// for other methods
239 
240     printk(KERN_ALERT" p of (temp) my_dev : %p \n",temp_h_dev);
241     
242     if((filp->f_flags & O_ACCMODE) == O_WRONLY)
243     {    
244         printk(KERN_ALERT" do trim \n");
245         char_data_trim(temp_h_dev);  /* ignore errors */    
246     }
247 
248     printk(KERN_ALERT"finish op successfully!\n");
249     return 0;
250 }
251 
252 static int zj_open(struct inode *inode,struct file *filp)
253 {
254     struct Hello_dev *temp_h_dev;
255     temp_h_dev = container_of(inode->i_cdev,struct Hello_dev,cdev);
256     filp->private_data = temp_h_dev;// for other methods
257 
258     if((filp->f_flags & O_ACCMODE) == O_WRONLY)
259     {    
260         zj_trim(temp_h_dev);  /* ignore errors */    
261     }
262 
263     printk(KERN_ALERT"finish zj op successfully!\n");
264     return 0;
265 }
266 static int h_relaese(struct inode *inode,struct file *filp)
267 {
268     return 0;
269 }
270 
271 //测试函数正确性 内存泄漏解决 测试存储结构
272 static ssize_t sc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
273 {
274     struct Hello_dev *dev = filp->private_data;
275     ssize_t retval = 0;
276     
277 
278     if (down_interruptible(&dev->sem))
279         return -ERESTARTSYS;
280     if (*f_pos >= dev->size)
281         goto out;
282     if (*f_pos + count > dev->size)
283         count = dev->size - (*f_pos);
284     if (copy_to_user(buf, dev->test_data, count)) {
285         retval = -EFAULT;
286         goto out;
287     }
288     *f_pos += count;
289     retval  = count;
290     printk(KERN_WARNING "DEBUG read \n");
291 out:
292     up(&dev->sem);
293     return retval;
294 }
295 static ssize_t zj_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
296 {
297     int x=0,y=0;//x是链表对应位置 从0开始   y是数组对应位置
298     struct Hello_dev *dev = filp->private_data;
299     ssize_t retval = 0;
300     struct sc_qset *dir ;
301     x=(long)*f_pos/DF_QSET; //这个位置就是开始读写的位置,第一个字符从这个位置开始读
302     y=(long)*f_pos%DF_QSET;
303     
304     if (down_interruptible(&dev->sem))
305         return -ERESTARTSYS;
306 
307     printk(KERN_ALERT"read 1 || x: %d ; y: %d \n",x,y);
308 
309     dir = zj_follow(dev,x);
310 
311 
312     if(!dir)
313         goto out;
314 
315     //检查读取位置是否还在设备内部 并且读取位置上有数据
316     if (*f_pos >= dev->size || !dir->data)
317         goto out;
318 
319     //超出设备部分不读取
320     if (*f_pos + count > dev->size)
321         count = dev->size - (*f_pos);
322 
323     printk(KERN_ALERT"read 2 || %d\n",count);
324 
325     //超出量子部分不读取
326     if(y + count > DF_QSET)
327         count = DF_QSET - y ;
328 
329     printk(KERN_ALERT"read 3 || %d\n",count);
330 
331     //复制到用户空间
332     if (copy_to_user(buf, dir->data+y, count)) {
333         retval = -EFAULT;
334         printk(KERN_ALERT"read 4 ||read failed  count = %d ,*f_pos = %d \n",(int)count,(int)*f_pos);
335         goto out;
336     }
337     
338     *f_pos += count;
339     retval  = count;
340     printk(KERN_WARNING "DEBUG zj read ||  x = %d , y = %d ,count = %d ,*f_pos = %d \n",x,y,(int)count,(int)*f_pos);
341 out:
342     up(&dev->sem);
343     return retval;
344 }
345 static ssize_t sc_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
346 {
347     struct Hello_dev *dev = filp->private_data;
348     ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
349 
350     if (down_interruptible(&dev->sem))
351         return -ERESTARTSYS;
352 
353 
354     if (!dev->test_data){
355         dev->test_data = kmalloc(SCLL_DEV_MEM_LEN * sizeof(char *), GFP_KERNEL);
356         if (!dev->test_data)
357             goto out;
358         memset(dev->test_data, 0, SCLL_DEV_MEM_LEN * sizeof(char *));
359     }
360 
361     if (copy_from_user(dev->test_data, buf, count)) {
362         retval = -EFAULT;
363         goto out;
364     }
365     *f_pos += count;
366     retval = count;
367 
368     printk(KERN_WARNING "DEBUG write \n");
369     /* update the size */
370     if (dev->size < *f_pos)
371         dev->size = *f_pos;
372 
373 
374 out:
375     up(&dev->sem);
376     return retval;
377 }
378 
379 static ssize_t zj_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
380 {
381     int x=0,y=0;//x是链表对应位置 从0开始   y是数组对应位置
382     struct Hello_dev *dev = filp->private_data;
383     ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
384     struct sc_qset *dir ;
385     x=(long)*f_pos/DF_QSET; //这个位置就是开始读写的位置,第一个字符从这个位置开始读
386     y=(long)*f_pos%DF_QSET;
387 
388     if (down_interruptible(&dev->sem))
389         return -ERESTARTSYS;
390 
391     dir = zj_follow(dev,x);
392 
393     if(!dir)
394         goto out;
395 
396     if (!dir->data)
397     {
398         dir->data = kmalloc(DF_QSET * sizeof(char), GFP_KERNEL);
399         if(dir->data)
400         memset(dir->data, 0, DF_QSET * sizeof(char));
401     }
402 
403     if( y + count > DF_QSET)
404         count=DF_QSET - y;
405 
406     if (copy_from_user(dir->data+y, buf, count)) {
407         retval = -EFAULT;
408         goto out;
409     }
410     *f_pos += count;
411     retval = count;
412 
413     
414     /* update the size */
415     if (dev->size < *f_pos)
416         dev->size = *f_pos;
417 out:
418     up(&dev->sem);
419     return retval;
420 }
421 
422 static ssize_t h_read(struct file *filp,char __user *buff,size_t count,loff_t *f_pos)
423 {
424     struct Hello_dev *dev = filp->private_data;
425     struct scull_qset *dptr;
426     int quantum = dev->quantum;
427     int qset =dev->qset;
428     int item_size =quantum * qset;
429     int item,s_pos,q_pos,reset;
430     ssize_t retval = 0 ;
431 
432     if(down_interruptible(&dev->sem))
433         return -ERESTARTSYS;
434     if(*f_pos >= dev->size)
435         goto out;
436     if(*f_pos + count > dev->size)
437         count = dev->size - *f_pos;
438     item  = (long)*f_pos / item_size;
439     reset = (long)*f_pos % item_size;
440     s_pos = reset / quantum;
441     q_pos = reset % quantum;
442 
443     dptr = h_follow(dev,item);
444 
445     if(dptr == NULL || ! dptr->data || ! dptr->data[s_pos])
446         goto out;
447     if(count >quantum-q_pos)
448         count = quantum -q_pos;
449     if(copy_to_user(buff,dptr->data[s_pos] + q_pos,count))
450     {
451         retval = -EFAULT;
452         goto out;
453     }
454     *f_pos += count;
455     retval = count;
456 out:
457     up(&dev->sem);
458     return retval;
459 }
460 static ssize_t h_write(struct file *filp,const char __user *buf ,size_t count ,loff_t *f_pos)
461 {
462     struct Hello_dev *dev = filp->private_data;
463     struct scull_qset *dptr;
464     int quantum = dev->quantum;
465     int qset =dev->qset;
466     int item_size =quantum * qset;
467     int item,s_pos,q_pos,reset;
468     ssize_t retval = -ENOMEM;
469     if(down_interruptible(&dev->sem))
470         return -ERESTARTSYS;
471     item  = (long)*f_pos / item_size;
472     reset = (long)*f_pos % item_size;
473     s_pos = reset / quantum;
474     q_pos = reset % quantum;
475 
476     dptr = h_follow(dev,item);
477     if(dptr == NULL)
478         goto out;
479     if(!dptr->data)
480     {
481         dptr->data = kmalloc(qset * sizeof(char *),GFP_KERNEL);
482         if(!dptr->data)
483             goto out;
484         memset(dptr->data,0,qset*sizeof(char *));
485     }
486     if(!dptr->data[s_pos])
487     {
488         dptr->data[s_pos] = kmalloc(quantum,GFP_KERNEL);
489         if(!dptr->data[s_pos])
490             goto out;
491     }
492     if(count > quantum -q_pos)
493         count =quantum -q_pos;
494     if(copy_to_user(dptr->data[s_pos]+q_pos,buf,count))
495     {
496         retval = -EFAULT;
497         goto out;
498 
499     }
500     pk_times=pk_add(pk_times);
501 
502     *f_pos += count;
503     retval = count;
504 
505     if(dev->size < *f_pos)
506         dev->size = *f_pos;
507 out:
508     up(&dev->sem);
509     return retval;
510 
511 }
512 //===========================================================================
513 //---------------struct for fops--------------------------------------------
514 static struct file_operations Hello_fops=
515 {
516     .owner = THIS_MODULE,
517     .read = h_read,
518     .write = h_write,
519     .open = h_open,
520     .release = h_relaese,
521 };
522 static struct file_operations sc_fops=
523 {
524     .owner = THIS_MODULE,
525     .read =  sc_read,
526     .write = sc_write,
527     .open =  sc_open,
528     .release = h_relaese,
529 };
530 static struct file_operations zj_fops=
531 {
532     .owner = THIS_MODULE,
533     .read = zj_read,
534     .write = zj_write,
535     .open = zj_open,
536     .release = h_relaese,
537 };
538 //==========================================================================
539 //----------------functions for dev setup-----------------------------------
540 static int holle_setup_cdev(struct Hello_dev  *dev , int index)
541 {
542     int err,first = MKDEV(maj,minx + index);
543     sema_init(&dev->sem,1);
544     cdev_init(&dev->cdev,&zj_fops);
545     dev->cdev.owner = THIS_MODULE;
546     dev->cdev.ops = &zj_fops;
547     err = cdev_add(&dev->cdev,first,1);
548     if(err)
549         printk(KERN_ALERT"fail to add %d,err code %d \n",index,err);
550     else 
551         printk(KERN_ALERT"add   successfully   !!!! \n");
552     return 0;
553 }
554 //=========================================================================== 
555 static void hello_exit(void)
556 {   
557     if(!my_dev)
558     {
559         char_data_trim(my_dev);
560         cdev_del(&my_dev->cdev);
561         kfree(my_dev);
562     }
563     unregister_chrdev_region(MKDEV(maj,minx),1);
564     printk(KERN_ALERT"unreg successfully  !!!! \n");        
565     printk(KERN_ALERT"==================goodbye,cruel world!==================\n");
566 }
567 
568 
569 static int hello_init(void)
570 {    
571     char name[]="hello"; //设备名称
572     dev_t sec;
573     int isregsu=0,isregsu_a=0;
574     
575     printk(KERN_ALERT"-----------------Hello world-----------------\n");
576        
577     
578     // 申请设备的内存空间 并初始化地址
579     my_dev = kmalloc(sizeof(struct  Hello_dev),GFP_KERNEL);
580     my_dev->data=NULL;// 此处必须清指针,如果不清指针kfree必崩溃 。且menset不行,原因不明白
581     my_dev->test_data=NULL; // 同上 可能是随机的指针指向了不能访问的内存页导致的
582     my_dev->head=NULL;
583 
584     if(!my_dev)
585     {
586         return -12;
587     }
588     
589     // 动态申请设备号 此处未提供静态设备号接口
590     isregsu_a = alloc_chrdev_region(&sec,0,1,name); 
591     
592     if(isregsu_a==0)
593         printk(KERN_ALERT"reg   successfully   !!!! \n");
594     else
595     {
596         printk(KERN_ALERT"fail to reg,error code %d !!\n",isregsu_a);
597         return -1;
598     }
599         
600     maj  = MAJOR(sec);
601     minx = MINOR(sec);
602 
603 
604     // 向内核注册设备
605     isregsu_a =  holle_setup_cdev(my_dev,0);
606     if(!isregsu_a)
607      printk(KERN_ALERT"setup dev ,op code  %d !!\n",isregsu_a);
608     else
609     {
610         printk(KERN_ALERT"fail to setup,op code %d !!",isregsu_a);
611         goto fail_out;
612     }
613     return 0;
614 
615 fail_out:// 初始化失败出口函数
616     hello_exit();
617     return isregsu;
618 
619 }
620 
621 
622 
623 
624 
625 
626 
627 module_init(hello_init);
628 module_exit(hello_exit);

 

posted @ 2016-07-23 09:34  吃猫粮的耗子  阅读(433)  评论(0)    收藏  举报