zoukankan      html  css  js  c++  java
  • linux驱动(一)

    编写模块必须先声明下面两句:

    #include <linux/module.h>               //这个头文件包含了许多符号与函数的定义,这些符号与函数多与加载模块有关

    #include <linux/init.h>                      //这个头文件包含了你的模块初始化与清除的函数

    另外,如果你的模块需要用到参数传递,那么你可能就要声明moduleparam.h这个头文件了。

    再者,模块里常包含一些描述性声明,如:

    MODULE_LICENSE("GPL");          // "GPL" 是指明了 这是GNU General Public License的任意版本

                                                                // “GPL v2” 是指明 这仅声明为GPL的第二版本

                                                                // "GPL and addtional"

                                                                // "Dual BSD/GPL"

                                                                // "Dual MPL/GPL"

                                                                // "Proprietary"  私有的

                                                                // 除非你的模块显式地声明一个开源版本,否则内核会默认你这是一个私有的模块(Proprietary)。

    MODULE_AUTHOR                        // 声明作者

    MODULE_DESCRIPTION              // 对这个模块作一个简单的描述,这个描述是"human-readable"的

    MODULE_VERSION                        // 这个模块的版本

    MODULE_ALIAS                               // 这个模块的别名

    MODULE_DEVICE_TABLE            // 告诉用户空间这个模块支持什么样的设备

    MODULE_声明可以写在模块的任何地方(但必须在函数外面),但是惯例是写在模块最后。      

    驱动程序的作用:

    简单来说 驱动程序就是使计算机与设备通信的特殊的代码,在作单片机时候(无OS)我们自己定义接口及自定义的结构来操作相关硬件,

    而在有OS的模式下我们操作的硬件是去实现对应的接口(这些接口是已定义好的,我们需要实现这些接口)而无需自己定义接口,这样既能正确的控制设备。

    又能很好的维护(如果需要升级驱动,上边的应用程序不需要改变)

    驱动分类:

    1. 字符设备:能够像字节流(类似文件)一样被访问的设备(至少实现open, close, read ,write等功能)
    2. 快设备:    用户空间接口与字符设备相同, 内部实与字符设备完全不同(可以被随即访问,一般在类UNIX系统中快设备的读取每次只能读一整块在linux可以操作任意字节)
    3. 网络设备:网络通路通过网络设备形成,能够与主机交换数据的设备

    内核功能划分:

    1. 进程管理(PM):进程的创建与撤销,在单个或者多个CPU上实现多进程的抽象
    2. 内存管理(MM):管理内存分配及回收的策略
    3. 文件系统(FS/VFS): Linux 非常依赖于文件系统,内核在没有结构的硬件系统上构造结文件系统,而文件抽象在整个系统中会广泛使用,Linux支持多种文件系统类型
    4. 设备控制:驱动程序,操控硬件以及相应总线设备
    5. 网络(NET): 在网络接口于应用程序之间传输数据。

    好了 理论行得东西介绍的差不多了,下边说点有用的,内核的驱动可以做成模块在需要的时候装载,在不需要的时候卸载
    我们在编写用户程序的时候总喜欢从编写hello world 写起 , 在内核驱动模块也是一样,下边是一个hello_world的一个模块

     
    1. //hello_world.c   
    2. #include <linux/init.h>   
    3. #include <linux/module.h>  
    4. MODULE_LICENSE("GPL");   
    5.   
    6. static int hello_init(void)   
    7. {   
    8.     printk(KERN_ALERT "hello module ");   
    9.     return 0;   
    10. }   
    11.   
    12. static void hello_exit(void)   
    13. {   
    14.     printk(KERN_ALERT "hello module exit ");   
    15. }   
    16.   
    17. module_init(hello_init);   
    18. module_exit(hello_exit);  

    以及对应的Makefile

     
    1. ifneq ($(KERNELRELEASE),)   
    2. # call from kernel build system   
    3. obj-m   := hello_world.o   
    4. #if we need more than one source code to build the module  
    5. #we should use the variable below:  example: modules-objs := file1.o file2.o  
    6. modules-objs :=   
    7.   
    8. else  
    9. #kernel PTAH   
    10. KERNELDIR ?= /lib/modules/$(shell uname -r)/build   
    11. PWD       := $(shell pwd)   
    12.   
    13. modules:   
    14.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules   
    15.   
    16. endif   
    17.   
    18. clean:   
    19.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions  

    有几点与用户空间程序不同的地方

    1. 模块程序没有main函数(那么程序入口在哪里?)
    2. 打印函数使用的printk 而不是用户空间的printf 而且使用方式不一样
    3. 模块的编译不是通常的方式
    4. 头文件不是常见的那些头文件
    5. 以及编译之后不会产生可执行文件,而是 .ko 文件
      ...

    模块没有main函数,在装载模块 insmod 时会调用module_init注册的函数 此处为hello_init
    在模块卸载remod时 会调用module_exit注册的函数 此处为hello_exit
    在module_init 注册的函数主要是进行初始化,分配内存, 注册设备等
    而module_exit中注册的函数与之相反, 设备注销, 释放内存等
    具体的编译模块的Makefile我在另一篇文章中有说到 此处不再赘述
    内核的打印函数使用printk去打印信息, printk不支持浮点类型, 在printk中可以加入信息级别有7中

     
    1. #define KERN_EMERG    "<0>"    /* system is unusable */  
    2. #define KERN_ALERT    "<1>"    /* action must be taken immediately */  
    3. #define KERN_CRIT     "<2>"    /* critical conditions */  
    4. #define KERN_ERR      "<3>"    /* error conditions */  
    5. #define KERN_WARNING  "<4>"    /* warning conditions */  
    6. #define KERN_NOTICE   "<5>"    /* normal but significant */  
    7. #define KERN_INFO     "<6>"    /* informational */  
    8. #define KERN_DEBUG    "<7>"    /* debug-level messages */  

    对应与不同的错误等级 选择不懂的option, 并做不同的处理, 小于一定等级的信息会直接打印到终端(非X-window下的终端),可以使用dmesg来查看全部的打印信息
    编译内核的头文件是在/lib/modules/$(shell uname -r)/build/include下得,而不是用户模式下得/usr/include
    编译后不会生产可执行文件,会生成一个.ko的文件
    使用insmod xxx.ko去装载模块
    使用lsmod去查看已装载的模块
    使用rmmod xxx 去卸载相应模块(卸载是不带.ko)

    http://blog.csdn.net/jshazk1989/article/details/6918828

  • 相关阅读:
    微信小程序支付【前端】
    CSS主题切换
    利用Proxy写了个存储管理
    前端存储cookie操作
    canvas电子签名和播放划线
    【原创】[Ext.ux.UploadDialog] 控件使用说明及在Ext 3.x下问题解决
    【原创】分享一组VC++底层图像处理函数
    【转发】SQL Server数据库被质疑解决方案
    SVN 解决update失败出现乱码提示或工作副本已经锁定
    Qt 外部子模块的3种使用方法,以QtXlsx为例
  • 原文地址:https://www.cnblogs.com/yuankaituo/p/4389456.html
Copyright © 2011-2022 走看看