一、向内核中添加驱动步骤

在向内核中添加驱动的时候要完成3 项工作,包括:

1、在Kconfig 中添加新代码对应项目的编译条件

2、将驱动源码添加到对应的目录中

3、在目录Makefile 中文件中增加针对新代码的编译条目



二、编译器路径的设置

1、打开家目录下的.bashrc文件,在其最下面添加如下内容:

export PATH=$PATH:/home/mint/itop/arm-2009q3/bin

使其生效

 .  .bashrc

2、该目录与交叉编译器的解压放置位置相对应

/home/mint/itop/arm-2009q3/bin

3、打开内核源码的顶层目录的Makefile文件

在195行的位置有如下内容

export KBUILD_BUILDHOST := $(SUBARCH)
ARCH    ?= arm
CROSS_COMPILE   ?= /home/mint/itop/arm-2009q3/bin/arm-none-linux-gnueabi-
#CROSS_COMPILE   ?= /usr/local/arm/4.5.1/bin/arm-none-linux-gnueabi-
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)

该交叉编译工具链的位置与上面是一一对应的。



三、使用make zImage编译内核执行过程

在这里以BUZZER的驱动为例。

1、在make zImage命令执行之后,它会首先找到源码顶层目录下的Makefile文件,运行Makefile 文件之后,它会在Makefile 文件中找到编译器的路径,然后系统根据环境变量找到“export PATH=$PATH/home/mint/itop/arm-2009q3/bin”编译器的路径。

2、在driver/char/ 目录下,暂时关注以下三个文件

itop4412_buzzer.c  //led 驱动的源码
itop4412_buzzer.o   //生成最终zImage 二进制的中间文件
Makefile             //make执行时所需要的文件

3、打开该目录下的Makefile文件

obj-$(CONFIG_BUZZER_CTL)  += itop4412_buzzer.o

如果想添加类似的字符驱动,就可以在这个目录下添加。



四、Makefile 脚本语法简介

1、强制编译进内核

obj-y       += misc.o

2、条件编译

obj-$(CONFIG_BUZZER_CTL)  += itop4412_buzzer.o

需要在Kconfig 中定义,在menuconfig中配置之后,编译器运行的时候找到对应的宏变量CONFIG_BUZZER_CTL之后才会编译。

3、Makefile的层层调用

打开driver/下的Makefile文件,在第33行中

obj-y               += char/

“加等号”右边有文件变为了文件夹。这里表示强制编译当前目录“/drivers”的下一级目录“/char”。在执行编译命令执行到这一句的时候,就会先跳转到“/char”目录下的“Makefile”文件。



五、Makefile 的测试

目标:通过配置menuconfig 中的SKYFALL,来将内核编译进内核或者不编译进内核。

实现步骤:

(1) 在源码目录下的driver/char目录下编写itop4412_skyfall.c源文件,文件内容如下。最后在/dev下显示的设备节点的名字为skyfall_007。

