鸿蒙的驱动子系统-3-驱动相关模块的编译 原创 精华

liangkz_梁开祝
发布于 2021-8-10 17:41
浏览
3收藏

鸿蒙的驱动子系统-3

驱动相关模块的编译

liangkz 2021.08.10

 

打开并查看 //vendor/hisilicon/hispark_taurus/config.json, 这是小型系统Hi3516开发板的产品配置表,仔细查看与驱动紧密相关的子系统和组件有:

      {
        "subsystem": "kernel",
        "components": [
          { "component": "liteos_a", "features":[] }
        ]
      },

      {
        "subsystem": "drivers",
        "components": [
          { "component": "drivers_framework", "features":[] },
          { "component": "adapter_uhdf", "features":[] },
          { "component": "peripheral_display", "features":[] },
          { "component": "peripheral_input", "features":[] },
          { "component": "peripheral_sensor", "features":[] },
          { "component": "peripheral_wlan", "features":[] }
        ]
      },

      {
        "subsystem": "vendor",
        "components": [
          { "component": "hi3516dv300_init", "features":[] },
          { "component": "hardware", "features":[] },
          { "component": "middleware", "features":[] }
        ]
      },

结合//build/lite/components/目录下对应的 json文件,列出下表:

鸿蒙的驱动子系统-3-驱动相关模块的编译-鸿蒙开发者社区

上表包含了整个驱动子系统的编译相关内容,互相交叉,关系稍微有点复杂,我花了一点时间做了梳理,先把一些要点做一下总结:

1. //drivers/framework/ 目录是纯代码目录,不包含编译配置脚本文件,对该目录代码文件的编译配置文件都在 //drivers/adapter/目录下了,分成两部分:

  • uhdf 部分是编译framework部署在用户空间的代码,见上表中adapter_uhdf部分。
  • khdf 部分是编译framework部署在内核空间的代码,上表中没有体现出来,但是在编译 liteos_a:kernel 的时候,会通过kernel模块的mk去include这里的 ./khdf/liteos/目录下的mk,从而触发khdf部分的编译。

2.  liteos_a:kernel 和framework的khdf部分的编译,会由 hi3516dv300_init 组件的编译来触发,最终生成了OHOS_Image*四个镜像文件。上表只做了简单地描述,可以去阅读和分析//device/hisilicon/build/hi3516dv300/ 目录下的几个编译脚本,顺着编译流程去做理解,下文会做进一步地展开分析。

 

3. //drivers/peripheral/ 目录下的几个模块,会被编译成对应的动态链接库文件,部署到 rootfs/usr/lib/目录下。

4. hardware和middleware两个组件,都是根据各自目录下的 BUILD.gn和build.sh脚本,对相关目录的代码进行编译,或者对子目录下的预编译库文件做选择,最终将库文件拷贝到项目输出根目录下,打包生成rootfs时,部署到rootfs/usr/lib/目录下

 

上面1.uhdf和3/4的编译输出,都部署在鸿蒙系统的用户空间,直接阅读编译脚本基本上就可以理解了,本文就不做详细分析了。

而1.khdf和2的编译有密切的相关性,其输出一并打包到OHOS系统镜像中,下面就来详细看一下。

 

从 hi3516dv300_init 组件的编译脚本 //device/hisilicon/build/hi3516dv300/BUILD.gn 入手:

build_ext_component("hi3516dv300_image") {
  exec_path = rebase_path(".", root_build_dir)
  outdir = rebase_path("$root_out_dir")
  command = "./build.sh ${outdir} ${device_path} ${board} ${ohos_kernel_type} ${ohos_build_compiler}"
  deps = [ "//kernel/liteos_a:kernel" ]
}

依赖liteos_a:kernel组件,执行这里的build.sh,根据参数,拷贝一组.so文件后,执行make。查看Makefile和hi3516dv300.mak,可以知道这是要编译 sdk_init和system_init 并打包生成 OHOS_Image 镜像。

 

编译liteos_a:kernel组件,入口则在 //kernel/liteos_a/BUILD.gn,

