scull在Ubuntu11.10上的编译

写在前面的话

在学习Linux设备驱动程序过程中,ldd3是必不可少的一本书,那么在书中,我们会看到书中的一个设备驱动程序----scull。

今天,我们就要看看如何将这个设备驱动程序在Ubuntu11.10上进行编译;而后,我们就能利用scull更加深层次的去学习驱动程序的知识。


首先,我们去下载一份ldd3的配套源码,下面是我分享的一份代码,大家可以下载使用:http://yunpan.cn/lk/sV2ZrN6JFEKKW?sid=301

对源码进行解压,里面会有好几个目录,我们现在要关心的就是scull这个目录,下面的操作都会在这里进行。

root@yafeng-VirtualBox:/examples# ls
include  LICENSE   misc-modules  pci    scull   sculld  scullv  shortprint  skull  tty
lddbus   Makefile  misc-progs    sbull  scullc  scullp  short   simple      snull  usb
root@yafeng-VirtualBox:/examples# 

再者,我们来看看我们要编译的平台的是怎么样的一个平台:

root@yafeng-VirtualBox:/# uname -a
Linux yafeng-VirtualBox 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686 i686 i386 GNU/Linux
root@yafeng-VirtualBox:/# 

通过上面的打印,我们可以知道是3.0.0.12的内核。

好了,万事俱备,只欠东风。下面就开始编译吧。我们总的思路就是一步步的make,然后根据提示一步步的解决啊!

一.习惯性地由make开始,我们会看到下面的错误:

root@yafeng-VirtualBox:/examples/scull# make
make -C /lib/modules/3.0.0-12-generic/build M=/examples/scull LDDINC=/examples/scull/../include modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
scripts/Makefile.build:49: *** CFLAGS was changed in "/examples/scull/Makefile". Fix it to use EXTRA_CFLAGS.  Stop.
make[1]: *** [_module_/examples/scull] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-12-generic'
make: *** [modules] Error 2

解决方法:循着错误提示,我们将Makefile文件中的CFLAGS都改为了EXTRA_CFLAGS,共三处。

二.继续make:

root@yafeng-VirtualBox:/examples/scull# make
make -C /lib/modules/3.0.0-12-generic/build M=/examples/scull LDDINC=/examples/scull/../include modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
  CC [M]  /examples/scull/main.o
/examples/scull/main.c:17:26: fatal error: linux/config.h: No such file or directory
compilation terminated.
make[2]: *** [/examples/scull/main.o] Error 1
make[1]: *** [_module_/examples/scull] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-12-generic'
make: *** [modules] Error 2
root@yafeng-VirtualBox:/examples/scull# 

解决方法:根据提示,我们来到main.c文件。将#include <linux/config.h>直接删掉即可,因为config.h这个头文件貌似在2.6.19的内核版本后就没有了。

三.走着:

root@yafeng-VirtualBox:/examples/scull# make
make -C /lib/modules/3.0.0-12-generic/build M=/examples/scull LDDINC=/examples/scull/../include modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
  CC [M]  /examples/scull/main.o
/examples/scull/main.c:555:2: error: unknown field ‘ioctl’ specified in initializer
/examples/scull/main.c:555:2: warning: initialization from incompatible pointer type [enabled by default]
/examples/scull/main.c:555:2: warning: (near initialization for ‘scull_fops.aio_read’) [enabled by default]
/examples/scull/main.c: In function ‘scull_init_module’:
/examples/scull/main.c:651:3: error: implicit declaration of function ‘init_MUTEX’ [-Werror=implicit-function-declaration]
cc1: some warnings being treated as errors

make[2]: *** [/examples/scull/main.o] Error 1
make[1]: *** [_module_/examples/scull] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-12-generic'
make: *** [modules] Error 2

这里有两个错误:

1.ioctl。

因为在内核2.6.36中已经完全删除了struct file_operations中的ioctl函数指针,取而代之的是unlocked_ioctl。

这种改动在应用程序中是兼容的,但是在驱动程序中,我们可以发现,两者是不能兼容的,参数中少了inode,所以在驱动程序中必须加以改变,不然就会影响cmd参数的变化。

int scull_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

long scull_ioctl (struct file *filp, unsigned int cmd, unsigned long arg);

解决办法:1.就是将源代码中的scull_ioctl的函数头改为上面的第二种形式。

2.所有file_operations结构体中的ioctl函数指针。改为unlocked_ioctl。

改动比较多,各个.c和.h文件中几乎都会涉及到。

2.init_MUTEX.

在2.6.24的内核中,我们可以发现如下定义:

static inline void init_MUTEX (struct semaphore *sem) 
{ 
        sema_init(sem, 1); 
}

但是在2.6.25以后就已经不再使用这个宏了。

解决方法:我们就直接用sema_init(struct semaphore *sem, int val);来代替它。

同样这里的改动比较多,因而还是要仔细一点。

四.坚持着:

root@yafeng-VirtualBox:/examples/scull# make
make -C /lib/modules/3.0.0-12-generic/build M=/examples/scull LDDINC=/examples/scull/../include modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
  CC [M]  /examples/scull/main.o
  CC [M]  /examples/scull/pipe.o
