找回密码
 注册
关于网站域名变更的通知
查看: 271|回复: 1
打印 上一主题 下一主题

iTOP-iMX6开发板-设备树驱动-以module的方式编译驱动

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-10-15 11:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
内核驱动不仅可以将驱动编译到内核中,还可以动态的编译内核驱动。本文档介绍如何以2 a, h: J  g( q
模块的方式编译内核驱动。* S; A! ?2 w& f' ?- o0 m% }
以 module 的方式编译驱动,需要以下几个部分:' }6 a6 Z! j0 b! u: F
1 内核成功编译过;
) _% v& u; V8 K; _% W+ Y  B: m7 ~2 找到内核的 ARM 编译器;. ^+ {7 E' M# t+ p' x; N
3 编译简单驱动;% h# }1 w% r6 Y& V  I8 T4 c- f
4 编译简单的 Makefile 文件,Makefile 文件中需要指向内核源码目录(成功编译过的内核源码目录);
  v) l$ f' \+ w  C, L& ^和文档在一起的有“Makefile”、c 文件和 ko 文件,大家可以用来测试。! ]* y! y. z8 h) y2 m
要动态的编译内核,首先需要将内核源码编译通过,内核的编译请参考使用手册第五章。* D6 ?$ u( H2 P# j; c: T  ]; ?
1. 内核和编译器路径
9 O# |1 r  @9 W# ~( i$ z! ~1 z0 H本节介绍内核路径、编译器路径。无论是 Qt 和 Ubuntu 的内核源码,都是在 android 源码包中,所以必须先解压 android 源码到 Ubuntu14.04 中。
* G7 {, M+ g; [$ b$ \! l% w7 y如下图所示,作者的 android 源码在“/home/iMX6Q/iTOP-iMX6_android6.0.1”目录下,内核源码在其中的“kernel_imx”目录下。
- {  W3 r- U8 e) L1 t; @% Z, f进入“kernel_imx”目录,查看“build_android_kernel.sh”中的脚本文件,如下图所示。
6 X" g$ |8 T8 V' Y/ m+ P0 V8 L' L0 b* }& S+ A9 Q
如上图所示,我们可以得到一些信息,在后面编译内核模块的时候,需要设置编译目标平台为 arm,“export ARCH=arm”;* ~; j5 u6 V% J! h/ ~
编译器的路径为“$(pwd)/../prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-”。理论上,应该使用这个编译器,但是实际上以
% X  Q+ z4 P. \3 J& r2 d8 Zmodules 的方式编译内核驱动的时候,使用这个编译器,是无法编译的!!
( x. N+ Z1 x$ r1 T+ m' L: {应该使用“../prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-”这个编译器才行,如下图所示。0 i$ y/ p( y5 y  c; [3 W" I! }1 e

. Y) b$ P& L8 F+ A% D' t编译器路径为内核源码目录对应的../prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-”,这是作者测试出来的,作者没有太多时间深入研究编译脚本,但是这个编译器是可以的。前面红色部分介绍的编译器,会提示报错,对于这个报错,飞思卡尔官方给出的是简单的回复“你使用了 android 的编译器”,没有提供更多的解释,也没有提示方法,不过作者测试了几个内核驱动,都是可以正常 insmod 和 rmmod 的。
! K+ w# W4 `* g2 ]" x- M/ c8 m; q( i5 {2 b1 i
2. Makefile 和测试驱动源码以及编译4 Y, k" e! I. P1 y5 z, M& z
作者在“/home/imx6”目录下新建一个“imx_driver_modules”目录,将要编译的驱动和 Makefile 文件放到这个目录下。
% ?5 Y) `5 k0 Q  s  V! B# a5 `5 p+ U/ A
% {! U1 W1 Y: Z, o7 H2.1 Makefile' {4 e; ^4 I2 i9 M! O
Makefile 脚本文件:
* G6 ~9 _1 u) Kobj-m += iTOP_IMX6_treedriver_hello.o
* `; z$ g# p2 [7 {, bKDIR =/home/iMX6Q/iTOP-iMX6_android6.0.1/kernel_imx
- D7 @# R9 o, R) U  APWD ?= $(shell pwd)
9 ]5 Z/ a8 q4 f. s. k" P2 p  }all:
0 H7 b# O9 v  q- |, B5 x& R. Nmake -C $(KDIR) M=$(PWD) modules modules ARCH=arm) h9 Z+ T. r( ~
CROSS_COMPILE=$(KDIR)/../prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
* U. ?; m- \: e4 oclean:7 u# S& _1 ]0 d# T9 x* W; m
rm -RF modules.order *.o workqueue.o Module.symvers *.mod.c *.ko
3 [) o2 K: ?, n: H  \脚本中:+ q2 s  C! b2 ?) o
第一行bj-m += iTOP_IMX6_treedriver_hello.o 表示编译的源文件为iTOP_IMX6_treedriver_hello.c,如果源文件名有变化,则需要修改成对应的。
! F! z9 i7 d' \: s( d$ I第二行:KDIR 参数指向对应的内核源码目录。作者的内核源码是在/home/iMX6Q/iTOP-iMX6_android6.0.1/kernel_imxx 目录下,用户要根据自己的具体情况来修改。# q5 G$ V2 G( |9 j1 |  _: o4 M
第三行:PWD ?= $(shell pwd)表示将当前目录的路径赋值给 PWD 变量,也就是/home/imx6_tree_driver/iTOP_IMX6_treedriver_hello。作者将会把 Makefile 文件和驱动源码放到这个目录下编译。' ]' S6 T, x$ d  t0 [& z
第五行:其中 make -C $(KDIR) M=$(PWD) modules,表示将当前目录下的文件编译为模块,并且制定了内核源码的路径;, D1 t& Z" \$ E
其中 ARCH=arm 表示设置目标 CPU 类别为 arm,也就是编译的依赖内核和驱动模块目标 CPU 为 ARM
) n# z0 C1 L# T其中 CROSS_COMPILE=$(KDIR)/../prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi- ,这里的路径,指向内核编译器的路径。
9 U1 d% Q3 m0 B1 j2.2 简单驱动源码
4 u9 q6 c( [/ Z4 T% C+ |* B驱动文件名称为:iTOP_IMX6_treedriver_hello.c,源码如下:
$ K! o+ d+ `$ ^4 \$ O: `- H. X! @" S
#include
) h5 [# r4 h, l9 @#include/ u( P. M" R; o" h
MODULE_LICENSE("Dual BSD/GPL");
$ ~! a, b* n6 o- O* P  @MODULE_AUTHOR("iTOPEET_dz");! n( y, @% c8 h
static int hello_init(void)
2 e+ }; Z/ _+ J8 w- |{
( I$ [/ ?0 }: c7 d5 i8 b) mprintk(KERN_EMERG "Hello World enter!\n");  m, P% C$ @8 V6 i
return 0;
9 ~& ^7 y) i/ m6 l8 [5 ]* _}$ \! b+ W2 N, E/ K) {2 G* y( L( j
static void hello_exit(void): \+ T" m; |3 D$ d* O! S$ W
{
8 v6 A; \8 ^3 Y  ?printk(KERN_EMERG "Hello world exit!\n");
7 Y, k9 S" ^% w* l9 q' u3 @}
- p) V7 i$ X, C0 I: n, e7 @  emodule_init(hello_init);
0 @- }* _, u1 Z0 o; Q9 Pmodule_exit(hello_exit);
8 j. N, a* {2 N, |( F0 w2 D驱动源码只有基本的入口和出口函数。加载和卸载的时候分别打印“Hello Worldenter!”和“Hello world exit!”。
' }0 j9 `* h0 I) p( y- P  e7 _  L" p" q( E
2.3 编译
5 ]: {% Z, q$ ]3 t/ t将源码和 Makefile 文件拷贝到 Ubuntu14 系统下。3 V" @/ {0 w" ~& h- g9 A4 E" h  K
使用命令“make”,如下图所示,可以看到有“iTOP_IMX6_treedriver_hello.ko”文件生成。
5 Z2 [/ d4 q# Q; r0 b: A4 H
9 A( F2 h1 k8 t! n( Y, B  x/ W2 e# Z* j' C/ o
使用命令“make clean”,可以删除中间文件。8 g. Z" M! b4 A1 H
3.模块编译常见问题! t6 {- {8 m  ?8 X8 ~$ z
在以模块的方式编译驱动的过程中,新手可能会以下问题。
7 _9 \4 E4 r: I) d1.内核源码没有编译或者内核源码路径设置不正确。
6 ~$ f/ t9 S# H4 X8 S如果内核源码没有编译,那么模块将会提示缺少库之类的错误;如果路径设置不正确,会提示找不到内核。
8 D  F$ r- c4 M5 u2.源码和 Makefile 文件在 Windows 下编写,然后拷贝到 Ubuntu 上,由于编辑器不同导致转码错误。) v8 f  ?1 i; o: t2 ]
这种错误比较容易解决,Make 编译之后,系统会提示 Makefile 或者驱动文件具体某一行出现问题。使用 vim 编辑器打开查看一下,就能找出一些乱码,使用 vim 编辑器修正一下再编译即可。  i3 O4 c: h1 \8 R8 E7 u; C
- D: M6 g( W0 o3 f, @2 m
4. 模块加载和卸载. _' G2 p4 F# B7 n# _
作者这里使用最小 linux 系统来测试模块的加载和卸载,最小系统在使用手册第十三章有介绍。在编译模块前,内核源码必须要编译通过,作者这里是在最小系统是加载模块,那么内核源码也必须编译为 qt 的内核(最小系统使用的是 qt 的内核),否则是无法加载的。
9 H4 G7 Q0 F1 J- N& }) Z$ u如下图所示,将驱动模块拷贝到开发板(作者采用的是 nfs 共享目录的方式,关于 nfs 大家可以参考群共享中 nfs 相关的文档,设备树和非设备的 Ubuntu 都通用。也可以用 tf 卡或者 U 盘)。
7 h! d4 K8 j: Z+ N$ `) H, W/ `+ t
; D5 L" Q/ l+ @+ s) o. c9 Y0 J, I( [$ u4 J) p. q# w
然后使用命令“insmod iTOP_IMX6_treedriver_hello.ko”加载驱动模块,如下图示,打印出“Hello World enter!”,表明模块驱动加载成功。5 B, d+ O' B! ~" F, i6 C1 a, t
. h3 Y2 X0 S) u

2 ^+ {8 a" b' s' w接着使用命令“rmmod iTOP_IMX6_treedriver_hello”卸载模块,如下图所示,发现提示没有目录 4.1.15,这里我们新建“/lib/modules/4.1.15”。7 g- O; l) g; x" q2 Y. n
! I% T; ^* V2 i+ ~" k

2 |1 j" _5 [1 x) Q" l9 B, Z如下图所示,使用命令“mkdir /lib/modules/4.1.15”新建目录,再次使用命令“rmmod iTOP_IMX6_treedriver_helloello”卸载驱动模块。/ j  A( }4 H- s5 R9 I, {
8 Q8 |* F0 K" z2 P+ D0 [( ~

8 @$ m* k% I3 |) ^- `2 p发现打印信息“Hello world exit!”,模块卸载成功。
$ p7 g* z3 E/ O只要重新烧写系统,这些新建目录只需要建立一次即可。
6 Q: g! {, H* y' J- ~! x6 |
  ?/ h& d& P3 W; A" @
; A- W+ L, h: i5 h" ?

该用户从未签到

2#
发表于 2020-10-15 13:12 | 只看该作者
来学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 23:54 , Processed in 0.156250 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表