#include <linux/init.h>
#include <linux/module.h>
/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>#define DRIVER_NAME "skyfall"
#define DEVICE_NAME "skyfall_007"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("SKYFALL");//long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
//驱动实际操作的实现
static long skyfall_ioctl( struct file *file, unsigned int cmd, unsigned long arg){printk("%s,%d\n",__func__,__LINE__);printk("cmd is %d,arg is %d\n",cmd,arg);return 0;
}//int (*release) (struct inode *, struct file *);
//关闭该驱动的实现
static int skyfall_release(struct inode *inode, struct file *file){printk("%s,%d\n",__func__,__LINE__);printk(KERN_EMERG "skyfall release\n");return 0;
}//int (*open) (struct inode *, struct file *);
//打开该驱动的实现
static int skyfall_open(struct inode *inode, struct file *file){printk("%s,%d\n",__func__,__LINE__);printk(KERN_EMERG "skyfall open\n");return 0;
}//定义一个字符设备操作集合
static struct file_operations skyfall_ops = {.owner           = THIS_MODULE,.open            = skyfall_open,.release         = skyfall_release,.unlocked_ioctl  = skyfall_ioctl,
};//定义一个杂项设备结构体
static  struct miscdevice skyfall_dev = {.minor = MISC_DYNAMIC_MINOR,.name  = DEVICE_NAME,//字符设备操作集合,需要提前定义一个,然后取地址.fops = &skyfall_ops,
};static int skyfall_probe(struct platform_device *pdv){printk(KERN_EMERG "initialized\n");printk("%s,%d\n",__func__,__LINE__);//注册杂项设备,需要一个传一个杂项设备的结构体,所以需要提前定义一个,然后取地址misc_register(&skyfall_dev);return 0;
}static int skyfall_remove(struct platform_device *pdv){printk(KERN_EMERG "\tremove\n");//注销杂项设备misc_deregister(&skyfall_dev);return 0;
}static void skyfall_shutdown(struct platform_device *pdv){;
}static int skyfall_suspend(struct platform_device *pdv,pm_message_t pmt){return 0;
}static int skyfall_resume(struct platform_device *pdv){return 0;
}struct platform_driver skyfall_driver = {.probe      = skyfall_probe,.remove     = skyfall_remove,.shutdown   = skyfall_shutdown,.suspend    = skyfall_suspend,.resume     = skyfall_resume,.driver     = {.name = DRIVER_NAME,.owner = THIS_MODULE,}
};static int __init skyfall_init(void)
{int DriverState;//定义驱动状态,判断驱动是否注册成功printk(KERN_EMERG "skyfall driver enter!\n");printk("%s,%d\n",__func__,__LINE__);DriverState = platform_driver_register(&skyfall_driver);/*驱动一旦注册成功,会与设备进行匹配,匹配成功是由platform_match函数进行匹配,驱动调用probe初始化函数*/printk(KERN_EMERG "DriverState = %d\n",DriverState);return 0;
}static void __exit skyfall_exit(void)
{printk(KERN_EMERG "skyfall driver exit!\n");platform_driver_unregister(&skyfall_driver);
}module_init(skyfall_init);
module_exit(skyfall_exit);

以上这些需要配合后面的注册设备与注册驱动相结合。

(2)打开源码目录下的driver/char目录下Makefile文件,添加编译选项

obj-$(CONFIG_SKYFALL_CTL) += itop4412_skyfall.o

(3)打开源码目录下的driver/char目录下Kconfig文件,添加菜单选项

config SKYFALL_CTLbool "Enable SKYFALL config"default yhelpEnable SKYFALL config!

(4)打开menuconfig界面,将Device Drivers —> Character devices—> [] Enable SKYFALL config (NEW) 添加 。


添加完毕后,保存,生成新的.config文件。

(5)查看.config文件

CONFIG_SKYFALL_CTL=y

(6)编译内核 sudo make zImage,查看有没有生成itop4412_skyfall.o中间文件

编译内核


(7)将新生成的内核烧写至开发板中

cp arch/arm/boot/zImage /mnt/share/

(8)在开发板的/dev目录中产生itop4412_skyfall.c 驱动的设备节点skyfall_007。在源码的driver/char目录下,生成了对应的中间文件。

(9)以上是生成skyfall设备节点的步骤。

(10)打开menuconfig界面,将Device Drivers —> Character devices—> [ ] Enable SKYFALL config 去掉 。

保存并退出,生成新的.config文件。

(11)打开.config文件,发现配置成功。

# CONFIG_SKYFALL_CTL is not set

(12)再次编译内核,发现没有中间文件itop4412_skyfall.o生成。

sudo make zImage

(13)将新生成的内核烧写至开发板中

cp arch/arm/boot/zImage /mnt/share/

(14)在开发板的/dev目录中没有产生itop4412_skyfall.c 驱动的设备节点skyfall_007。



(15)至此,整个过程全部完成。



六、内核编译的全部过程

1、红色的线条表示配置文件Kconfig 这一部分,在Kconfig 中要定义针对具体驱动文件的宏变量。然后使用menuconfig 工具生成新的.config文件。

2、黑色的线条表示编译文件Makefile 这一部分,在Makefile 中针对宏变量编译驱动文件。

3、执行make 命令之后,调用.config文件,配合各级目录中的Makefile 文件编译具体的驱动源代码,将源代码编译成.o中间文件。

4、当中间文件全部编译完成之后,编译工具会生成一个非常精炼的zImage二进制文件。



