• liunx驱动----构造和运行模块


    以hello world模块为例

    #include <linux/init.h>
    #include <linux/module.h>
    
    
    
    //在执行  insmod hlello 的时候会被调用
    static int hello_init(void)
    {
    
        printk(KERN_ALERT"hello_init
    ");
        return 0;
    }
    
    
    //在执行  rmmod hlello 的时候会被调用
    static void hello_exit(void)
    {
        printk(KERN_ALERT"hello_exit
    ");    
    }
    
    MODULE_LICENSE("GPL");//添加自由许可证
    module_init(hello_init);
    module_exit(hello_exit);
    KERN_ALERT:是用来定义这条消息的优先级的。声明在:kernel.h  includelinuxkernel.h中声明
    #define    KERN_EMERG    "<0>"    /* system is unusable    (紧急情况,系统可能会崩溃)        */
    #define    KERN_ALERT    "<1>"    /* action must be taken immediately(必须立即响应)    */
    #define    KERN_CRIT    "<2>"    /* critical conditions   (临界情况)         */
    #define    KERN_ERR    "<3>"    /* error conditions        (错误信息)    */
    #define    KERN_WARNING    "<4>"    /* warning conditions    (警告信息)        */
    #define    KERN_NOTICE    "<5>"    /* normal but significant condition( 普通的但可能需要注意的信息)    */
    #define    KERN_INFO    "<6>"    /* informational         (提示性信息)   */
    #define    KERN_DEBUG    "<7>"    /* debug-level messages   (调试信息)         */

    Makfile:

    KERN_DIR = /work/system/linux-2.6.22.6   //内核路径
    
    all:
            make -C $(KERN_DIR) M=`pwd` modules
    
    clean:
            make -C $(KERN_DIR) M=`pwd` modules clean
            rm -rf modules.order
    
    obj-m   += helloworld.o         //编译成helloworld.o

    make输出信息:

    make -C /work/system/linux-2.6.22.6 M=`pwd` modules
    make[1]: Entering directory `/work/system/linux-2.6.22.6'
      CC [M]  /home/book/work/nfs_root/first_fs/work/helloworld/helloworld.o
      Building modules, stage 2.
      MODPOST 1 modules
      CC      /home/book/work/nfs_root/first_fs/work/helloworld/helloworld.mod.o
      LD [M]  /home/book/work/nfs_root/first_fs/work/helloworld/helloworld.ko
    make[1]: Leaving directory `/work/system/linux-2.6.22.6'

    从输出信息中可以看出 ,最终的目的是生成了  helloworld.ko 这个文件 

    运行结果:

    为什么需要使用printk 函数来打印了?

      在模块运行过程中,不能依赖于c库,模块能够调用printk是因为在 insmod函数装入模块后,模块就链接到了内核中。所以就能访问公用的符号(printk)

    为什么模块需要初始化?

      模块初始化的目的就是为了以后调用模块中的函数做准备。

    设备驱动程序如何引用当前进程?

      在设备驱动程序中只需要包含<linux/sched.h>头文件即可引用当前进程。例如  通过访问  Staruc task_staruct  成员变量答应当前的命令名称。和进程ID

      分别在装载和卸载调用中添加两条打印语句:printk(KERN_INFO"The process is "%s"(pid %i) ",current->comm,current->pid)        

      打印出当前命令名进程ID

    //在执行  insmod hlello 的时候会被调用
    static int hello_init(void)
    {
    
        printk(KERN_ALERT"hello_init
    ");
        printk(KERN_INFO"The process is "%s"(pid %i)
    ",current->comm,current->pid);
        return 0;
    }
    
    
    //在执行  rmmod hlello 的时候会被调用
    static void hello_exit(void)
    {
        printk(KERN_ALERT"hello_exit
    ");    
        printk(KERN_INFO"The process is "%s"(pid %i)
    ",current->comm,current->pid);
    }

    运行状态如下:

    模块参数:

    由于系统不同,所以驱动程序需要的参数也会发生变化,其中包括设备编号以及其他一些用来控制驱动程序操作方式的参数。

      为了满足这个需求,内核允许对驱动程序指定参数,而这些参数可在装载驱动模块是发生改变。

    在insmod改变模块参数之前,模块必须让这些参数对insmod命令可见(可操作)。必须使用module_param 宏来声明,在moduleparm.h中定义

    module_param 需要三个参数: 变量名称      类型    用于sysfs入口项的访问许可掩码。

    代码如下:

    static char *param_string = "hello";//一个名字为param_string 的指针变量
    static int     print_cont =1;   //int  型变量
    
    
    module_param(param_string, charp, S_IRUGO);//使用module_param宏来让param_string变量对insmod 命令可见
    module_param(print_cont, int, S_IRUGO);//同上
    
    
    //在执行  insmod hlello 的时候会被调用
    static int hello_init(void)
    {
        int i;
        printk(KERN_ALERT"hello_init
    ");
        printk(KERN_INFO"The process is "%s"(pid %i)
    ",current->comm,current->pid);
        for(i= 0 ;i < print_cont; i++)             //根据变量打印对应的次数
        printk(KERN_ALERT"%s
    ",param_string);  //打印
        return 0;
    }
    
    
    //在执行  rmmod hlello 的时候会被调用
    static void hello_exit(void)
    {
        printk(KERN_ALERT"hello_exit
    ");    
        printk(KERN_INFO"The process is "%s"(pid %i)
    ",current->comm,current->pid);
    }
    
    MODULE_LICENSE("GPL");//添加自由许可证
    module_init(hello_init);
    module_exit(hello_exit);

    运行结果:

    内核模块支持参数类型:

    bool 

    invbool(反转其值,true变为false  false 变为true)

    charp  字符指针值,内核会给字符串分配内存,并相应设置指针。

    int 

    long

    short

    uint

    ulong

    ushort

  • 相关阅读:
    android 自定义Dialog
    【Head First Java 读书笔记】(四)对象的行为
    【Head First Java 读书笔记】(三)primitive主数据类型和引用
    【Android学习】自定义checkbox
    【Java】java中的compareTo和compare的区别
    【Java】对Map按key和value分别排序
    【Andoid学习】GridView学习
    【实习项目记录】(三)调整网络图片固定宽高
    【实习项目记录】(二) JSON
    【实习项目记录】(一)加密算法MD5和RSA
  • 原文地址:https://www.cnblogs.com/hjxzjp/p/10765443.html
Copyright © 2020-2023  润新知