原创 建立和运行模块总结

2009-5-31 09:12 1665 5 5 分类: MCU/ 嵌入式








  1. LInux
    的方式看待设备可区分为 3
    种基本设备类型.可分类成字符模块,
    块模块和网络模块.


  2. 因为内核编程没有库连接到模块中,
    源文件不应当包含通常的头文件,驱动模块运行在内核空间,运行时不能依赖于任何函数库和模块连接,所以在写驱动时所调用的函数只能是作为内核一部分的函数。


  3. 要十分注意驱动程序的并发处理。


  4. 驱动模块和应用程序的一个重要不同是:应用程序退出时可不管资源释放或者其他的清除工作,但模块的退出函数必须仔细撤销初始化函数所作的一切,否则,在系统重新引导之前某些东西就会残留在系统中。


  5. 内核只有一个非常小的堆栈,你的函数必须与这个内核空间调用链共享这个堆栈.如果需要大的结构,
    在调用时应当采用动态分配.


  6. 你查看内核 API
    , 你会遇到以双下划线(__)开始的函数名.
    这通常是一个低层的接口组件,
    双下划线告诉程序员:"
    如果你调用这个函数,
    确信你知道你在做什么."


  7. 内核代码不能做浮点算术.


  8. Linux使用超级中断应当执行以下两条命令安装:




apt-get
install minicom


apt-get
install lrzsz #x|y|zmod






  1. 如果你编写一个模块想用来在多个内核版本上工作,
    可能只能使用宏定义和 #ifdef
    来使代码正确建立.
    在这样情况下, 你要利用在
    linux/version.h
    中发现的定义(UTS_RELEASELINUX_VERSION_CODEKERNEL_VERSION)




因此,
几乎所有模块代码都有下面内容:




#include
<linux/module.h>



#include
<linux/init.h>



  1. 所有模块代码都应该指定所使用的许可证:





MODULE_LICENSE("Dual
BSD/GPL"
);



此外还有可选的其他描述性定义:




MODULE_AUTHOR("");
MODULE_DESCRIPTION
("");
MODULE_VERSION
("");
MODULE_ALIAS
("");
MODULE_DEVICE_TABLE
("");



上述MODULE_声明习惯上放在文件最后。


  1. 初始化和关闭如下:




    static
    int __init initialization_function(void)
    {
    /



    Initialization
    code here



    /
    }
    module_init(initialization_function);


    static
    void __exit cleanup_function(void)
    {
    /



    Cleanup code here


    /
    }
    module_exit(cleanup_function);



  2. 不要轻言注册失败。要尽量妥善处理。



    struct
    something


    item1;
    struct
    somethingelse


    item2;
    int
    stuff_ok;
    void my_cleanup(void)
    {
    if (item1)

    release_thing(item1);
    if (item2)

    release_thing2(item2);
    if (stuff_ok)

    unregister_stuff( );
    return;
    }
    int __init
    my_init(void)
    {
    int err = -ENOMEM;
    item1 =
    allocate_thing(arguments);
    item2 =
    allocate_thing2(arguments2);
    if (!item2 || !item2)

    goto fail;
    err = register_stuff(item1, item2);
    if
    (!err)
    stuff_ok = 1;
    else
    goto fail;

    return 0; /



    success


    /

    fail:
    my_cleanup( );
    return err;
    }



  3. insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(即函数和变量的地址),这是实现模块化驱动程序所必须的。


  4. Linux使用模块层叠技术,我们可以将模块划分为多个层,通过简化每个层可缩短开发周期。如果一个模块需要向其他模块到处符号,则使用下面的宏:




EXPORT_SYMBOL(name);


EXPORT_SYMBOL_GPL(name);



符号必须在模块文件的全局变量部分导出,因为这两个宏将被扩展为一个特殊变量的声明,而该变量必须是全局的。


  1. 函数(
    __init
    __exit )和数据
    (__initdata
    __exitdata)的标记,
    只用在模块初始化或者清理时间.
    为初始化所标识的项可能会在初始化完成后丢弃;
    退出的项可能被丢弃如果内核没有配置模块卸载.
    这些标记通过使相关的目标在可执行文件的特定的
    ELF 节里被替换来工作.


  2. #include
    <linux/sched.h>” 
    最重要的头文件之一。包含驱动程序使用的大部分内核API的定义,包括睡眠函数以及各种变量声明。






PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条