|
[导读] 回想自己刚刚学写Linux 驱动时,觉得很难,简直无从下手。现在写公众号,也常遇到一些朋友对于写一个Linux驱动不知道这个驱动究竟如何编译、如何装载、如何测试,本文就如何编译进内核或者模块来聊一聊我的一些体会。 大家周末好,最近来了很多新朋友,感谢小伙伴们关注小号,让我们一起进步,一起成长!如果喜欢小号请星标,星标的作用将会使本号最新文章在列表中置顶,这样就不会错过推送的文章了。 基本概念要学习Linux驱动开发,个人体会是要建立清晰的概念,对于概念尽量理解清楚其内涵以及作用。 驱动模型先来看看驱动处在Linux系统中的什么位置:
这里有两个重要概念需要理解,啥是内核空间?啥又是用户空间?现代宏操作系统(相对于微内核而言)通常将虚拟内存分割隔离成内核空间和用户空间两个部分。或许会问为啥要这样处理呢?这样隔离分割可提供内存保护和硬件保护,以防止恶意或错误的软件行为。再进一步说说就好理解了,用户空间需要访问内核空间需要访问内核空间以及底层设备要怎么做呢?利用操作系统提供的操作系统调用(OS API)进而访问内核空间,这些操作接口是内核经过精心设计且提供了完备的保护机制,故而对内核空间是安全的。 内核职责对于Linux内核而言,其主要功能职责有这么几个:
Linux 内核架构分析) ]; d( K( U3 W7 h, S8 ` 驱动类型 回到驱动这个概念,Linux驱动已基本明了在整个系统中处于什么位置。Linux根据设备特点,将设备驱动程序大致分为下面三大类:
刚刚接触Linux设备驱动开发的朋友,往往对这一步会不知道如何下手,这里来描述一下两种方式。这是本文想重点想分享的内容。 Linux内核代码主要采用了Kconfig/Makefile进行配置以及构建管理。
以<<Linux设备驱动程序>>中hello word代码进行说明。 #include <linux/module.h>#include <linux/init.h>9 Q0 n5 M2 R; V3 S MODULE_LICENSE("Dual BSD/GPL");- n; _) k, B, \+ A# l static int hello_init(void) { printk(KERN_ALERT "Hello word"); return 0;9 O* X2 r1 W. t- p& q1 k( A* g- G } static void hello_exit(void), }1 x$ J- J/ R8 S2 S0 u% s5 s8 | {3 @' o3 `$ u1 h3 o; u! L printk(KERN_ALERT "Goodbye,Hello word");7 t1 j( }8 j, ~/ ^2 ^3 ?* X } ! A: [& y! H; p4 ^ /* register the init and exit routine of the module */, }) L" U, f3 y module_init( hello_init ); module_exit( hello_exit );9 @1 {2 p" g- c/ |) e7 T; h 1.在./driver下创建目录,比如创建为hello文件夹
2.在该文件夹创建hello.c将上述代码编辑进这个文件保存,具体怎么操作就不详述了。 3.在该文件夹下创建Kconfig,Makefile两个文件
Kconfig内容:( J5 U' T0 z. F& o" z* @ tristate "hello driver" : T+ z2 }" C2 K$ Q5 u. D& _. J help This hello driver is just to shaow how to develop driver process.$ a+ D9 z, Y5 T: M, ^ 1 }. D; l0 O- Y This driver can also be built as a module. If so, the module. g" u7 u; {. ~- R. A+ m will be called . default y - t! ^8 x/ d6 q' o/ P( h #endmenu 表示如果使能了CONFIG_HAVE_HELLO在内核裁剪配置文件中,将显示hello driver菜单,默认编译进内核:
Makefile内容: obj-$(CONFIG_HAVE_HELLO) += hello.o表示CONFIG_HAVE_HELLO使能时,编译规则指定的文件为hello.c 4.编辑driver顶层的Kconfig,Makefile文件 Kconfig文件 menu "Device Drivers", W9 m1 w0 [# ^- h3 ~( y9 Dsource "drivers/amba/Kconfig" ......4 `. J. P. }, ~% s; \$ N8 ] 6 y# o# ?; z {% @/ S; w0 h source "drivers/hello/Kconfig"% a" f5 B' p% F8 F5 ]3 x endmenu 在endmenu前添加hello文件夹的配置文件解析:source "drivers/hello/Kconfig" 如此一来,配置系统就会按照这个配置去解析hello文件夹下的Kconfig Makefile文件: #3 V* U) d( u% M' F2 M1 ]: {& Q' L7 \# Makefile for the Linux kernel device drivers. #0 [7 o% E. \5 s # 15 Sep 2000, Christoph Hellwig <hch@infradead.org>1 K6 ^. p/ }* m* ~ # Rewritten to use lists instead of if-statements. #1 X& \. R* }( u obj-y += irqchip/ obj-y += bus/4 Q2 c% F+ Q, @: _& O) g7 X .......# I1 u& j' J& ` c# a S! M3 W5 |$ [9 I obj-$(CONFIG_HAVE_HELLO) += hello/ 在原Makefile后添加obj-$(CONFIG_HAVE_HELLO) += hello/,这句话的作用是当CONFIG_HAVE_HELLO使能后,在哪里去找源文件。在结合hello文件下模块Makefile就形成了层次式Makefile 接下来看看如何编译。 编译首先调用make distclean,清除原来的配置。
然后调用make ARCH=arm xxx_defconfig:
configuration written to .config表示这步操作成功,如果失败检查Kconfig配置是否出错。 ARCH=arm 表示使用的是ARM平台的目标机,如nanopi2_linux_defconfig 表示配置文件,该文件存在于:
然后来看看hello是否生效,调用make ARCH=arm menuconfig
进入Device Drivers子目录,移动光标到最底部,就看到添加的hello driver配置菜单了。
那么这里如前文所说我们有这么几种选择:
选择好,保存配置,剩下就是编译了: 编译进内核:
编译为模块:
最后在./driver/hello文件下生成hello.ko就成了,剩下就是动态加载调试了。 总结一下通过上文阅读,应能掌握如何配置、编译进内核或者模块的基本操作,对于刚入手学习Linux驱动开发属于必掌握的基本操作,由于书籍中少有这种实战介绍,所以这里总结分享一下这些基础操作。当然对于熟悉了内核驱动开发而言,完全可以直接编辑xxx_defconfig,如如这里可以这么做: CONFIG_HELLO_DRIVER=m这就修改为=y表示编译进内核,=m表示编译为模块,=n表示不使能. ) O- A- t2 n3 H9 K+ R |
| 顶一下 |
微信公众号
手机版