Linux 驱动开发内核模块的添加

今天从网上看了个视频教程,关于内核模块开发的。网络上有许多这样的文章,应该比我这个详细。

写这篇博客的目的是做一下笔记,便于自己查阅。

首先给出内核模块源代码,当然是最最简单的helloworld。

   #include <linux/init.h>   

   #include <linux/module.h>   

     

   MODULE_LICENSE("GPL");  //GPL 开源协议

    

    static int hello_init(void)  

   {  

        printk(KERN_ALERT "hello module!\n");  //内核打印信息函数,相当于应用层的printf();

     return 0;  

}  

 

 static void hello_exit(void)  

{  

   printk(KERN_ALERT "bye module!\n");  

 }  

  

 module_init(hello_init);  //必须使用的,模块加载函数。向内核注册

 module_exit(hello_exit);  //必须使用的,模块卸载函数注册


需要的Makefile

ifneq ($(KERNELRELEASE),)    //判断KERNELRELEASE不能与NULL

obj-m:=hello.o   //目标模块的名称

else

#generate the path

CURRENT_PATH:=$(shell pwd)  //获得当前目录的名称并赋值给CURRENT_PATH变量

#the absolute path  // 是用绝对路径

LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build      //内核模块所依赖的内核编译路径,shell uname -r获得当前内核版本号

#complie object

default:

make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules //make -C 表示到$(LINUX_KERNEL_PATH)使用它的makefile编译。

                                                                                                                             //M=$(CURRENT_PATH)表示你的内核源代码的位置

                                                                                                                             // modules :编译成为模块

clean:

make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

endif

编译一次内核模块需要两次执行上述makefile,第一次执行的时候KERNELRELEASE是没有值得,第二次执行时KERNELRELEASE是有值得。需要

注意此处



如果多个C文件进行的编译一个内核模块。Makefile则需要写为如下格式


ifneq ($(KERNELRELEASE),)    //判断KERNELRELEASE不能与NULL

obj-m:=hello.o   //目标模块的名称

hello.o-objs :=file1.o file2.o file3.o  ...  //(可以最近多个)       ------>如果一个源文件可以用这个方式生产与文件名不同的内核模

else

#generate the path

CURRENT_PATH:=$(shell pwd)  //获得当前目录的名称并赋值给CURRENT_PATH变量

#the absolute path  // 是用绝对路径

LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build      //内核模块所依赖的内核编译路径,shell uname -r获得当前内核版本号

#complie object

default:

make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules //make -C 表示到$(LINUX_KERNEL_PATH)使用它的makefile编译。

                                                                                                                             //M=$(CURRENT_PATH)表示你的内核源代码的位置

                                                                                                                             // modules :编译成为模块

clean:

make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

endif


编译得到hello.ko,然后insmod hello.ko加载模块,rmmod hello卸载模块。

查看内核模块lsmod

modprobe hello:也是加载一个模块,但是不同于insmod的是,它会在/lib/modules/$<$version>/modules.dep查看要加载的模块,看

是否依赖于其他的模块,如果有modprobe会先找到那些被依赖模块并先安装它们。

--------------------------------华丽的分割线---------------------------------------

内核参数

1.定义模块参数的方法:

            module_param(name, type, perm);

            其中,name:表示参数的名字;
     type:表示参数的类型;
     perm:表示参数的访问权限;


       static int num=10;
module_param(num,int,S_IRUGO);
static int hello_init(void)
{
    printk("Hello module init./n");
    printk("num=%d/n",num);
    return 0;
}
static void   hello_exit(void)
{
    printk("Goodbye module exit./n");
}
module_init(hello_init);
module_exit(hello_exit);

       MODULE_LICENSE("GPL");

       MODULE_DESCRIPTION("a simple module");
MODULE_ALIAS("hello");

shell    $ insmod hello.ko  num=100 即可改变num的值。

-------------------------------------------华丽分割线-----------------------------------

内核模块符号导出

    EXPORT_SYMBOL(函数名/变量名

      即当一个内核模块调用另外一个内核模块的函数或者变量时,需要再被调用的内核模块中将变量或者函数使用EXPROT_SYMBOL 将对应函数或者变量导出,才能

正常使用。关于这部分内容网络上有许多博文,具体使用时请参考其他博文吧。


----------------------------华丽分割线----------------------------------------------

内核打印&级别。

/proc/sys/kernel/printk中定义着其他控制台和其他log文件的打印级别。

其他的就不再赘述了,网上有很多博文了。

-----------------------------------华丽结束线-----------------------------------




发布了26 篇原创文章 · 获赞 39 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章