现在的位置: 首页 > 综合 > 正文

Linux 设备驱动helloworld.ko的制作过程

2018年08月16日 ⁄ 综合 ⁄ 共 2233字 ⁄ 字号 评论关闭

一. 源程序

hello.c

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

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ChangZhi");

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

static void hello_exit(void)
{
        printk(KERN_ALERT "GoodBye, cruel Workd!\n");
}

module_init(hello_init);
module_exit(hello_exit);

     (1) moudle.h 包含了大量加载模块需要的函数和符号的定义.
     (2) init.h 来指定你的初始化和清理函数
     (3) MODULE_LICENSE("GPL");指定代码使用哪个许可
           内核认识的特定许可有, 
                "GPL"( 适用 GNU 通用公共许可的任何版本 ), 
                "GPL v2"( 只适用 GPL 版本 2 ), 
                "GPL and additional rights", 
                "Dual BSD/GPL", 
                "Dual MPL/GPL", 
                "Proprietary".
    (4) 除此之外还可以包含模块的其他描述性定义
          MODULE_AUTHOR ( 声明谁编写了模块 ), 
          MODULE_DESCRIPION( 一个人可读的关于模块做什么的声明 ), MODULE_VERSION ( 一个代码修订版本号),
          MODULE_ALIAS ( 模块为人所知的另一个名子 ), 
          MODULE_DEVICE_TABLE ( 来告知用户空间, 模块支持那些设备).
    (5) static int hello_init(void)
             初始化函数应当声明成静态的,
          static void hello_exit(void) 
               清理函数, 它注销接口, 在模块被去除之前返回所有资源给系统
    (6) module_init(hello_init);
           这个宏定义增加了特别的段到模块目标代码中, 表明在哪里找到模块的初始化函数. 没有这个定义, 你的初始化函数不会被调用.
           module_exit(hello_exit);
    (7)printk
            在 Linux 内核中定义并且对模块可用; 它与标准 C 库函数 printf 的行为相似. 内核需要它自己的打印函数, 因为它靠自己运行
    (8)字串 KERN_ALERT 是消息的优先级,因为使用缺省优先级的消息可能不会在任何有用的地方显示

二. Makefile

obj-m := hello.o
  
all: 
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 

注意:make前面是TAB,不是空格。

      (1)obj-m := hello.o

              表明有一个模块要从目标文件 hello.o 建立. 在从目标文件建立后结果模块命名为 hello.ko。

      (2)KERNELDR := /usr/src/linux-2.6.26

              用来定位内核源码目录

      (3)PWD := $(shell pwd)

             获得当前目录路径

      (4)M=$(PWD) M= 选项

              使 makefile 在试图建立模块目标前, 回到你的模块源码目录

      (5)$(MAKE) -C $(KERNELDR) M=$(PWD) modules

              这个命令开始是改变它的目录到用 -C 选项提供的目录下( 就是说, 你的内核源码目录 ). 它在那里会发现内核的顶层 makefile. 这个 M= 选项使 makefile 在试图建立模块目标前, 回到你的模块源码目录. 这个目标, 依次地, 是指在 obj-m 变量中发现的模块列表, 在我们的例子里设成了 module.o.


下面的版本要对应:

[root@changzhi moudle]# rpm -qa| grep kernel-header
kernel-headers-2.6.32-220.el6.x86_64
[root@changzhi moudle]# uname -r
2.6.32-220.el6.x86_64

      

三. 执行

    1. insmod
          加载模块的代码段和数据段到内核,并且调用模块的初始化函数来启动所有东西.
     2. rmmod
          如果内核认为模块还在用( 就是说, 一个程序仍然有一个打开文件对应模块输出的设备 ), 或者内核被配置成不允许模块去除, 模块去除会失败.
     3. lsmod 
         生成一个内核中当前加载的模块的列表. lsmod 通过读取 /proc/modules 虚拟文件工作. 当前加载的模块的信息也可在位于 /sys/module 的 sysfs 虚拟文件系统找到.

     insmod和rmmod的时候可以在/var/log/messages中看到。

抱歉!评论已关闭.