Chinaunix

标题: scull驱动奇怪的问题。不能运行。已解决 [打印本页]

作者: HJLin    时间: 2010-12-01 10:34
标题: scull驱动奇怪的问题。不能运行。已解决
本帖最后由 HJLin 于 2010-12-01 17:42 编辑

从昨天晚上开始发现这个问题一直美法解决。非常郁闷啊。。。

问题如下:
ldd3上面的例子,原来我是用一个文件(scull.c)全部实现的。运行没有问题。后来为了优化设计,我把各个功能拆开到多个文件中(scull_fops.h scull_fops.c scull.c)中。出现问题了,编译正常,但是insmod scull.ko加载之后(dmesg, /var/log/messages)没有任何反应。/proc/devices也没有生成scull设备。非常的郁闷啊。

下面是代码,请高手帮助小弟一把: scull.tar.gz (2.85 KB, 下载次数: 62)
作者: HJLin    时间: 2010-12-01 10:38
附上直观的代码,望高手方便赐教。。

Makefile
  1. obj-m := scull.o

  2. scull-objs := scull_fops.o

  3. KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  4. PWD := $(shell pwd)
  5. default:
  6.         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

  7. clean:
  8.         $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
  9.         rm -fr *.o *.ko *.symvers *.mod.c
复制代码
scull_fops.h
  1. #ifndef _SCULL_FOPS_H_
  2. #define _SCULL_FOPS_H_

  3. #include <linux/sched.h>
  4. #include <linux/types.h>
  5. //file file_operations etc.
  6. #include <linux/module.h>
  7. #include <linux/fs.h>
  8. #include <linux/cdev.h>
  9. //copy
  10. #include <asm/uaccess.h>


  11. MODULE_LICENSE("Dual BSD/GPL");

  12. loff_t scull_llseek(struct file *, loff_t, int);
  13. ssize_t scull_read(struct file *, char __user *, size_t, loff_t *);
  14. ssize_t scull_write(struct file *, const char __user *, size_t, loff_t *);
  15. int scull_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
  16. int scull_open(struct inode *, struct file *);
  17. int scull_release(struct inode *, struct file *);

  18. struct scull_qset {
  19.   void **data;
  20.   struct scull_qset *next;
  21. };

  22. struct scull_dev {
  23.   struct scull_qset *data;  /* Pointer to first quantum set */
  24.   int quantum;  /* the current quantum size */
  25.   int qset;  /* the current array size */
  26.   unsigned long size;  /* amount of data stored here */
  27.   unsigned int access_key;  /* used by sculluid and scullpriv */
  28.   struct semaphore sem;  /* mutual exclusion semaphore  */

  29.   struct cdev cdev; /* Char device structure */
  30. };

  31. int scull_trim(struct scull_dev *dev);
  32. struct scull_qset *scull_follow(struct scull_dev *dev, int item);

  33. #endif