/examples/scull/pipe.c: In function ‘scull_p_read’:
/examples/scull/pipe.c:131:7: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
/examples/scull/pipe.c:131:7: note: each undeclared identifier is reported only once for each function it appears in
/examples/scull/pipe.c:131:3: error: implicit declaration of function ‘signal_pending’ [-Werror=implicit-function-declaration]
/examples/scull/pipe.c:131:3: error: implicit declaration of function ‘schedule’ [-Werror=implicit-function-declaration]
/examples/scull/pipe.c: In function ‘scull_getwritespace’:
/examples/scull/pipe.c:168:38: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
/examples/scull/pipe.c: In function ‘scull_p_write’:
/examples/scull/pipe.c:219:2: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
/examples/scull/pipe.c:223:34: error: ‘SIGIO’ undeclared (first use in this function)
/examples/scull/pipe.c:223:41: error: ‘POLL_IN’ undeclared (first use in this function)
cc1: some warnings being treated as errors

make[2]: *** [/examples/scull/pipe.o] Error 1
make[1]: *** [_module_/examples/scull] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-12-generic'
make: *** [modules] Error 2

看错误提示,这里主要就是TASK_INTERRUPTIBLE宏没有定义。这是最好办的。

解决方法:到源码中rgrep一下呗,看它在哪个头文件中,就将它加上。

一般来说,系统的源代码都会放在:/usr/src/XXX-generic目录下。

最后,发现TASK_INTERRUPTIBLE定义在linux/sched.h中;因而,只需要在需要的.c文件中添加#include <linunx/sched.h>即可。

五.胜利就在眼前:

make -C /lib/modules/3.0.0-12-generic/build M=/examples/scull LDDINC=/examples/scull/../include modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
  CC [M]  /examples/scull/access.o
/examples/scull/access.c:99:34: error: ‘SPIN_LOCK_UNLOCKED’ undeclared here (not in a function)
/examples/scull/access.c: In function ‘scull_u_open’:
/examples/scull/access.c:107:29: error: ‘struct task_struct’ has no member named ‘uid’
/examples/scull/access.c:108:29: error: ‘struct task_struct’ has no member named ‘euid’
/examples/scull/access.c:115:26: error: ‘struct task_struct’ has no member named ‘uid’
/examples/scull/access.c: In function ‘scull_w_available’:
/examples/scull/access.c:166:27: error: ‘struct task_struct’ has no member named ‘uid’
/examples/scull/access.c:167:27: error: ‘struct task_struct’ has no member named ‘euid’
/examples/scull/access.c: In function ‘scull_w_open’:
/examples/scull/access.c:185:26: error: ‘struct task_struct’ has no member named ‘uid’
/examples/scull/access.c: In function ‘scull_w_available’:
/examples/scull/access.c:169:1: warning: control reaches end of non-void function [-Wreturn-type]
make[2]: *** [/examples/scull/access.o] Error 1
make[1]: *** [_module_/examples/scull] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-12-generic'
make: *** [modules] Error 2

这里也是有两个问题哦。

1.struct task_struct。

错误提示没有uid和euid。查看源代码发现还真没有,不过觉得有点不可思议。继续搜索……发现在2.6.35内核中,就将这两个成员放到const struct cred *cred成员中了 。也就是被降级了。

解决方法:很好办,只要像下面一样,在uid和euid引用的地方再加一层cred,不就OK了。

current->uid-----》current->cred->uid
current->euid-----》current->cred->euid

2.SPIN_LOCK_UNLOCKED

很明显,这又是一个未定宏的错误。但是我们又发现了这个宏在2.6.19的内核中就已经被弃用.

解决方法:在我们3.0.0.12的内核中要换一个宏来代替它----DEFINE_SPINLOCK(X);替代方法如下:

static spinlock_t scull_u_lock = SPIN_LOCK_UNLOCKED;----> static DEFINE_SPINLOCK(scull_u_lock);

注意要在每个.c文件中都将SPIN_LOCK_UNLOCKED进行如上替换。

六.阳光总在风雨后:

root@yafeng-VirtualBox:/examples/scull# make
make -C /lib/modules/3.0.0-12-generic/build M=/examples/scull LDDINC=/examples/scull/../include modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-12-generic'
  CC [M]  /examples/scull/main.o
  CC [M]  /examples/scull/pipe.o
  CC [M]  /examples/scull/access.o
  LD [M]  /examples/scull/scull.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /examples/scull/scull.mod.o
  LD [M]  /examples/scull/scull.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.0.0-12-generic'

经过这么多的修改,终于将scull编译好了。

接下来,你就可以用实验来好好巩固你在书本上看到的知识了哦!以后我也可以用这个来讲解驱动知识了,不会那么的枯燥。

最后,我们来看看如何加载scull。

看到有scull_load和scull_unload了吧。对的,加载就用scull_load,反之卸载就用scull_unload。

要是两个文件没有执行权限的,就先给他们chmod一个执行权限哦!加载后如下所示:

root@yafeng-VirtualBox:/examples/scull# chmod +x scull_*
root@yafeng-VirtualBox:/examples/scull# ls
access.c  main.c  Makefile       Module.symvers  pipe.o   scull.init  scull_load   scull.mod.o  scull_unload
access.o  main.o  modules.order  pipe.c          scull.h  scull.ko    scull.mod.c  scull.o
root@yafeng-VirtualBox:/examples/scull# ./scull_load
root@yafeng-VirtualBox:/examples/scull# 

用cat /proc/devices应该就能scull*的几项打印,这就说明设备已经挂载好了。

当不使用scull时,就指向scull_unload文件。即可卸载。

好了,今天就先讲到这了,以后有机会,就讲讲用scull实验的情况。