build_ext_component("make") {
  exec_path = rebase_path(".", root_build_dir)
  tee_enable = "false"
  if (board_name == "hi3516dv300" && enable_tee_ree) {
    tee_enable = "tee"
  }
  prebuilts = "sh build.sh ${board_name} ${ohos_build_compiler} ${root_build_dir} ${ohos_build_type} ${tee_enable} \"${device_company}\" \"${product_path}\""
  outdir = rebase_path(get_path_info(".", "out_dir"))
  command = "make clean OUTDIR=$outdir && make rootfs VERSION=\"${ohos_version}\" -j 16 OUTDIR=$outdir"
}

根据build的参数,到 //kernel/liteos_a/tools/build/config/ 目录下寻找一个匹配的config文件,拷贝到 //kernel/liteos_a/.config,但这还不是.config的全部,执行make时,根据Kconfig的配置,层层将编译内核的默认配置收集汇总到.config文件内,driver部分就包含了:

######################## config options os drivers ########################
menu "Driver"
config DRIVERS
    bool "Enable Driver"
    default y
    help
      Answer Y to enable LiteOS support driver.

source "../../kernel/liteos_a/bsd/dev/usb/Kconfig"
source "../../drivers/adapter/khdf/liteos/Kconfig"

这就把 //drivers/adapter/khdf/ 模块的编译配置包含进来了,并且由这个Kconfig关联驱动模块的其他Kconfig:

source "../../drivers/adapter/khdf/liteos/model/bus/usb/Kconfig"
source "../../drivers/adapter/khdf/liteos/test/Kconfig"
source "../../drivers/adapter/khdf/liteos/model/display/Kconfig"
source "../../drivers/adapter/khdf/liteos/model/input/Kconfig"
source "../../drivers/adapter/khdf/liteos/model/sensor/Kconfig"

source "../../device/hisilicon/drivers/Kconfig"

经过这一步,编译内核的所有配置项都集中到了.config文件中。

 

 

再看 //kernel/liteos_a/config.mk:

-include $(LITEOSTOPDIR)/tools/build/mk/los_config.mk

打开这个 los_config.mk,找到driver部分:

################################## Driver Option Begin #################################
ifeq ($(LOSCFG_DRIVERS_HDF), y)
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/hdf_lite.mk
endif

【*】再打开这个hdf_lite.mk,找到下面这段:

HAVE_VENDOR_CONFIG := $(shell if [ -d $(LITEOS_SOURCE_ROOT)/vendor/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config ]; then echo y; else echo n; fi)
ifeq ($(LOSCFG_DRIVERS_HDF_TEST), y)
include $(LITEOS_DRIVERS_HDF)/test/test_lite.mk
# test
    LITEOS_BASELIB += -lhdf_test
    LIB_SUBDIRS    += $(LITEOS_DRIVERS_HDF)/test

                                   #//drivers/adapter/khdf/liteos/test,通过Makefile可以编译驱动子系统的测试文件

    LITEOS_BASELIB += -lhdf_test_config
    LIB_SUBDIRS += $(LITEOS_SOURCE_ROOT)/vendor/$(LOSCFG_DEVICE_COMPANY)/$(LOSCFG_PRODUCT_NAME)/config/hdf_test

                                #//vendor/hisilicon/hispark_taurus/config/hdf_test

    #这里并不显式地去编译hdf_config,即显式地执行Makefile,
    #而是通过hdf_test/hdf_test.hcs 里面的 #include "../hdf.hcs" 去将其编译到
    # ./out/hispark_taurus/ipcamera_hispark_taurus/obj/kernel/liteos_a/lib/libhdf_test_config.a 里面去
else
# config
    LITEOS_BASELIB += -lhdf_config
ifeq ($(HAVE_VENDOR_CONFIG), y)
    LIB_SUBDIRS += $(LITEOS_SOURCE_ROOT)/vendor/$(LOSCFG_DEVICE_COMPANY)/$(LOSCFG_PRODUCT_NAME)/config

    #要是上面LOSCFG_DRIVERS_HDF_TEST是 n,不编译hdf_test/,这里才会显式地编译 hdf_config,执行这个目录下的Makefile指令,

    # ./out/hispark_taurus/ipcamera_hispark_taurus/obj/kernel/liteos_a/lib/libhdf_config.a 里面去