复制代码
scull_fops.c
  1. #include "scull_fops.h"

  2. struct scull_dev dev;
  3. //EXPORT_SYMBOL(dev);

  4. struct file_operations scull_fops = {
  5.   .owner = THIS_MODULE,
  6.   .llseek = scull_llseek,
  7.   .read = scull_read,
  8.   .write = scull_write,
  9.   .ioctl = scull_ioctl,
  10.   .open = scull_open,
  11.   .release = scull_release
  12. };
  13. //EXPORT_SYMBOL(scull_fops);


  14. loff_t
  15. scull_llseek(struct file *filp, loff_t offp, int count) {
  16.   return 0;
  17. }

  18. ssize_t
  19. scull_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos) {
  20.   printk("scull, scull_read() buff=%p, count=%i, *f_pos=%i\n", buff, count, *f_pos);
  21.   struct scull_dev *dev = (struct scull_dev*)filp->private_data;
  22.   struct scull_qset *p;
  23.   int quantum = dev->quantum;
  24.   int qset = dev->qset;
  25.   int itemsize = qset * quantum;
  26.   ssize_t retval = 0;

  27.   if (down_interruptible(&dev->sem))
  28.     return -ERESTARTSYS;
  29.   if (*f_pos >= dev->size)
  30.     goto out;
  31.   if (*f_pos + count > dev->size)
  32.     count = dev->size - *f_pos;

  33.   int item = (long)*f_pos / itemsize;
  34.   int rest = (long)*f_pos % itemsize;

  35.   int s_pos = rest / quantum;
  36.   int q_pos = rest % quantum;

  37.   //follow the list up to the right qset
  38.   p = scull_follow(dev, item);

  39.   //printk("p = %p \n", p);
  40.   //printk("p->data = %p \n", p->data);
  41.   //printk("p->data[s_pos] = %p \n", p->data[s_pos]);
  42.   
  43.   if (p == NULL || p->data == NULL || p->data[s_pos] == NULL ) {
  44.     printk("something is wrong\n");
  45.     goto out;
  46.   }
  47.    
  48.   char *str = p->data[s_pos] + q_pos;
  49.   //read only up to the end of this quantum
  50.   if (count > quantum - q_pos)
  51.     count = quantum - q_pos;
  52.   
  53.   if (copy_to_user(buff, p->data[s_pos] + q_pos, count) != 0) {
  54.     retval = -EFAULT;
  55.     goto out;
  56.   }  
  57.   
  58.   printk("scull, success read %i bytes\n", count);
  59.   *f_pos += count;
  60.   retval = count;

  61. out:
  62.   up(&dev->sem);
  63.   return retval;
  64. }

  65. ssize_t
  66. scull_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos) {
  67.   printk("scull, scull_write() start, buff=%p, count=%i, *f_pos=%i\n", buff, count, *f_pos);   
  68.   struct scull_dev *dev = filp->private_data;
  69.   int itemsize = dev->qset * dev->quantum;

  70.   ssize_t retval = 0;
  71.   if (down_interruptible(&dev->sem)) {
  72.     return -ERESTARTSYS;
  73.   }
  74.   
  75.   int item = (long)*f_pos / itemsize;
  76.   int rest = (long)*f_pos % itemsize;
  77.   int s_pos = rest / dev->quantum;
  78.   int q_pos = rest % dev->quantum;
  79.   
  80.   struct scull_qset *p = scull_follow(dev, item);
  81.   if (p == NULL) {
  82.     printk("scull_follow() failed\n");
  83.     goto out;
  84.   }

  85.   if (p->data == NULL) {
  86.     p->data = kmalloc(sizeof(char*) * dev->qset, GFP_KERNEL);
  87.     if (p->data == NULL)
  88.       goto out;
  89.     memset(p->data, 0, sizeof(char*) * dev->qset);  
  90.   }
  91.   if ((p->data)[s_pos] == NULL) {
  92.     (p->data)[s_pos] = kmalloc(dev->quantum, GFP_KERNEL);
  93.     if ((p->data)[s_pos] == NULL)
  94.       goto out;
  95.   }
  96.   if (count > dev->quantum - q_pos)
  97.     count = dev->quantum - q_pos;

  98.   //printk("p = %p \n", p);
  99.   //printk("p->data = %p \n", p->data);
  100.   //printk("p->data[s_pos] = %p \n", p->data[s_pos]);

  101.   if (copy_from_user(p->data[s_pos] + q_pos, buff, count) != 0) {
  102.     retval = -EFAULT;
  103.     goto out;
  104.   }

  105.   retval = count;
  106.   *f_pos += count;
  107.   
  108.   if (dev->size < *f_pos) {
  109.     dev->size = *f_pos;
  110.   }
  111.   printk("scull, copy_from_user %i bytes\n", count);

  112. out:
  113.   up(&dev->sem);
  114.   return retval;
  115. }
  116. int
  117. scull_ioctl(struct inode *indoe, struct file *filp, unsigned int flag, unsigned long num) {
  118.   return 0;
  119. }

  120. int
  121. scull_open(struct inode *inode, struct file *filp) {
  122.   printk("scull, scull_open() start\n");
  123.   struct scull_dev *dev;
  124.   dev = container_of(inode->i_cdev, struct scull_dev, cdev);
  125.   filp->private_data = dev;

  126.   if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
  127.     scull_trim(dev);   
  128.   }
  129.   return 0;
  130. }

  131. int
  132. scull_release(struct inode *inode, struct file *filp) {
  133.   printk("scull, scull_release() start\n");
  134.   return 0;
  135. }

  136. int
  137. scull_trim(struct scull_dev *dev) {
  138.   printk("scull, scull_trim() start\n");
  139.   struct scull_qset *p = dev->data;
  140.   while (p != NULL) {
  141.     int i;
  142.     for (i=0; i<dev->qset; i++) {
  143.       kfree((p->data)[i]);
  144.     }
  145.     kfree(p->data);
  146.     struct scull_qset *next = p->next;
  147.     kfree(p);
  148.     p = next;
  149.   }

  150.   dev->size = 0;
  151.   dev->data = NULL;
  152.   return 0;
  153. }

  154. struct scull_qset *
  155. scull_follow(struct scull_dev *dev, int item) {
  156.   printk("scull, scull_follow() start\n");
  157.   struct scull_qset *p = dev->data;
  158.   if (dev->data == NULL) {
  159.     dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
  160.     if (dev->data == NULL)
  161.       return NULL;
  162.     p = dev->data;
  163.     p->next = NULL;
  164.     p->data = NULL;
  165.   }

  166.   while (item-- != 0) {
  167.     if (p->next == NULL) {
  168.       p->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
  169.       if (p->next == NULL)
  170.         return NULL;
  171.       p->next->data = NULL;
  172.       p->next->next = NULL;
  173.     }
  174.     p = p->next;
  175.   }

  176.   return p;
  177. }
