zoukankan      html  css  js  c++  java
  • 《Linux4.0设备驱动开发详解》笔记第四章:Linux内核模块

    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);
    • 对于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 ...
  • 相关阅读:
    Django基础
    PostMan打不开怎么解决
    Beyond Compare 4.x(含4.3.3)专业版独家破解(附激活密钥以及注册机,全网独家可用)
    详细安装教程(视频版)
    经典排序算法及总结(python实现)
    Django开发常用方法及面试题
    C:UsersKellyAppDataRoaming pm-cache\_logs2019-03-24T08_17_24_284Z-debug.log
    vue项目搭建和开发流程 vue项目配置ElementUI、jQuery和Bootstrap环境、跨域问题
    970.强整数
    9_11 bootstarp使用
  • 原文地址:https://www.cnblogs.com/zcjboke/p/5513139.html
Copyright © 2011-2022 走看看