linux_driver_module

linux device driver tutorial

The first driver:

loading and removing the driver in user space
nothing.c

#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

Makefile

obj-m := nothing.o

compile and test:

$make -C /usr/src/linux-headers-3.16.7-ckt5my-very-own-kernel M=`pwd` modules

或者

make -C /lib/modules/`uname -r`/build M=`pwd` modules

out:

make: Entering directory `/usr/src/linux-lts-utopic-3.16.0'
  CC [M]  /home/wonfee/wonfee/linux/driver-tutorial/nothing/nothing.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/wonfee/wonfee/linux/driver-tutorial/nothing/nothing.mod.o
  LD [M]  /home/wonfee/wonfee/linux/driver-tutorial/nothing/nothing.ko

  sudo insmod nothing.ko
  lsmod |grep nothing
  nothing                 8255  0
  sudo rmmod nothing

The “Hello world” driver:

loading and removing the driver in kernel space
hello.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_DEBUG "Hello World !!!\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_DEBUG "Bye bye !!!\n");
}

module_init(hello_init);
module_exit(hello_exit);

make -C /usr/src/linux-headers-3.16.7-ckt5my-very-own-kernel M=`pwd` modules

make: Entering directory `/usr/src/linux-lts-utopic-3.16.0'
  CC [M]  /home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "mcount" [/home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.ko] undefined!
  CC      /home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.mod.o
  LD [M]  /home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.ko
make: Leaving directory `/usr/src/linux-lts-utopic-3.16.0'

sudo insmod hello.ko

insmod: ERROR: could not insert module hello.ko: Unknown symbol in module

dmesg |tail

...
[21684.565795] hello: Unknown symbol mcount (err 0)

加载内核模块出错,网上说是gcc 版本问题,当前使用的gcc是软链接到gcc-4.4,这是之前为了编译android源码时将gcc从4.8降到了4.4,重新将gcc链接到4.8:
gcc -v

gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

make -C /usr/src/linux-headers-3.16.7-ckt5my-very-own-kernel/ M=`pwd` modules

make: Entering directory `/usr/src/linux-lts-utopic-3.16.0'
  CC [M]  /home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.mod.o
  LD [M]  /home/wonfee/wonfee/linux/driver-tutorial/helloworld/hello.ko
make: Leaving directory `/usr/src/linux-lts-utopic-3.16.0'

sudo insmod hello.ko
dmesg |tail -n 1

[22644.697688] Hello World !!!

sudo rmmod hello
dmesg |tail -n 1

[22663.379104] Bye bye !!!

Makefile

//------------ General Makefile------------------
 obj-m := hello.o
 KERNELDIR := /lib/modules/$(shell uname -r)/build
 PWD := $(shell pwd)
 modules:
     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

编译模块,可以使用如下两种方式:

$make -C /usr/src/linux-xxx M=`pwd` modules

$make -C /lib/modules/uname -r/build M=pwd modules

两者效果相同, 只是使用的源码路径不一样,usr/src目录下那个源代码一般是我们自己下载后解压的或者系统更新时下载的,而lib目录下的则是在编译时自动copy过去的,两者其实是完全一样的。