复制代码
scull.c
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/types.h>
  4. #include <linux/cdev.h>

  5. #include "scull_fops.h"

  6. extern struct scull_dev dev;
  7. extern struct file_operations scull_fops;

  8. dev_t devno;
  9. int major = 0;
  10. int minor = 0;
  11. int nr_devs = 4;

  12. //init
  13. int scull_init(void);
  14. //exit
  15. void scull_exit(void);
  16. //分配设备
  17. int alloc_dev(void);
  18. //注册设备
  19. int register_dev(void);

  20. int
  21. scull_init(void) {
  22.   printk("hello, scull\n");
  23.   printk("The process is \"%s\" (pid %i)\n", current->comm, current->pid);
  24.   if (alloc_dev() == -1) {
  25.     printk("scull: can't alloc devno, %i\n", major);
  26.     return -1;
  27.   }
  28.   if (register_dev() == -1) {
  29.     printk("scull, register_dev() failed\n");
  30.     return -1;
  31.   }
  32.   return 0;
  33. }

  34. void
  35. scull_exit(void) {
  36.   printk("Goodbye, scull %i,%i\n", major, minor);
  37.   unregister_chrdev_region(devno, nr_devs);
  38.   cdev_del(&dev.cdev);
  39. }

  40. int
  41. alloc_dev(void) {
  42.   int result = 0;
  43.   printk("scull, alloc_dev() start\n");
  44.   if (major == 0) {
  45.     result = alloc_chrdev_region(&devno, minor, nr_devs, "scull");
  46.     major = MAJOR(devno);
  47.   } else {
  48.     devno = MKDEV(major, minor);
  49.     result = register_chrdev_region(devno, nr_devs, "scull");
  50.   }
  51.   return result;
  52. }

  53. int
  54. register_dev(void) {
  55.   printk("scull, register_dev() start\n");
  56.   dev.data = NULL;
  57.   dev.quantum = 4000;
  58.   dev.qset = 1000;
  59.   dev.size = 0;
  60.   init_MUTEX(&dev.sem);
  61.   
  62.   cdev_init(&dev.cdev, &scull_fops);
  63.   dev.cdev.owner = THIS_MODULE;
  64.   dev.cdev.ops = &scull_fops;
  65.   return cdev_add(&dev.cdev, devno, 1);
  66. }

  67. module_init(scull_init);
  68. module_exit(scull_exit);
复制代码

作者: dreamice    时间: 2010-12-01 11:12
你为什么要写这一行:
scull-objs := scull_fops.o
作者: dreamice    时间: 2010-12-01 11:13
看起来应该是你的Makefile的问题
作者: HJLin    时间: 2010-12-01 11:22
本帖最后由 HJLin 于 2010-12-01 13:25 编辑

scull-objs := scull_fops.o 这个是说这个模块(scull)依赖哪些文件的。
如果不加,编译的话报警告找不到符号。
insmod失败


这个语法也是昨天网上查到的。
作者: yikaikai    时间: 2010-12-01 16:21
编译没出现错误或者警告信息么?
作者: HJLin    时间: 2010-12-01 16:26
编译没有什么问题。就是一些代码混编的警告。