else
    LIB_SUBDIRS += $(LITEOS_SOURCE_ROOT)/device/$(LOSCFG_DEVICE_COMPANY)/$(LOSCFG_PRODUCT_NAME)/config
endif
endif

通过参数对路径下的config进行确认,HAVE_VENDOR_CONFIG 是存在的,也就是y,上面的.config中,LOSCFG_DRIVERS_HDF_TEST也是默认配置为y的,会跑# test这个,而不是# config。

LIB_SUBDIRS += //vendor/hisilicon/hispark_taurus/config/hdf_test

而不是 //device/hisilicon/hispark_taurus/sdk_liteos/config 下的 config 目录。

 

【**】进入//vendor/hisilicon/hispark_taurus/config/hdf_test/目录查看 Makefile 文件:

include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk

MODULE_NAME := hdf_test_config
LOCAL_HCS_ROOT := $(shell pwd)

LOCAL_PLATFORM_HCS_SRC := hdf_test.hcs

include $(HDF_DRIVER)

再去打开这个lite.mk,最后面有一句:

HDF_DRIVER = $(HDF_ROOT_DIR)/adapter/khdf/liteos/hdf_driver.mk

再打开这个hdf_driver.mk

HAVE_VENDOR_CONFIG := $(shell if [ -d $(LITEOS_SOURCE_ROOT)/vendor/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config ]; then echo y; else echo n; fi)

ifeq ($(LOCAL_HCS_ROOT),)
ifeq ($(HAVE_VENDOR_CONFIG), y)
LOCAL_HCS_ROOT := $(abspath $(LITEOSTOPDIR)/../../vendor/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config)
else
LOCAL_HCS_ROOT := $(abspath $(LITEOSTOPDIR)/../../device/$(patsubst "%",%,$(LOSCFG_DEVICE_COMPANY))/$(patsubst "%",%,$(LOSCFG_PRODUCT_NAME))/config)
endif
endif

所以LOCAL_HCS_ROOT是vendor的://vendor/hisilicon/hispark_taurus/config

而不是device目录下的 //device/hisilicon/hispark_taurus/sdk_liteos/config

 

 

回到上面【**】 //vendor/hisilicon/hispark_taurus/config/hdf_test/Makefile 文件,要编译 hdf_test.hcs,打开该文件:

#include "../hdf.hcs"
#include "hdf_test_manager/device_info.hcs"
#include "gpio_test_config.hcs"
#include "i2c_test_config.hcs"
#include "spi_test_config.hcs"
#include "uart_test_config.hcs"
#include "hdf_config_test.hcs"
#include "sdio_test_config.hcs"
#include "emmc_test_config.hcs"
#include "pwm_test_config.hcs"

也就是编译hdf_test目录下的 测试相关的 hcs 之外,还编译上一级目录的 hdf.hcs,再打开这个 hdf.hcs 文件:

#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/i2c/i2c_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/gpio/gpio_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/uart/uart_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/sdio/sdio_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/emmc/emmc_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/watchdog/watchdog_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/usb/usb_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/rtc/rtc_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/spi/spi_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/pwm/pwm_config.hcs"
#include "../../../../device/hisilicon/hispark_taurus/sdk_liteos/config/dmac/dmac_config.hcs"

 

#include "device_info/device_info.hcs"
#include "wifi/wlan_platform.hcs"
#include "wifi/wlan_chip_hi3881.hcs"
#include "lcd/lcd_config.hcs"
#include "input/input_config.hcs"
#include "sensor/sensor_config.hcs"


#include "../../../../vendor/huawei/hdf/sample/config/uart/uart_config.hcs"
#include "../../../../vendor/huawei/hdf/sample/config/device_info/device_info.hcs"

从这里可以看出,//device/hisilicon/hispark_taurus/sdk_liteos/config 目录下的 hcs 文件,除了device_info、input、lcd、wifi四个模块并不参与编译之外,大部分都会得到编译,而这四个模块在vendor目录下都有对应的 hcs 来替代。实际上对比一下device和vendor目录下的这四个模块,差别不大。

