Android linux firmware下载——续request_firmware之fw_path_para方式

683 阅读3分钟

安卓10固件下载——续

之前有写过一篇blog来分析安卓代码里固件下载部分的实现,链接:android8 linux内核下载固件函数request_firmware流程分析

但是最近在工作中,遇到了一种情况,在安卓文件系统的同一个目录,有时自己编写的固件下载函数能够成功,有时再重新烧录一遍系统以后就不成功了,总显示打开文件失败(至今不知为何,忘有大佬能指出可能存在的问题)。

在这种情况下,需要暂时使用安卓系统自带的request_firmware来下载固件,但代码自带的fw_path中的路径不包含我们需要存放固件的位置,同时又不希望修改fw_path变量,这就很尴尬。

查了很久的资料都没啥有效的,后又花几周仔细看了看安卓代码,发现还有以下这种方法可实现:可以利用fw_path_para

思路来源是在安卓源码中找到了一段话:
文件位置kernel/Documentation/driver-api/firmware/fw_search_path.rst

=====================
Firmware search paths
=====================

The following search paths are used to look for firmware on your
root filesystem.

* fw_path_para - module parameter - default is empty so this is ignored
* /lib/firmware/updates/UTS_RELEASE/
* /lib/firmware/updates/
* /lib/firmware/UTS_RELEASE/
* /lib/firmware/

The module parameter ''path'' can be passed to the firmware_class module
to activate the first optional custom fw_path_para. The custom path can
only be up to 256 characters long. The kernel parameter passed would be:

* 'firmware_class.path=$CUSTOMIZED_PATH'

There is an alternative to customize the path at run time after bootup, you
can use the file:

* /sys/module/firmware_class/parameters/path

You would echo into it your custom path and firmware requested will be
searched for there first.

以下代码均来自于android 10,本文是在上一篇博客的基础上写的,不是从开头讲起,如有疑问可以看下之前那篇。和上篇的Android版本虽不同,但文中涉及到的内容区别不大。

正文开始

文件位置rk3399-android-10/kernel/drivers/base/firmware_loader/main.c

/* direct firmware loading support */
static char fw_path_para[256];
static const char * const fw_path[] = {
        fw_path_para,
        "/lib/firmware/updates/" UTS_RELEASE,
        "/lib/firmware/updates",
        "/lib/firmware/" UTS_RELEASE,
        "/lib/firmware"
};

/*
 * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH'
 * from kernel command line because firmware_class is generally built in
 * kernel instead of module.
 */
module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");

上述代码,由注释及代码可知,在firmware_class模块内,声明了一个fw_path_para全局变量,而module_param_string使该变量可被模块外访问,外部访问的变量名是path,这个外部可见的path与模块内部可见的fw_path_para是同一个变量,只不过内外的叫法不同。

而安卓系统运行起来以后,在控制台,cd到/sys/module/下,ls所见的都是系统当前已加载的各个模块。再cd到firmware_class文件夹里,ls可以看到有parameters这个文件夹(每个模块对应的文件夹下都有parameters和uevents)。这个文件夹里是当前模块通过module_param系列函数声明的变量,firmware_class/parameters下的是path。

输入cat /sys/module/firmware_class/parameters/path可以查看当前path的值,也就是上述main.c中fw_path_para的值。

想要改变这个path有两类:一种是暂时的,每次重启系统后都失效;另一种是永久的。

暂时的就是,在每次系统运行起来以后,修改firmware_class/parameters/path的值。cd到parameters目录,如果想要存放固件的目录是/vendor/firmware/,则su进入管理员模式,输入echo -n "/vendor/firmware" > /sys/module/firmware_class/parameters/path

如果不加-n,则path的值会带着换行符,在后续代码的生成完整固件路径的时候也会带着这个换行符,效果例如:

“/vendor/firmware/
test.bin”

firmware后也不要加“/”,否则会多出一个“/”,如:

“/vendor/firmware//test.bin"。

写完后可以cat输出一下,看是否成功。此时再尝试固件下载调用request_firmware可成功。

永久的改变,自然是在系统初始化该变量的时候就修改成自己需要的位置。对应的修改在~/rk3399-android-10/device/rockchip/common/BoardConfig.mk

ifneq ($(filter true, $(BOARD_AVB_ENABLE)), )
BOARD_KERNEL_CMDLINE := androidboot.wificountrycode=US androidboot.hardware=rk30board androidboot.console=ttyFIQ0 firmware_class.path=/vendor/firmware init=/init rootwait ro init=/init
else # BOARD_AVB_ENABLE is false
BOARD_KERNEL_CMDLINE := console=ttyFIQ0 androidboot.baseband=N/A androidboot.wificountrycode=US androidboot.veritymode=enforcing androidboot.hardware=rk30board androidboot.console=ttyFIQ0 androidboot.verifiedbootstate=orange firmware_class.path=/vendor/firmware init=/init rootwait ro
endif # BOARD_AVB_ENABLE

此处,将两处firmware_class.path=都置为目的存放位置。重新编译系统,系统运行起来,在控制台输入cat查看path的值,会发现它与BoardConfig.mk里设置的一致。