您的位置:首页 > 运维架构 > Linux

《Linux4.0设备驱动开发详解》笔记--第四章:Linux内核模块

2016-05-18 11:03 435 查看

4.1 内核模块程序结构

加载:insmod,modprobe(同时加载模块的依赖模块)

卸载:rmmod

查看已加载的模块及模块间的依赖关系:lsmod,实际上是分析/proc/modules文件

已加载的模块信息放在/sys/module目录下,没加载一个模块就会在该目录下生成一个以模块名命名的目录,“tree -a”可获取目录树

模块许可声明:申明许可权限,否则将收到内核被污染警告,一般申明为MODULE_LICENSE(“GPL v2”)语句申明采用GPL v2.

模块参数(可选):模块被加载的时候可以传递给它的值,它本身对对应模块的内部的全局变量

模块导出符(可选):其他模块可以使用模块导出的函数和变量

模块作者等信息声明

4.2 模块加载函数

Linux内核模块加载函数一般以__init标识申明,如

static int __init initialization_function(void)
{
/*初始化代码*/
}
module_init(initialization_function);


初始化成功返回0,否则返回错误码。

request_module(const char* fmt, …):灵活加载内核模块

数据也可以定义为__initdata,只是在初始化的阶段需要的数据,结束后释放占用的内存

4.4 模块卸载函数

一般以__exit标识申明,如

static void __exit cleanup_function(void)
{
/*释放代码*/
}
module_exit(cleanup_function);


被直接编译进内核的模块的卸载函数会被省略,不编译进内核,因为模块被内置了,也就不会被卸载。

4.5 模块参数

module_param(参数名,参数类型,参数读写权限):为模块定义一个参数,如下定义一个int参数和char指针参数

static char *book_name = "dissecting Linux Deice Driver";
module_param(book_name, char, S_IRUGO);

static int book_num = 4000;
module_param(book_num, int, S_IRUGO);


“insmod (或modprobe) 模块名 参数名 = 参数值”,不传递则用缺省值,模块被内置时用bootloader通过bootargs里设置“模块名.参数 = 值”给内置模块传递参数。

参数数组:module_param_array(数组名,数组类别,数组长度,参数读写权限)

/sys/module下有已加载模块命名的目录,当“参数读写权限”为0,则此参数不存在sysfs文件系统下对应的节点,否则此模块的目录下会出现parameter目录,其中包含以参数名命令的文件节点,文件权限与设定的权限一致。

允许insmod和modprobe命令时,用逗号隔开输入的数组元素

例:定义两个参数的模块

/*======================================================================
A kernel module: book
This example is to introduce module params

The initial developer of the original code is Baohua Song
<author@linuxdriver.cn>. All Rights Reserved.
======================================================================*/
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static char *book_name = "dissecting Linux Device Driver";
static int num = 4000;

static int book_init(void)
{
printk(KERN_INFO " book name:%s\n",book_name);
printk(KERN_INFO " book num:%d\n",num);
return 0;
}
static void book_exit(void)
{
printk(KERN_INFO " Book module exit\n ");
}
module_init(book_init);
module_exit(book_exit);
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);

MODULE_AUTHOR("Song Baohua, author@linuxdriver.cn");
MODULE_DESCRIPTION("A simple Module for testing module params");
MODULE_VERSION("V1.0");


通过insmod加参数和不加参数实验,在/var/log/messages文件中查看内核的输出

在/sys/module/book/parameters目录下输入tree查看参数文件节点

4.6 导出符号

/proc/kallsyms文件记录了符号及符号所在的内存地址

导出符号:EXPORT_SYSBOL(符号名),EXPORT_SYSBOL_GPL(符号名)(只适用于包含GPL许可权的模块)

例:

/*======================================================================
A simple kernel module to introduce export symbol

The initial developer of the original code is Baohua Song
<author@linuxdriver.cn>. All Rights Reserved.
======================================================================*/
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

int add_integar(int a,int b)
{
return a+b;
}

int sub_integar(int a,int b)
{
return a-b;
}

EXPORT_SYMBOL(add_integar);
EXPORT_SYMBOL(sub_integar);


4.7 模块申明与描述

MODULE_AUTHOR(author);

MODULE_DESCRIPTION(description);

MODULE_VERSION(version_string);

MODULE_DEVICE_TABLE(table_info);

MODULE_ALIAS(alternate_name);

对于
4000
USB, PCI等设备驱动,通常创建一个MODULE_DEVICE_TABLE来表明驱动模块支持的设备

4.8 模块的使用计数

try_module_get(&module)和module_put(&module):模块计数管理接口

try_module_get(&module):增加模块使用计数,返回0,调用失败,希望使用的的模块不存在或正在被卸载

module_put(&module):减少模块使用计数

模块的使用计数一般不由模块本身管理,由内核更底层的代码(总线驱动或者此类设备共用的核心模块)来实现,以简化驱动开发

当设备正在使用的时候,模块不可以被卸载

4.9 模块编译

Makefile

模块包含多个.c文件,则Makefile写法

obj-m := modulename.o
modulename-objs := file1.o file2.o ...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux kernel