• Linux内核驱动编程


    Linux内核驱动编程

    2015-02-12

    驱动程序基础的东西这儿就不罗嗦了,百度上有更好的资料,此处我们只是注重实际用处。

        下面我们开始写程序:

    一、初步helloword程序

    首先是来一个简单的hello。

    hello.c代码:

     1 /******************************
     2 
     3 the first program
     4 
     5 Hello World!
     6 
     7 ******************************/
     8 
     9 #include <linux/module.h>
    10 
    11 #include <linux/init.h>
    12 
    13  
    14 
    15 static int hello_init(void)
    16 
    17 {
    18 
    19 printk("<0>
    Hello, world!
    
    ");
    20 
    21 return 0;
    22 
    23 }
    24 
    25  
    26 
    27 static void hello_exit(void)
    28 
    29 {
    30 
    31 printk("<0>
    Goodbye,world 
    
    ");
    32 
    33 }
    34 
    35  
    36 
    37 module_init(hello_init);
    38 
    39 module_exit(hello_exit);
    40 
    41 MODULE_LICENSE("Dual BSD/GPL"); //Any version of public GNU license
    View Code

    Make代码:

     1 ifeq ($(KERNELRELEASE),)
     2 
     3 KERNELDIR ?= /home/study/system/linux-2.6.31
     4 
     5 PWD := $(shell pwd)
     6 
     7 modules:
     8 
     9 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    10 
    11 modules_install:
    12 
    13 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    14 
    15 clean:
    16 
    17 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
    18 
    19  
    20 
    21 else
    22 
    23 obj-m := hello.o
    24 
    25 endif
    View Code

    注意:

    ①:Makefile中的KERNELDIR ,这个linux源代码的版本是和你的开发板的一模一样,必须修改,否侧或有错误

    ②:该应用程序必须在开发板上运行,千万注意别再服务器操作系统使用,否则存在破坏系统的危险。

    接下来就是,编译->加载,使用以下命令

     1 make CROSS_COMPILE=arm-none-linux-gnueabi-
     2 
     3 //此处为修改为你操作系统上的gcc 交叉编译
     4 
     5 insmod hello.ko
     6 
     7 //加载模块,此时屏幕上会打印,hello,world
     8 
     9 rmmod hello.ko
    10 
    11 //卸载模块,同样会打印 goodsbye world

    接下来我们对其进行改进

    二、改进helloword程序,增加输入模块参数

    我们在代码中增加以下代码:

    1 static char *name = "LoverXue";
    2 
    3 static int age = 1;
    4 
    5  
    6
    7 module_param(name,charp,S_IRUGO);
    8 
    9 module_param(age,int,S_IRUGO);

    编译后,加载时,输入以下命令

    make CROSS_COMPILE=arm-none-linux-gnueabi-

    insmod hello.ko name="lihaiyan" age=20

    结果如下:

    附上源代码如下:

    hello.c代码:

     1 /******************************
     2 
     3 the first program
     4 
     5 Hello World!
     6 
     7 ******************************/
     8 
     9  
    10 
    11 #include <linux/module.h>
    12 
    13 #include <linux/init.h>
    14 
    15  
    16 
    17 //module param list
    18 
    19 static char *name = "LoverXue";
    20 
    21 static int age = 1;
    22 
    23  
    24 
    25 static int hello_init(void)
    26 
    27 {
    28 
    29     printk("<0>
    Hello, %s
    I know you age is%d
    
    ",name,age);
    30 
    31     return 0;
    32 
    33 }
    34 
    35  
    36 
    37 static void hello_exit(void)
    38 
    39 {
    40 
    41     printk("<0>
    Goodbye,%s
    
    ",name);
    42 
    43 }
    44 
    45  
    46 
    47 module_init(hello_init);
    48 
    49 module_exit(hello_exit);
    50 
    51 MODULE_LICENSE("Dual BSD/GPL"); //Any version of public GNU license
    52 
    53  
    54 
    55 module_param(name,charp,S_IRUGO);
    56 
    57 module_param(age,int,S_IRUGO);
    View Code

    三、改进helloword程序,增加模块之间的依赖

    此时,我们的目的是:写两个模块,模块二调用模块一中的函数。

    先附上代码,我们看着代码来讲解:

    模块一:包含 add_sub.c add_sub.h Makefile 三个文件

    add_sub.h

    1 #ifndef _ADD_SUB_H_
    2 
    3 #define _ADD_SUB_H_
    4 
    5 long add_integer(long a,long b);//function add
    6 
    7 long sub_integer(long a,long b);//function sub
    8 
    9 #endif
    View Code

    add_sub.h 中定义声明了模块二中要调用的函数,函数具体实现,看add_sub.c

    add_sub.c

     1 /*************************************
     2 
     3 add_sub function
     4 
     5 *************************************/
     6 
     7 #include <linux/init.h>
     8 
     9 #include <linux/module.h>
    10 
    11  
    12 
    13 #include "add_sub.h" //包含函数声明的头文件
    14 
    15  
    16 
    17 //returen sum of the two //实现函数
    18 
    19 long add_integer(long a,long b)
    20 
    21 {
    22 
    23     return a+b;
    24 
    25 }
    26 
    27  
    28 
    29 //returen subtraction of the two
    30 
    31 long sub_integer(long a,long b)
    32 
    33 {
    34 
    35     return a-b;
    36 
    37 }
    38 
    39 //为了让其他模块可以调用此函数,
    40 
    41 //必须用EXPORT_SYMBOL将函数导出到内核
    42 
    43 //export the function
    44 
    45 EXPORT_SYMBOL(add_integer); /
    46 
    47 EXPORT_SYMBOL(sub_integer);
    48 
    49  
    50 
    51 MODULE_LICENSE("Dual BSD/GPL");
    View Code

    Makefile代码:

     1 ifeq ($(KERNELRELEASE),)
     2 
     3 KERNELDIR ?= /home/study/system/linux-2.6.31
     4 
     5 PWD := $(shell pwd)
     6 
     7 #################################################
     8 
     9 PRINT_INC = $(PWD)/
    10 
    11 EXTRA_CFLAGS += -I $(PRINT_INC)
    12 
    13 #################################################
    14 
    15 modules:
    16 
    17 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    18 
    19 modules_install:
    20 
    21 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    22 
    23 clean:
    24 
    25 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
    26 
    27  
    28 
    29 else
    30 
    31 obj-m := add_sub.o
    32 
    33 endif
    View Code

    修改前面的代码,必须增加#号内的代码。

    此时,我们模块一全部写完。

    make 编译。

    模块二:包含hello.c Makefile

    hello.c代码:

     1 /******************************
     2 
     3 the first program
     4 Hello World!
     5 ******************************/
     6 #include <linux/module.h>
     7 #include <linux/init.h>
     8 
     9 //extern module
    10 #include "./add/add_sub.h" //包含头文件
    11 
    12 //module param list
    13 static char *name = "LoverXue";
    14 static int age = 20;
    15 static long num1 = 1;
    16 static long num2 = 0;
    17 static short flag = 1;
    18 
    19 static int hello_init(void)
    20 {
    21     printk("<0>
    Hello, %s
    I know you age is%d
    
    ",name,age);
    22     if(flag == 1 ){
    23         printk("<0>sum of two %ld + %ld = %ld 
    ", num1,num2,add_integer(num1,num2));
    24 
    25     }else{
    26         printk("<0>subtraction of two %ld - %ld = %ld 
    ", num1,num2,sub_integer(num1,num2));
    27     }
    28     return 0;
    29 }
    30 
    31 static void hello_exit(void)
    32 {
    33     printk("<0>
    Goodbye,%s
    
    ",name);
    34 }
    35 
    36 module_init(hello_init);
    37 module_exit(hello_exit);
    38 MODULE_LICENSE("Dual BSD/GPL"); //Any version of public GNU license
    39 MODULE_VERSION("V1.0");
    40 
    41 module_param(name,charp,S_IRUGO);
    42 module_param(age,int,S_IRUGO);
    43 module_param(num1,long,S_IRUGO);
    44 module_param(num2,long,S_IRUGO);
    45 module_param(flag,short,S_IRUGO);        
    View Code

    Makefile文件代码:

     1 ifeq ($(KERNELRELEASE),)
     2 
     3 KERNELDIR ?= /home/study/system/linux-2.6.31
     4 
     5 PWD := $(shell pwd)
     6 
     7 ##########################################################
     8 
     9 export-objs := /home/study/EasyARM-iMX257/module_study/02_add/add/add_sub.o
    10 
    11 SYMBOL_INC = $(obj)/
    12 
    13 SYMBOL_INC += /home/study/EasyARM-iMX257/module_study/02_add/add
    14 
    15 EXTRA_CFLAGS += -I $(SYMBOL_INC)
    16 
    17 KBUILD_EXTRA_SYMBOLS = /home/study/EasyARM-iMX257/module_study/02_add/add/Module.symvers
    18 
    19 #########################################################
    20 
    21 modules:
    22 
    23 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    24 
    25 modules_install:
    26 
    27 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    28 
    29 clean:
    30 
    31 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
    32 
    33 else
    34 
    35 obj-m := hello.o
    36 
    37 endif
    View Code

    KBUILD_EXTRA_SYMBOLS的意思就是包含我们要调用的模块的Module.symvers,

    此处最好使用绝对路径。

    编译,

    如果编译出错,如图所示。

    解决方法是;先编译模块一,然后将模块一的Module.symvers拷贝到我们的模块二的目录下,再编译模块二。

    如图所示就不会再出这样的错误了。

    加载模块

    接着就是在开发板中加载模块

    insmod ./add/add_sub.ko
    
    insmod hello.ko num1=50 num2=20 flag=0

    结果如下:

    四、将驱动使用静态编译入内核

    接下来,我们来将刚刚写的代码使用静态编译,加入内核

    1. :我们进入内核的driver目录,增加目录add_sub_Kconfig
    mkdir add_sub_Kconfig

    1. :将我们刚刚写的hello.c add_sub.c add_sub.h 三个文件拷贝入此文件夹

    1. :在此文件夹中增加Makefile,Kconfig两个文件,代码如下:

    Makefile代码

    #drivers/add_sub_Kconfig/Makefile
    
    # Makefile for the ADD_SUB core.
    
    #
    
    obj-$(CONFIG_ADD_SUB) := add_sub.o
    
    obj-$(CONFIG_TEST) := hello.o

    Kconfig代码如下:

    #drivers/add_sub_Kconfig/Kconfig
    
    menu "ADD_SUB" #main menu //增加主菜单
    
    comment "ADD_SUB"
    
    //增加子菜单
    
    config CONFIG_ADD_SUB #children menu, add the add_sub module
    
    boolean "ADD_SUB support"
    
    default y
    
    #children menu ,add the test menu
    
     
    
    config CONFIG_TEST
    
    tristate "ADD_SUB test support"
    
    depends on CONFIG_ADD_SUB #Depends on the config CONFIG_ADD_SUB
    
    default y
    
    endmenu
    1. :修改driver下的Makefile,Kconfig 文件代码:

    Makefile中增加:

    obj-$(ADD_SUB) += add_sub_Kconfig/

    将上面我们自己写的makefile文件包含进来:

    Kconfig中末尾增加以下代码:

    将上面我们自己写的Kconfig文件包含进来

    source "drivers/add_sub_Kconfig/Kconfig"
    
    source "drivers/test//Kconfig"

    1. :修改arch/arm/ 目录下的 Makefile Kconfig

    实验证明只对,只对drivers/Kconfig中修改内容无效,drivers/Kconfig中修改内容无效,还要对arch/arm/Kconfig进行修改,很重要的一步,很多资料上都遗漏了这一步)

    在Kconfig中加入代码:

    source "drivers/add_sub_Kconfig/Kconfig"

    1. :配置编译

    在内核的根目录下执行,make menuconfig 如图所示:

    进入Device Drivers 目录

    在最后面,我们看到了,我们自定义的模块:ADD_SUB模块

    进入ADD_SUB,我们会看到我们写的两个模块全都默认选中了

    此时,我们再次编译内核,就会把我们的模板使用静态编译进内核。

  • 相关阅读:
    浏览器的缓存机制
    浏览器渲染原理及优化
    flutter 安装 & 启动 windows
    从浏览器输入 url 到页面渲染
    压力测试简单案例
    Office2021简体中文离线安装包下载地址合集,目前最全! L
    pdfplumber yongqi
    MySQL中对varchar类型排序问题 yongqi
    基础知识串讲笔记2022124 yongqi
    Faker是一个Python包,,待学习 yongqi
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4288907.html
Copyright © 2020-2023  润新知