最后面的两句include hdf/sample 的hcs,就是前文《小型系统驱动示例程序的编译和验证》中添加进来的,编译示例程序的hcs文件。

 

全工程搜索文件 hdf.hcs 和 device_info.hcs:

ohos@ubuntu:~/Ohos/B_LTS$ find ./ -name hdf.hcs
./device/hisilicon/hispark_aries/sdk_liteos/config/hdf.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/hdf.hcs 【不编译】
./device/qemu/arm_virt/config/hdf.hcs
./vendor/hisilicon/hispark_aries/config/hdf.hcs
./vendor/hisilicon/hispark_taurus/config/hdf.hcs 【编译,hdf_test.hcs -->> hdf.hcs】
ohos@ubuntu:~/Ohos/B_LTS$find ./ -name device_info.hcs
./device/hisilicon/hispark_aries/sdk_liteos/config/device_info/device_info.hcs
./device/hisilicon/hispark_taurus/sdk_liteos/config/device_info/device_info.hcs【不编译】
./device/qemu/arm_virt/config/device_info/device_info.hcs
./vendor/huawei/hdf/sample/config/device_info/device_info.hcs【编译,device_info.hcs -->> sample/.../device_info.hcs】
./vendor/hisilicon/hispark_aries/config/device_info/device_info.hcs
./vendor/hisilicon/hispark_aries/config/hdf_test/hdf_test_manager/device_info.hcs
./vendor/hisilicon/hispark_taurus/config/device_info/device_info.hcs 【编译,hdf.hcs -->> device_info.hcs】
./vendor/hisilicon/hispark_taurus/config/hdf_test/hdf_test_manager/device_info.hcs 【编译,hdf_test.hcs -->> hdf_test_manager/device_info.hcs】

把无关的先去除,剩下的就是就是上面几个了。

 

上面就是对驱动子系统的驱动配置和设备树描述文件(.hcs)的编译关系的梳理,上面【*】提到的 hdf_driver.mk 的作用,就是配置编译工具,将 *.hcs 配置文件编译成 *_hex.c,再编译成 *.o和 *.hcb 文件,存放在:项目输出根目录下的/obj/kernel/liteos_a/obj/vendor/hisilicon/hispark_taurus/config/hdf_test_config/config/目录下。

 

至于驱动子系统部署在内核空间部分代码的编译,则需要到 //drivers/adapter/khdf/liteos/Makefile 来查看:

include $(LITEOSTOPDIR)/config.mk          #//kernel/liteos_a/config.mk 
include ./lite.mk                                          #HDF_DRIVER = $(HDF_ROOT_DIR)/adapter/khdf/liteos/hdf_driver.mk  上面有展开

MODULE_NAME := hdf

HDF_FRAMEWORKS = ../../../framework

根据source,编译出libhdf.a静态链接库文件到 //out/.../obj/kernel/liteos_a/lib/libhdf.a,生成OHOS_Image镜像时将其链接进去。

 

而//device/hisilicon/drivers/lite.mk 则描述了具体的驱动模块代码编译成对应的静态库文件,文件末尾的:

LITEOS_BASELIB += -lhdf_uart_sample
LIB_SUBDIRS    += $(LITEOSTOPDIR)/../../vendor/huawei/hdf/sample/platform/uart

就是前文《小型系统驱动示例程序的编译和验证》添加上去的,让例子程序的内核部分参与编译,生成静态库文件,生成OHOS_Image镜像时将其链接进去。

 

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2021-8-10 17:41:43修改
7
收藏 3
回复
举报
4条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

单独将楼主的表收藏一份

1
回复
2021-8-10 17:53:35
Anzia
Anzia

好羡慕你呀,我上班看这些子系统的源码都看不懂,欠的前置知识太多了

 

回复
2021-8-11 00:20:13
liangkz_梁开祝
liangkz_梁开祝 回复了 Anzia
好羡慕你呀,我上班看这些子系统的源码都看不懂,欠的前置知识太多了

知道欠缺就恶补,你们是潜力股。

回复
2021-8-11 08:23:26
wx616d8dee1ba97
wx616d8dee1ba97

请问标准系统的驱动编译配置有参考例子吗

回复
2021-11-2 14:51:57
回复
    相关推荐