[root@localhost scull]# make
make -C /lib/modules/2.6.18-92.el5/build M=/root/ldd3/scull  modules
make[1]: Entering directory `/usr/src/kernels/2.6.18-92.el5-i686'
  CC [M]  /root/ldd3/scull/scull_fops.o
/root/ldd3/scull/scull_fops.c: In function ‘scull_read’:
/root/ldd3/scull/scull_fops.c:25: warning: format ‘%i’ expects type ‘int’, but argument 4 has type ‘loff_t’
/root/ldd3/scull/scull_fops.c:26: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c:40: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c:58: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c:58: warning: unused variable ‘str’
/root/ldd3/scull/scull_fops.c: In function ‘scull_write’:
/root/ldd3/scull/scull_fops.c:79: warning: format ‘%i’ expects type ‘int’, but argument 4 has type ‘loff_t’
/root/ldd3/scull/scull_fops.c:80: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c:88: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c: In function ‘scull_open’:
/root/ldd3/scull/scull_fops.c:142: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c: In function ‘scull_trim’:
/root/ldd3/scull/scull_fops.c:161: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c:168: warning: ISO C90 forbids mixed declarations and code
/root/ldd3/scull/scull_fops.c: In function ‘scull_follow’:
/root/ldd3/scull/scull_fops.c:181: warning: ISO C90 forbids mixed declarations and code
  LD [M]  /root/ldd3/scull/scull.o
  Building modules, stage 2.
  MODPOST
  CC      /root/ldd3/scull/scull.mod.o
  LD [M]  /root/ldd3/scull/scull.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.18-92.el5-i686'
作者: EZWORD    时间: 2010-12-01 17:14
本帖最后由 EZWORD 于 2010-12-01 17:15 编辑

程序本身没有问题,问题在于程序太乱,以下我测试结果
insmod scull.ko
hello, scull
The process is "insmod" (pid 83)
scull, alloc_dev() start
scull, register_dev() start
cat /proc/device
251 scull   


简单的把那个scull_fops.c包进来。。。。。
makefile中
scull-objs := scull_fops.o
这一行要去掉

建议好好学学c的编程规范

作者: EZWORD    时间: 2010-12-01 17:19
去试试吧,我这里就可以通过,而且出现设备了。
作者: HJLin    时间: 2010-12-01 17:26
回复 10# EZWORD


    你可以用,是按照我的源码,文件分开的吗?没有把scull_fops 合到scull.c 里面把?
作者: EZWORD    时间: 2010-12-01 17:30
你这个问题应该在于makefile上,
直接把他包括进来,或者只修改makefile也可以。
具体方法参考Documentation\kbuild\modules.txt
作者: HJLin    时间: 2010-12-01 17:32
回复 12# EZWORD


    给个具体的方法好么?没有弄过啊?
作者: EZWORD    时间: 2010-12-01 17:37
第一个方法应该是这样:
1,makefile中去掉上面说的那一行
2,在scull.c中把那个scull_fops.c包括进来
第二个方法就是把makefile重写:网上搜到例子如下
 如果是多个源文件编译出一个模块,那么假设模块名是mytest.ko,那么源文件名不能有mytest.c,下面是一个例子:
  obj-m := mytest.o
  mytest-objs := file1.o file2.o file3.o


对于第一个方法确认可用,第二个你自己试试吧。
作者: HJLin    时间: 2010-12-01 17:41
回复 14# EZWORD


    果然是高手啊,第二个方法改个名字就能用了。非常感谢。
ps:自学这个东西还真困难啊。
作者: EZWORD    时间: 2010-12-01 17:42
呵呵,别忘了给我加点分。。。
作者: dreamice    时间: 2010-12-02 15:18
回复 16# EZWORD


    感谢热心,我也给你加分了,继续发扬!
作者: EZWORD    时间: 2010-12-02 15:56
回复  EZWORD


    感谢热心,我也给你加分了,继续发扬!
dreamice 发表于 2010-12-02 15:18



    太少了。
作者: dreamice    时间: 2010-12-02 19:47
太少了。
EZWORD 发表于 2010-12-02 15:56



    哈哈,再接再厉!
作者: Yuek_Lee    时间: 2011-01-13 17:27
Makefile的问题,原先的scull.o模块现在依赖 scull.c 和 scull_fops.c生成。改成这么写就行了
obj-m:=modscull.o
modscull-objs:=scull_fops.o scull.o

还有设备注册那个函数有点问题
如果设备号申请成功但是设备注册失败,注册的设备号未释放,最好调用scull_exit之后再return -1




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2