• hello 内核模块


    #ifndef __KERNEL__
    #  define __KERNEL__
    #endif
    #ifndef MODULE
    #  define MODULE
    #endif
    
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/init.h>
    
    MODULE_LICENSE("GPL");
    
    static int year=2013;
    
    MODULE_PARM(year,"i");
    
    int hello_init()
    {
    	printk(KERN_WARNING"Hello World %d!
    ",year);
    	return 0;
    }
    
    
    void hello_exit()
    {
    	printk("Hello Exit!
    ");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    

    1.在包含任何头文件前,必须先预定义符号__KERNEL__,这个符号用于控制选择头文件的哪一部分。

    2.另一个很重要的符号就是MODULE,必须在包含<linux/module.h>前定义这个符号,它用于告诉头文件,这是一个模块,如果编译进内核,必须去掉该定义。

    3.模块加载函数(必需):安装模块时被系统自动调用的函数,通过module_init宏来指定。

    4.模块卸载函数(必需):卸载模块时被系统自动调用的函数,通过module_exit宏来指定。

    5.许可证申明(可选):宏MODULE_LICENSE被用来告知内核,该模块带有一个许可证,没有这样的说明,加载模块时内核会抱怨。有效的许可证有"GPL","GPL v2","GPL and additional rights","Dual BSD/GPL","Dual MPL/GPL"和“Proprietary"。

    6.模块参数(可选):通过宏MODULE_PARM指定模块参数,模块参数用于在加载模块时传递参数给它。

        MODULE_PARM(name,type)有两个参数,name是模块参数的名称type是这个参数的类型,类型包括以下几种:

    b:比特型    h:短整型    i:整型    l:长整型    s:字符串型

       在传递字符串型的参数时,这个模块参数需要在模块中用char* 来声明,系统会自动为其分配内存空间。

       例如:

           int a = 3;

           char* st;

           MODULE_PARM(a,"i");

           MODULE_PARM(st,"s");

    7.模块的编译工作由gcc -c 命令来完成。例如:

    #gcc -c -I/usr/src/linux-headers-2.6.32-48/include hello.c

    8.加载 insmod    (insmod hello.o)

    9.卸载 rmmod    (rmmod hell)

    10.查看 lsmod

    11.加载 modprobe

        modprobe如同insmod,也是加载一个模块到内核。它的不同之处在于它会查看要加载的模块,看它是否还依赖于其他模块,如果是modprobe找到这些模块,把他们先加载到内核。

    12.为了确定模块是否可以被安全的卸载了,系统为每个模块保留了一个使用计数(lsmod可查看),用于记录正在使用该模块的用户数,只有当使用计数=0时,模块才可以被卸载。

     以下3个宏在内核中用来维护使用计数:

           MOD_INC_USE_COUNT:模块计数加1

           MOD_DEC_USE_COUNT:模块计数减1

           MOD_IN_USE:模块计数非0时返回真


    内核模块开发过程中需特别注意以下几点:

    1.在使用gcc编译模块时使用-c编译选项

    2.在gcc编译选项中定义宏:_DMODULE和 -D__KERENL__

    或直接在源文件中定义这两个宏:

      #define MODULE

      #define __KERNEL__

    3.在使用gcc编译内核模块时,需要通过增加编译选项:-I/XXX/include  来指定内核源代码的头文件目录,并且还要保证内核源代码必须是配置过(make menuconfig),make dep过的。

    注:XXX代表内核源代码的绝对路径,如:/usr/src/linux-headers-2.6.32-48/

    4.版本不匹配

       内核模板的版本是由其所依赖的内核源代码版本所决定的,位于内核源代码所处的顶层Makefile中,如:

    VERSION = 3
    PATCHLEVEL = 9
    SUBLEVEL = 2
    EXTRAVERSION =

      当此版本与正在运行的内核版本(可通过uname -r 查询)不一致时,内核模块将无法插入内核。

    解决办法:

    1.使用insmod -f  强行插入

    2.修改内核源代码顶层Makefile中的版本信息来与uname -r查看到的一致。

  • 相关阅读:
    Java面试题
    verilog之锁存器和触发器
    verilog基本语法之always和assign
    verilog之基本结构
    ZYNQ7000系列学习之TF卡读写实验
    英语文档阅读学习系列之ZYNQ-7000 All Programmable SOC Packaging and Pinout
    物理之纳电子
    英语文档阅读学习系列之Zynq-7000 EPP Software Developers Guide
    嵌入式C语言设计学习
    ZYNQ7000系列学习之自定义模块构成IP
  • 原文地址:https://www.cnblogs.com/wangfengju/p/6173025.html
Copyright © 2020-2023  润新知