驱动编译进内核或编译模块的区别

Linux kernel 分析之十三:kbuild系统-编译到内核和编译成模块的区别 代码编译到内核和编译成模块在代码中有什么区别呢? 从模块的代码中看是一样的。入口函数都是module_init(fun),但是代码中的条件编译会使宏module_init()在编译到内核和编译成模块的情况下替换成不同的代码。 include/linux/init.h中可知#ifndef MODULE... #define module_init(x)  __initcall(x);... 阅读详情
 

linux内核中Kconfig文档的作用

2.6内核的源码树目录下一般都会有两个文文:Kconfig和Makefile。分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。在内核配置make menuconfig(或xconfig等)时,从Kconfig中读出配置菜单,用户配置完后保存到.config(在顶层目录下生成)中。在内核编译时,主Makefile调用这个.config,就知道了用户对内核的配置情况。

上面的内容说明:Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,可以通过修改Kconfig来增加对我们驱动的配置菜单,这样就有途径选择我们的驱动,假如想使这个驱动被编译,还要修改该驱动所在目录下的Makefile。

因此,一般添加新的驱动时需要修改的文件有两种(注意不只是两个)

*Kconfig
*Makefile

要想知道怎么修改这两种文件,就要知道两种文档的语法结构。

First:   Kconfig

 

每个菜单项都有一个关键字标识,最常见的就是config。

语法:
config symbol

options
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

symbol就是新的菜单项,options是在这个新的菜单项下的属性和选项

其中options部分有:

1、类型定义:
每个config菜单项都要有类型定义,bool:布尔类型, tristate三态:内建、模块、移除, string:字符串, hex:十六进制, integer:整型

例如config HELLO_MODULE
bool "hello test module"

bool类型的只能选中或不选中,tristate类型的菜单项多了编译成内核模块的选项,假如选择编译成内核模块,则会在.config中生成一个CONFIG_HELLO_MODULE=m的配置,假如选择内建,就是直接编译成内核影响,就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置.

2、依赖型定义depends on或requires
指此菜单的出现是否依赖于另一个定义

config HELLO_MODULE
bool "hello test module"
depends on ARCH_PXA
    这个例子表明HELLO_MODULE这个菜单项只对XScale处理器有效,即只有在选择了ARCH_PXA, 该菜单才可见(可配置)。

3、帮助性定义
只是增加帮助用关键字help或---help---
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

更多详细的Kconfigconfig语法可参考:


Second:  内核的Makefile

内核的Makefile分为5个组成部分:
Makefile     最顶层的Makefile
.config        内核的当前配置文档,编译时成为顶层Makefile的一部分
arch/$(ARCH)/Makefile 和体系结构相关的Makefile
s/ Makefile.*    一些Makefile的通用规则
kbuild Makefile      各级目录下的大概约500个文档,编译时根据上层Makefile传下来的宏定义和其他编译规则,将源代码编译成模块或编入内核。

顶层的Makefile文档读取 .config文档的内容,并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。 s目录下的Makefile文档包含了任何用来根据kbuild Makefile 构建内核所需的定义和规则。

(其中.config的内容是在make menuconfig的时候,通过Kconfig文档配置的结果)


在linux2.6.x/Documentation/kbuild目录下有详细的介绍有关kernel makefile的知识。

最后举个例子:
假设想把自己写的一个flash的驱动程式加载到工程中,而且能够通过menuconfig配置内核时选择该驱动该怎么办呢?能够分三步:

第一:将您写的flashtest.c 文档添加到/driver/mtd/maps/ 目录下。

第二:修改/driver/mtd/maps目录下的kconfig文档:
config MTD_flashtest
tristate “ap71 flash"

这样当make menuconfig时 ,将会出现 ap71 flash选项。

第三:修改该目录下makefile文档。
添加如下内容:obj-$(CONFIG_MTD_flashtest)    += flashtest.o

这样,当您运行make menucofnig时,您将发现ap71 flash选项,假如您选择了此项。该选择就会保存在.config文档中。当您编译内核时,将会读取.config文档,当发现ap71 flash 选项为yes 时,系统在调用/driver/mtd/maps/下的makefile 时,将会把 flashtest.o 加入到内核中。即可达到您的目的。

