22、TSP内核配置:Kconfig配置、Makefile编写、模块编译

好,咱们今天聊聊TSP驱动在内核里是怎么“注册”进去的。说白了,就是让Linux内核知道“嘿,这儿有个触摸屏驱动,你得编译它、加载它”。

这部分工作,我把它分成三块:Kconfig配置Makefile编写、以及模块编译。这三块是连着的,缺一个都不行。我刚开始接触内核驱动时,就吃过这个亏——Kconfig写对了,Makefile忘了加,结果make menuconfig里死活看不到我的驱动选项。嗯,这种坑,咱们今天一并填上。

Kconfig配置:给驱动一个“开关”

Kconfig是内核的配置系统。你运行make menuconfig时看到的那些菜单,就是Kconfig文件定义的。我们要做的,就是给TSP驱动加一个配置项,让开发者可以选择“编译进内核”还是“编译成模块”。

我个人习惯把TSP驱动的Kconfig放在drivers/input/touchscreen/目录下。打开这个目录下的Kconfig文件,添加如下内容:

config TOUCHSCREEN_TSP
    tristate "TSP Touchscreen support"
    depends on I2C
    help
      Say Y here if you want to support TSP touchscreen.
      If unsure, say N.

      To compile this driver as a module, choose M here.
      The module will be called tsp.ko.

这里有几个关键点:

  • tristate:表示三态——Y(编译进内核)、M(编译成模块)、N(不编译)。触摸屏驱动一般选M,方便调试和更新。
  • depends on I2C:TSP大部分走I2C总线,所以依赖I2C子系统。如果你用的SPI,就写depends on SPI
  • help:写清楚这个驱动是干什么的。别偷懒,以后你自己回头看代码时,help信息能救命。
我的小技巧: 我习惯在Kconfig里加一个default n。为什么?因为默认关闭,避免新手一不留神把驱动编进内核,结果硬件没接好导致系统启动卡死。安全第一。

Makefile编写:告诉编译器怎么干活

Kconfig只是定义了“开关”,Makefile才是真正告诉编译器“哪些文件要编译、怎么编译”的地方。同样在drivers/input/touchscreen/目录下,找到Makefile,添加一行:

obj-$(CONFIG_TOUCHSCREEN_TSP) += tsp.o

这行代码的意思是:如果CONFIG_TOUCHSCREEN_TSP被配置为Y或M,就编译tsp.o。如果配置为N,这行就相当于被注释掉了。

如果你的驱动由多个源文件组成,比如tsp_core.ctsp_i2c.ctsp_fw.c,可以这样写:

obj-$(CONFIG_TOUCHSCREEN_TSP) += tsp.o
tsp-objs := tsp_core.o tsp_i2c.o tsp_fw.o

这里tsp-objs指定了最终生成tsp.o需要哪些目标文件。内核的构建系统会自动把它们链接到一起。

注意: 我曾经犯过一个低级错误——文件名写成了tsp-core.c,但Makefile里写的是tsp_core.o。内核编译时找不到文件,报错信息还特别隐晦。折腾了半天才发现是下划线和连字符的问题。所以,文件名和Makefile里的名字必须完全一致,包括大小写和分隔符。

模块编译:从源码到.ko文件

Kconfig和Makefile都准备好了,接下来就是编译。有两种方式:

方式一:在内核源码树内编译

如果你有完整的内核源码,并且已经配置过(比如运行过make defconfigmake menuconfig),直接:

make modules
make modules_install

内核构建系统会自动扫描所有Makefile,找到obj-$(CONFIG_TOUCHSCREEN_TSP)对应的文件,编译生成tsp.ko

方式二:外部模块编译(我最常用的方式)

实际项目中,我们往往不编译整个内核,只编译自己的驱动模块。这时候用外部模块编译:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

这条命令的意思是:到内核构建目录(-C参数)去找头文件和Makefile规则,然后编译当前目录(M=$(pwd))下的模块。

编译成功后,你会看到:

Building modules, stage 2.
MODPOST 1 modules
CC [M]  /home/user/tsp/tsp.mod.o
LD [M]  /home/user/tsp/tsp.ko

嗯,看到tsp.ko生成,心里就踏实了。

加载与测试

模块编译好了,怎么用?

  • 加载模块sudo insmod tsp.ko
  • 查看模块信息modinfo tsp.ko(会显示作者、描述、依赖等)
  • 卸载模块sudo rmmod tsp
  • 查看内核日志dmesg | tail(看驱动有没有打印信息)
避坑指南: 我曾经在加载模块时遇到insmod: ERROR: could not insert module tsp.ko: Unknown symbol。这是因为模块依赖的某个内核符号没有导出。解决办法:检查/proc/kallsyms里有没有你调用的函数,或者用modprobe代替insmod,它会自动处理依赖。

知识体系图

下面这张图总结了TSP内核配置到模块编译的完整流程:

TSP内核配置与编译流程 Kconfig配置 定义配置选项 tristate / depends on Makefile编写 指定编译规则 obj-$(CONFIG_...) += 模块编译 生成 .ko 文件 make modules 方式一:内核源码树内编译 make modules && make modules_install 方式二:外部模块编译 make -C /lib/modules/... M=$(pwd) 输出:tsp.ko 内核模块文件 加载与测试 insmod / rmmod / dmesg

这张图从左到右展示了从Kconfig定义、Makefile编写,到两种编译方式,最终生成tsp.ko并加载测试的完整链路。你想想看,每一步都环环相扣,少了哪个环节,驱动都跑不起来。

总结一下

Kconfig是“开关”,Makefile是“配方”,编译是“烹饪”。三者配合好了,你的TSP驱动才能顺利变成内核的一部分。我个人建议初学者先从外部模块编译开始,这样不用每次修改代码都重新编译整个内核,省时间。

嗯,这部分内容就到这里。记住:配置无小事,一个字母错了,可能就要折腾半天。细心一点,后面会省很多事。


公众号:蓝海资料掘金营,微信deep3321