004_Makefile的编译相关推荐

  1. go build 编译报错 missing go.sum entry for module providing package

    go build 编译报错 missing go.sum entry for module providing package 解决方法 // 移除未使用的依赖 go mod tidy 再次编译,就可 ...

  2. kotlin重写构造方法编译报错:Primary constructor call expected

    在kotlin中使用construct关键字定义构造方法,如果类定义时已经有构造方法(类名后带括号),需要添加构造方法时,需要使用以下写法: class User(var name,var age){ ...

  3. Myeclipse中项目没有代码错误提示,jsp页面无编译迹象?如何解决

    在使用Myeclipse开发项目时,发现jsp页面中嵌入的java代码没有编译的迹象,错误的get方法没有报错,没有报错信息我们如何知道我们开发的内容是正确的呢? 接下来就演示一下如何解决

  4. 初试linux编译(ubuntu+vim)+玩转智能蛇

    一.初试linux编译(ubuntu+vim) 步骤: ①下载vmware15+ubuntu桌面版映像 ②安装ubuntu ③下载vim+gcc 在ubuntu终端输入: sudo apt-get i ...

  5. java调用clang编译的so_写Java这么久,JDK源码编译过没?编译JDK源码踩坑纪实

    好奇害死羊 很多小伙伴们做Java开发,天天写Java代码,肯定离不开Java基础环境:JDK,毕竟我们写好的Java代码也是跑在JVM虚拟机上. 一般来说,我们学Java之前,第一步就是安装JDK环 ...

  6. Go 编译的可执行文件是否有动态库链接?

    Go 引用了其他包的话,是将引用的包都编译进去.用 ldd 看几个 Go 编译出来的二进制程序有的没有动态链接库的使用.但是有的又有引用动态链接库,这个是为什么? 回答:Go 默认是开启 CGO_EN ...

  7. Go 知识点(18)— 条件编译(编译标签、文件后缀)

    1. 条件编译 Go 能根据所处环境选择对应的源码进行编译.让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就叫做条件编译. 在 Go 中,也称之为 Build Constraints ...

  8. RPC 笔记(03)— gRPC 概念、安装、编译、客户端和服务端示例

    1. gRPC 概念 gRPC 是 Google 开源的一款高性能的 RPC 框架.GitHub 上介绍如下: gRPC is a modern, open source, high-performa ...

  9. GCC 同时编译多个 C/C++ 文件

    以下这些操作都可以共用一条 gcc 指令: 将多个 C/C++ 源文件加工为汇编文件或者目标文件: 将多个 C/C++ 源文件或者预处理文件加工为汇编文件或者目标文件: 将多个 C/C++ 源文件.预 ...

  10. GCC 编译 C++ 程序分步骤流程(预处理 gcc -E、编译 gcc -S、汇编 gcc -c 和链接 gcc 以及 gcc -o 选项)

    C 或者 C++ 程序从源代码生成可执行程序的过程,需经历 4 个过程,分别是预处理.编译.汇编和链接. 同样,使用 GCC 编译器编译 C 或者 C++ 程序,也必须要经历这 4 个过程.但考虑在实 ...

最新文章

  1. SpringCloud 教程 | 第二篇: 服务消费者(rest+ribbon)
  2. bs4之标签树的平行遍历
  3. 数据结构-二叉树的非递归遍历
  4. mysql sleep连接过多的完美解决办法
  5. 【WXS数据类型】Boolean
  6. GIMP的Path的import和export
  7. VBScript 程序员参考手册 读书笔记01-07
  8. 2020,2022年全年详细工作日、周末、节假日数据表sql
  9. 浅谈国内软件信息化项目项目立项管理办法
  10. 高中分班考试如何计算机,新高一生如何应对分班考?
  11. JavaScript swiper
  12. 蓝绿发布、金丝雀发布、A/B测试
  13. Arduino追光小车
  14. 从Hadoop到Spark和Flink,大数据处理框架十年激荡发展史
  15. Redirect组件的使用
  16. idea中push代码失败问题解决
  17. 【地理人工智能交叉】通过整合兴趣点和Word2Vec模型感知城市土地利用的空间分布
  18. 如何下载通州区卫星地图高清版大图
  19. java泛型(360°无死角讲解)
  20. 让低版本的IE浏览器支持HTML5

热门文章

  1. PHP方法,传入的参数前带三个点是什么意思?
  2. 细说10月24号为什么是程序员的节日?
  3. 怎么快速找到:附近的人
  4. 笔记本wifi共享出来能够连接但是没有网速
  5. 如何把字符串复制给数组杭电11页几小题的总结
  6. C语言函数:even(n),fflush(stdin)
  7. 使用cephadm搭建ceph(octopus)过程
  8. EF中的Guid主键
  9. 终端测试是硬件测试还是软件测试,移动终端软件测试基础知识
  10. java中创建库存_java案例实例 商品库存管理系统