转载: http://blog.youkuaiyun.com/aaronychen/article/details/2946740
 
 

我们都知道驱动可以编译成module和直接编译进内核,那么这两者到底有什么区别?

从驱动的入口函数来看,两者都是一样的,都是module_init();

在linux/init.h中可以看到,以下代码:

  1. #ifndef MODULE  
  2.  
  3. #ifndef __ASSEMBLY__   
  4.   
  5. /* initcalls are now grouped by functionality into separate  
  6.  * subsections. Ordering inside the subsections is determined 
  7.  * by link order.  
  8.  * For backwards compatibility, initcall() puts the call in  
  9.  * the device init subsection. 
  10.  * 
  11.  * The `id' arg to __define_initcall() is needed so that multiple initcalls 
  12.  * can point at the same handler without causing duplicate-symbol build errors. 
  13.  */ 
  14.  
  15. #define __define_initcall(level,fn,id) /  
  16.     static initcall_t __initcall_##fn##id __attribute_used__ /  
  17.     __attribute__((__section__(".initcall" level ".init"))) = fn  
  18. ....................  
  19. ....................  
  20. #define __initcall(fn) device_initcall(fn)  
  21.  
  22. #define __exitcall(fn) /   
  23.     static exitcall_t __exitcall_##fn __exit_call = fn  
  24. .....................  
  25. #else /* MODULE */   
  26. /* Each module must use one module_init(), or one no_module_init */ 
  27. #define module_init(initfn)                 /  
  28.     static inline initcall_t __inittest(void)       /  
  29.     { return initfn; }                  /  
  30.     int init_module(void) __attribute__((alias(#initfn)));  
  31.   
  32. /* This is only required if you want to be unloadable. */ 
  33. #define module_exit(exitfn)                 /  
  34.     static inline exitcall_t __exittest(void)       /  
  35.     { return exitfn; }                  /  
  36.     void cleanup_module(void) __attribute__((alias(#exitfn)));  
当我们选择将驱动编译成模块时,那么MODULE宏就会被定义;

如果没有定义MODULE宏,那么驱动初始化函数就会带有.initcall6.init属性,那么在其编译时将会被安排到__initcall_start和__initcall_end范围之间(可以参考内核源码目录下的内核链接脚本arch/cpu-type/kernel/vmlinux.lds.S,其中cpu-type可以是mips、arm、i386等),

 
__initcall_start = .;  
  1.   .initcall.init : {  
  2.     INITCALLS  
  3.   }  
  4.   __initcall_end = .;  
  5.   
  6. 而INITCALLS宏定义在include/asm-generic/Vmlinux.lds.h中:  
  7. #define INITCALLS                           /  
  8.     *(.initcall0.init)                      /  
  9.     *(.initcall0s.init)                     /  
  10.     *(.initcall1.init)                      /  
  11.     *(.initcall1s.init)                     /  
  12.     *(.initcall2.init)                      /  
  13.     *(.initcall2s.init)                     /  
  14.     *(.initcall3.init)                      /  
  15.     *(.initcall3s.init)                     /  
  16.     *(.initcall4.init)                      /  
  17.     *(.initcall4s.init)                     /  
  18.     *(.initcall5.init)                      /  
  19.     *(.initcall5s.init)                     /  
  20.     *(.initcallrootfs.init)                     /  
  21.     *(.initcall6.init)                      /  
  22.     *(.initcall6s.init)                     /  
  23.     *(.initcall7.init)                      /  
  24.     *(.initcall7s.init)  

在kernel启动时,会执行如下函数:

init->do_basic_setup->do_initcalls

do_initcalls中会把.initcall.init中的函数依次执行一遍

for (call = __initcall_start; call < __initcall_end; call++) {

 

...

 

(*call)();

 

...

 

}

于是在内核启动过程中执行了module_init(fn)函数,也就实现了自动加载模块的目的;

这类似于pmon中带有constructor属性的函数,都是在编译时统一将其安排到某一连续的地址范围内,然后再启动时,遍历执行这些函数。

 

****************************************************************************************************************************************************************************************
***编译成模块时,模块也有版本号!在模块的Makefile中有编译该模块使用的内核版本号。或者在当前编译这个模块的内核源代码中也可以看到内核版本号。这个版本号即为所编译的模块的版本号!
当用insmod将模块加载进某个内核时,模块版本号必须要与该内核版本号一致,当然也可以用modprobe命令来强行插入。
注意前后两个内核版本号是针对不同的内核的,前者是针对编译模块时用的内核,后者是模块加载进内核时的内核(即利用该模块的某个内核)。
 
 
***字符设备和块设备跟文件系统打交道,他们服务于 文件系统,所以只需要关心文件系统。

***网络设备和协议栈打交道,他们服务于协议栈,所 以只需要关心协议栈。
【内核编译、.ko驱动模块编译】- 未完结 把驱动编译到内核 与 把驱动编译成模块,生成.ko文件 阅读详情

相关推荐

linux内核设备驱动——将驱动程序编译进内核

选择在开发机上编译而不是本机编译时,需要注意的一点就是:通常嵌入式开发都是基于arm、mips等嵌入式架构,而PC常用X86架构,在编译时就不能使用开发机上的gcc编译器,因为开发机上编译器是针对开发平台(X86),而非运行平台(arm、mips),所以需要使用交叉编译工具链,同时在编译时指定运行的主机平台。在上文中还提到,Kconfig分布式地存在于子目录下,同时需要注意的是,在编译时,配置工具并非无差别地进入每个子目录,收集所有的Kconfig信息,而是遵循一定的规则递归进入。

m0_74282605的博客 696

【深入Linux内核驱动】【Linux设备驱动】驱动编译进内核和编译成模块有什么区别

该文阐述了驱动编译进内核和编译成模块有什么区别,主要通过Makefile文件进行深入

Tschome的博客 1095

编译内核与编译为独立模块的比较及示例代码

将模块静态编译到内核意味着将模块的代码直接合并到内核镜像中,并在内核启动时一同加载。但是,这种方式也有一些限制和缺点,如不易定制和扩展,需要重新编译整个内核才能更新模块。编译成独立模块意味着将模块的代码编译成独立的文件,可以在运行时加载和卸载。这种方式的主要优点是灵活性和可定制性较高,可以单独编译和更新模块,而无需重新编译整个内核。本文将比较将模块静态编译到内核和编译成独立模块的优缺点,并提供相应的示例代码。综上所述,将模块静态编译到内核的方式性能较好,但不易定制和更新模块,需要重新编译整个内核。

DevGOOD的博客 303

linux驱动开发学习笔记七:将驱动程序编译成.ko文件或者直接编译进内核

一、前言        也学了10天左右的linux驱动开发了,一般学习新知识的时候,我都喜欢首先理清思路,然后才去关注更加细节的东西,这次也不例外。        正如我前面写的几篇博客,主要内容包括linux内核和linux发行版的概念与区别;linux系...

耐心的小黑的博客 5915

【Kernel】驱动编译的两种方式:编译成模块、编译进内核(使用杂项设备驱动模板)

杂项设备的驱动是驱动开发中最简单最方便的,核心就是处理write信号和read信号做出对应的反应。如果需要将驱动编译成模块前提是有编译好的kernel,并且开发板是烧录的该版本的kernel,编译成模块我们只需要新建一个Makefile文件: 然后我们只需要make就会生成.ko文件,然后将ko文件拷贝到开发板中,加载驱动使用insmod、卸载内核使用rmmod。 驱动编译进内核 如果要将驱动编译到内核中去则需要新建两个文件一个Makefile一个Kconfig Makefile Kconfig 相关的Kc

凉开水白菜的博客 3959

Android Settings 设置Preference置灰显示

使Preference置灰显示,不能点击。先调用Preference的setEnabled(false),再调用setShouldDisableView(true); 如果使置灰项恢复正常可点击,可调用setEnabled(true)。

随风而动 1048

驱动程序module_init()在编译成模块或编译进内核时的区别

内核版本linux-2.6.22.6 在内核目录include/linux/init.h中会解析,是否定义了MODULE宏来区分编译进内核还是编译成模块。 编译进内核的宏展开过程 module_init(x)->__initcall(x);->device_initcall(fn)->__define_initcall("6s",fn,6s) #define...

yogach的博客 966

别再瞎调了!手把手教你搞定STM32步进电机PID速度环(附完整代码与比例系数详解)

本文详细解析了STM32步进电机PID速度环的完整实现过程,从算法输出到脉冲频率的转换链路,重点讲解了比例系数的确定方法及系统标定实验。通过完整的代码示例和调试技巧,帮助工程师解决实际应用中的常见问题,提升步进电机控制精度与稳定性。

weixin_28729331的博客 214

Linux内核模块下载到板子,在Linux内核中增加新驱动模块

开发环境开发板:A33-Vstar开发板系统: Linux/arm 3.4.39 KernelUbuntu版本:Ubuntu14.04----------------------------------------------------新增内核驱动,并可以通过make menuconfig配置。内核完整路径:~/A33-Vstar/dragonboard/linux-3.41. 构建测试模块:h...

weixin_35315019的博客 451

2025华东杯A/B/C题解题思路+可运行代码参考

这些因素包括但不限于:助滑坡的坡度、运动员的质量、滑雪板的接触面与雪地的摩擦力、空气阻力系数、运动员的体型和衣物形态等。助滑坡是运动员滑行至起跳台前的最后一段坡道,这一段坡道的坡度、长度和运动员的姿势会直接影响到起跳时的初始速度。运动员的滑行速度不仅受助滑坡的坡度影响,还受到摩擦力、空气阻力和重力等多方面因素的影响。通过合理的姿势调整,运动员能够有效减少空气阻力,增加身体的重力加速度,进而提升滑行速度。助滑坡的角度通常介于10°到12°之间,而运动员的滑行速度将受到重力、摩擦力和空气阻力的共同作用。

qq_52590045的博客 1797

宇瞳杯视讯镜头完成版(除公差/鬼像分析)

宇瞳杯视讯镜头完成版(除公差/鬼像分析)

weixin_72050316的博客 1049

linux内核驱动模块加载方式

在类unix操作系统中,驱动加载方式一般分为:动态加载和静态加载,下面分别对其详细论述。 一、动态加载 动态加载是将驱动模块加载到内核中,而不能放入/lib/modules/下。 在2.4内核中,加载驱动命令为:insmod ,删除模块为:rmmod; 在2.6以上内核中,除了insmod与rmmod外,加载命令还有modprob...

weixin_34159110的博客 188

基于Python的农业市场价格抓取与供需分析:现代爬虫技术与实战应用

在正式开始爬虫开发之前,我们首先了解爬虫的基本概念和工作原理。爬虫(Web Scraping)是通过编程的方式,自动从互联网上获取信息的技术。它可以帮助我们提取HTML页面中的特定数据,通常用于收集并处理大量信息。发送HTTP请求:爬虫需要向目标网站发送请求,获取网站的HTML页面内容。解析HTML页面:通过HTML解析器对获取的页面内容进行解析,提取其中需要的数据。数据清洗与存储:将提取的数据进行清洗,去除多余的字符或无关内容,然后存储到合适的格式(如CSV文件、数据库等)中。数据分析与可视化。

2201_76125261的博客 1117

Linux驱动基础开发

来源:http://www.linuxidc.com/Linux/2011-10/44721.htm Linux 设备驱动概述 目前,Linux软件工程师大致可分为两个层次:  (1)Linux应用软件工程师(Application Software Engineer): 主要利用C库函数和Linux API进行应用软件的编写; 从事这方面的开发工作,主要需要学习:符合linux posix标准的API函数及系统调用,linux的多任务编程技巧:多进程、多线程、进程间通信、多任务...

一口Linux的专栏 1081

基于STM32、HAL库的RN8209D电能计量芯片驱动程序设计

/ 假设电压互感器变比为220V:0.5V,电流互感器变比为20A:5mA。// 电压ADC原始值。// 电流ADC原始值。// 有功功率(W)// 电能(kWh)

corlin6688的博客 470

【软件系统架构】系列四:嵌入式软件-NPU(神经网络处理器)系统及模板

NPU(Neural Processing Unit) 是专门用于人工神经网络推理与训练的处理器,具备高并行、低功耗、低延迟等特点。它是边缘 AI、自动驾驶、智能摄像头、语音识别等场景中的关键硬件。

moton2017的博客 2249

Makefile及Android.mk编写及如何编译进内核

目录 1、Makefile简介... 3 2、编写通用Makefile文件... 3 3、编译进内核或编译成模块... 6 4、Android.mk文件编写... 7     1、Makefile简介        Makefile是完成一个程序的整个编译过程。程序的编译过程主要分为1,预处理,2,编译,3,汇编,4,链接。        当执行make命令时,编译器会首先查找...

李渊的博客 2702

Oracle EBS GL日记账批“选定以过账”状态数据修复

日记账来源:应收账款。用户操作过账以后,自动提交请求“过账:单一分类账”一直运行中,该请求执行5,6个小时甚至10多个小时无法完成,导致“标准管理器”阻塞大量请求待定,“冲突解决管理器”的待定数量不断增加。系统管理员不得不把该请求强制取消,此时,日记账批的状态处于“选定以过账”(GL_JE_BATCHES.STATUS为S),如下图 检查此日记账批有3千多条日记账题头,由于日记账比较多,日记账的科目余额计算需要大量服务器资源和执行时间比较长。

陈显平的专栏-Oracle EBS 3245

字符设备驱动的理解

一、 字符设备驱动主要是对fs.h里面的file_operations里的open、read、write、close等等一些函数的实现 二、 字符设备驱动可以编译进kernel(内核)里面,也可以编译成模块,再测试的时候直接运行模块(.ko)即可。 三、 模块的加载与删除 moudle_init(chrdevbase_init),模块的入口,当加载模块的时候,会调用里面的chrdevbase_init函数 moudle_close(chrdevbase_close),模块的出口,退出模块的时候,会调用里面的

heng6868的博客 281

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

GPIO设备驱动原理

例如,USB驱动程序向Linux核心提供了一个设备文件I/O接口,GPIO设备驱动程序向GPIO子系统提供了GPIO设备接口,接着向核心提供了文件I/O和缓冲区的接口。作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据;如果不能,就调用请求函数来进行实际的I/O操作。:在对字符设备发出读/写请求时,实际的硬件I/O操作就紧接着发生了。,其驱动程序的使用可以按照两种方式编译,一种是静态编译进内核,另一种是编译成模块以供动态加载。在Linux系统下,字符设备和块设备的主要区别是。

aa252525_的博客 152

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Linux下把驱动编译进内核及图形化配置的方式进行选择

Linux下把驱动编译进内核及图形化配置的方式进行选择

suifen_的博客 2748

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Linux 驱动开发之内核模块开发——内核模块编译 Makefile 入门

Linux模块化编译 通用makfile编译步骤

发如雪 3653

Linux驱动模块编译

1、将驱动编译成模块,然后使用命令将驱动加载到内核2、直接将驱动编译到内核中。

ttdffmm的博客 1225

编译进内核的驱动是如何工作的

打开内核源码下的顶层Makefile,驱动编译进内核KBUILD_AFLAGS_KERNEL决定驱动编译成模块KBUILD_AFLAGS_MODULE决定所以这里时驱动编译成模块即。

weixin_52849254的博客 487

linux内核设备驱动程序——将驱动程序编译进内核

值得注意的是,/boot/vmlinuz-$(version)是linux启动时读取的镜像,但是在本机中进行驱动程序编译的时候并不会影响到这个镜像,换句话说,即使是指定了obj-y,驱动程序也不会编译到/boot/vmlinuz-$(version)镜像中,自然达不到将驱动编译进内核的效果。对于模块而言,就是相应模块无法加载。在上文中还提到,Kconfig分布式地存在于子目录下,同时需要注意的是,在编译时,配置工具并非无差别地进入每个子目录,收集所有的Kconfig信息,而是遵循一定的规则递归进入。

m0_74282605的博客 299

Linux内核模块详解

内核模块 实验目的 内核模块是Linux操作系统中一个比较独特的机制。通过这一章学习,希望能够理解Linux提出内核模块这个机制的意义;理解并掌握Linux实现内核模块机制的基本技术路线;运用Linux提供的工具和命令,掌握操作内核模块的方法。 实验内容 针对三个层次的要求,本章安排了3个实验。 第一个实验,编写一个很简单的内核模块。虽然简单,但它已经具备了内核模块的基本要素。与此同时,...

Kunaly 2万+
上一篇: 简单字符设备驱动程序(二)
下一篇: file指针
sooolo
博客等级 码龄17年 95粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值