【鸿蒙】标准系统移植指南

电子说

1.3w人已加入

描述

标准系统移植指南

本文描述了移植一块开发板的通用步骤,和具体芯片相关的详细移植过程无法在此一一列举。后续社区还会陆续发布开发板移植的实例供开发者参考。

定义开发板

本文以移植名为 MyProduct 的开发板为例讲解移植过程,假定 MyProduct 是 MyProductVendor 公司的开发板,使用 MySoCVendor 公司生产的 MySOC 芯片作为处理器。

定义产品

在 //vendor/MyProductVendor/{product_name} 名称的目录下创建一个 config.json 文件,该文件用于描述产品所使用的 SOC 以及所需的子系统。配置如下:
//vendor/MyProductVendor/MyProduct/config.json

{
    "product_name": "MyProduct",
    "version": "3.0",
    "type": "standard",
    "target_cpu": "arm",
    "ohos_version": "OpenHarmony 1.0",
    "device_company": "MyProductVendor",
    "board": "MySOC",
    "enable_ramdisk": true,
    "subsystems": [
      {
        "subsystem": "ace",
        "components": [
          { "component": "ace_engine_lite", "features":[] }
        ]
      },
	...
    ]
}


主要的配置内容
 

鸿蒙


已定义的子系统可以在“//build/subsystem_config.json”中找到。当然你也可以定制子系统。
这里建议先拷贝 Hi3516DV300 开发板的配置文件,删除掉 hisilicon_products 这个子系统。这个子系统为 Hi3516DV300 SOC 编译内核,显然不适合 MySOC。

移植验证

至此,你可以使用如下命令,启动你产品的构建了:

./build.sh --product-name MyProduct 

构建完成后,可以在 //out/{device_name}/packages/phone/images 目录下看到构建出来的 OpenHarmony 镜像文件。

内核移植

这一步需要移植 Linux 内核,让 Linux 内核可以成功运行起来。

为 SOC 添加内核构建的子系统

修改文件 //build/subsystem_config.json 增加一个子系统。配置如下:

 "MySOCVendor_products": {
    "project": "hmf/MySOCVendor_products",
    "path": "device/MySOCVendor/MySOC/build",
    "name": "MySOCVendor_products",
    "dir": "device/MySOCVendor"
  },

接着需要修改定义产品的配置文件 //vendor/MyProductVendor/MyProduct/config.json,将刚刚定义的子系统加入到产品中。

编译内核

源码中提供了 Linux 4.19 的内核,归档在 //kernel/linux-4.19。本节以该内核版本为例,讲解如何编译内核。
在子系统的定义中,描述了子系统构建的路径 path,即 //device/MySOCVendor/MySOC/build。这一节会在这个目录创建构建脚本,告诉构建系统如何构建内核。
建议的目录结构:

├── build
│ ├── kernel
│ │     ├── linux
│ │           ├──standard_patch_for_4_19.patch // 基于4.19版本内核的补丁
│ ├── BUILD.gn
│ ├── ohos.build


BUILD.gn 是 subsystem 构建的唯一入口。
期望的构建结果

文件 文件说明
$root_build_dir/packages/phone/images/uImage 内核镜像
$root_build_dir/packages/phone/images/uboot bootloader 镜像

移植验证

启动编译,验证预期的 kernel 镜像是否成功生成。

用户态启动引导

1.用户态进程启动引导总览。
 

鸿蒙


系统上电加载内核后,按照以下流程完成系统各个服务和应用的启动:

1.内核启动 init 进程,一般在 bootloader 启动内核时通过设置内核的 cmdline 来指定 init 的位置;如上图所示的"init=/init root/dev/xxx"。
2.init 进程启动后,会挂载 tmpfs,procfs,创建基本的 dev 设备节点,提供最基本的根文件系统。
3.init 继续启动 ueventd 监听内核热插拔事件,为这些设备创建 dev 设备节点;包括 block 设备各个分区设备都是通过此事件创建。
4.init 进程挂载 block 设备各个分区(system,vendor),开始扫描各个系统服务的 init 启动脚本,并拉起各个 SA 服务。
5.samgr 是各个 SA 的服务注册中心,每个 SA 启动时,都需要向 samgr 注册,每个 SA 会分配一个 ID,应用可以通过该 ID 访问 SA。
6.foundation 是一个特殊的 SA 服务进程,提供了用户程序管理框架及基础服务;由该进程负责应用的生命周期管理。
7.由于应用都需要加载 JS 的运行环境,涉及大量准备工作,因此 appspawn 作为应用的孵化器,在接收到 foundation 里的应用启动请求时,可以直接孵化出应用进程,减少应用启动时间。
init。
init 启动引导组件配置文件包含了所有需要由 init 进程启动的系统关键服务的服务名、可执行文件路径、权限和其他信息。每个系统服务各自安装其启动脚本到 /system/etc/init 目录下。
新芯片平台移植时,平台相关的初始化配置需要增加平台相关的初始化配置文件 /vendor/etc/init/init.{hardware}.cfg;该文件完成平台相关的初始化设置,如安装 ko 驱动,设置平台相关的 /proc 节点信息。
init 相关进程代码在 //base/startup/init_lite 目录下,该进程是系统第一个进程,无其它依赖。

HDF 驱动移植

LCD

HDF 为 LCD 设计了驱动模型。支持一块新的 LCD,需要编写一个驱动,在驱动中生成模型的实例,并完成注册。
这些 LCD 的驱动被放置在 //drivers/hdf_core/framework/model/display/driver/panel 目录中。

1.创建 Panel 驱动
在驱动的 Init 方法中,需要调用 RegisterPanel 接口注册模型实例。如:

int32_t XXXInit(struct HdfDeviceObject *object)
{
    struct PanelData *panel = CreateYourPanel();
    // 注册
    if (RegisterPanel(panel) != HDF_SUCCESS) {
        HDF_LOGE("%s: RegisterPanel failed", __func__);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}
struct HdfDriverEntry g_xxxxDevEntry = {
    .moduleVersion = 1,
    .moduleName = "LCD_XXXX",
    .Init = XXXInit,
};
HDF_INIT(g_xxxxDevEntry);


2.配置加载 panel 驱动产品的所有设备信息被定义在文件 //vendor/MyProductVendor/MyProduct/config/device_info/device_info.hcs 中。修改该文件,在 display 的 host 中,名为 device_lcd 的 device 中增加配置。
注意:moduleName 要与 panel 驱动中的 moduleName 相同。

root {
    ...
    display :: host {
        device_lcd :: device {
            deviceN :: deviceNode {
                policy = 0;
                priority = 100;
                preload = 2;
                moduleName = "LCD_XXXX";
            }
        }
    }
}
​

触摸屏

本节描述如何移植触摸屏驱动。触摸屏的驱动被放置在 //drivers/hdf_core/framework/model/input/driver/touchscreen 目录中。移植触摸屏驱动主要工作是向系统注册 ChipDevice 模型实例。

1.创建触摸屏器件驱动
在目录中创建名为 touch_ic_name.c 的文件。代码模板如下:注意:请替换 ic_name 为你所适配芯片的名称。

#include "hdf_touch.h"
static int32_t HdfXXXXChipInit(struct HdfDeviceObject *device)
{
    ChipDevice *tpImpl = CreateXXXXTpImpl();
    if(RegisterChipDevice(tpImpl) != HDF_SUCCESS) {
        ReleaseXXXXTpImpl(tpImpl);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}
struct HdfDriverEntry g_touchXXXXChipEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_TOUCH_XXXX",
    .Init = HdfXXXXChipInit,
};
HDF_INIT(g_touchXXXXChipEntry);


其中 ChipDevice 中要提供若干方法。

鸿蒙

2.配置产品,加载器件驱动
产品的所有设备信息被定义在文件 //vendor/MyProductVendor/MyProduct/config/device_info/device_info.hcs 中。修改该文件,在名为 input 的 host 中,名为 device_touch_chip 的 device 中增加配置。注意:moduleName 要与触摸屏驱动中的 moduleName 相同。

deviceN :: deviceNode {
    policy = 0;
    priority = 130;
    preload = 0;
    permission = 0660;
    moduleName = "HDF_TOUCH_XXXX";
    deviceMatchAttr = "touch_XXXX_configs";
}

WLAN

Wi-Fi 驱动分为两部分,一部分负责管理 WLAN 设备,另一个部分负责处理 WLAN 流量。HDF WLAN 分别为这两部分做了抽象。目前支持 SDIO 接口的 WLAN 芯片。
图 1 WLAN 芯片

鸿蒙


支持一款芯片的主要工作是实现一个 ChipDriver 驱动。实现 HDF_WLAN_CORE 和 NetDevice 提供的接口。主要需要实现的接口有:

接口 定义头文件 说明
HdfChipDriverFactory //drivers/hdf_core/framework/include/wifi/hdf_wlan_chipdriver_manager.h ChipDriver 的 Factory,用于支持一个芯片多个 Wi-Fi 端口
HdfChipDriver //drivers/hdf_core/framework/include/wifi/wifi_module.h 每个 WLAN 端口对应一个 HdfChipDriver,用来管理一个特定的 WLAN 端口
NetDeviceInterFace //drivers/hdf_core/framework/include/net/net_device.h 与协议栈之间的接口,如发送数据、设置网络接口状态等

建议适配按如下步骤操作:

创建 HDF 驱动建议将代码放置在 //device/MySoCVendor/peripheral/wifi/chip_name/,文件模板如下:

static int32_t HdfWlanXXXChipDriverInit(struct HdfDeviceObject *device) {
    static struct HdfChipDriverFactory factory = CreateChipDriverFactory();
    struct HdfChipDriverManager *driverMgr = HdfWlanGetChipDriverMgr();
    if (driverMgr- >RegChipDriver(&factory) != HDF_SUCCESS) {
        HDF_LOGE("%s fail: driverMgr is NULL!", __func__);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}
struct HdfDriverEntry g_hdfXXXChipEntry = {
    .moduleVersion = 1,
    .Init = HdfWlanXXXChipDriverInit,
    .Release = HdfWlanXXXChipRelease,
    .moduleName = "HDF_WIFI_CHIP_XXX"
};
HDF_INIT(g_hdfXXXChipEntry);
​

在 CreateChipDriverFactory 中,需要创建一个 HdfChipDriverFactory,接口如下:

接口 说明
const char *driverName 当前 driverName
int32_t (*InitChip)(struct HdfWlanDevice *device) 初始化芯片
int32_t (*DeinitChip)(struct HdfWlanDevice *device) 去初始化芯片
void (_ReleaseFactory)(struct HdfChipDriverFactory _factory) 释放 HdfChipDriverFactory 对象
struct HdfChipDriver _(_Build)(struct HdfWlanDevice *device, uint8_t ifIndex) 创建一个 HdfChipDriver;输入参数中,device 是设备信息,ifIndex 是当前创建的接口在这个芯片中的序号
void (_Release)(struct HdfChipDriver _chipDriver) 释放 chipDriver
uint8_t (*GetMaxIFCount)(struct HdfChipDriverFactory *factory) 获取当前芯片支持的最大接口数

HdfChipDriver 需要实现的接口有:

接口 说明
int32_t (*init)(struct HdfChipDriver *chipDriver, NetDevice *netDev) 初始化当前网络接口,这里需要向 netDev 提供接口
int32_t (*deinit)(struct HdfChipDriver *chipDriver, NetDevice *netDev) 去初始化当前网络接口
struct HdfMac80211BaseOps *ops WLAN 基础能力接口集
struct HdfMac80211STAOps *staOps 支持 STA 模式所需的接口集
struct HdfMac80211APOps *apOps 支持 AP 模式所需要的接口集

2.编写配置文件,描述驱动支持的设备。
在产品配置目录下创建芯片的配置文件 //vendor/MyProductVendor/MyProduct/config/wifi/wlan_chip_chip_name.hcs。
注意: 路径中的 vendor_name、product_name、chip_name 请替换成实际名称。
模板如下:

root {
    wlan_config {
        chip_name :& chipList {
            chip_name :: chipInst {
                match_attr = "hdf_wlan_chips_chip_name"; /* 这是配置匹配属性,用于提供驱动的配置根 */
                driverName = "driverName"; /* 需要与HdfChipDriverFactory中的driverName相同*/
                sdio {
                    vendorId = 0x0296;
                    deviceId = [0x5347];
                }
            }
        }
    }
}
​

3.编写配置文件,加载驱动。
产品的所有设备信息被定义在文件 //vendor/MyProductVendor/MyProduct/config/device_info/device_info.hcs 中。修改该文件,在名为 network 的 host 中,名为 device_wlan_chips 的 device 中增加配置。
注意:moduleName 要与触摸屏驱动中的 moduleName 相同。

deviceN :: deviceNode {
    policy = 0;
    preload = 2;
    moduleName = "HDF_WLAN_CHIPS";
    deviceMatchAttr = "hdf_wlan_chips_chip_name";
    serviceName = "driverName";
}


4.构建驱动

  • 创建内核菜单在 //device/MySoCVendor/peripheral 目录中创建 Kconfig 文件,内容模板如下:
config DRIVERS_WLAN_XXX
    bool "Enable XXX WLAN Host driver"
    default n
    depends on DRIVERS_HDF_WIFI
    help
      Answer Y to enable XXX Host driver. Support chip xxx
​

接着修改文件 //drivers/hdf_core/adapter/khdf/linux/model/network/wifi/Kconfig,在文件末尾加入如下代码将配置菜单加入内核中,如:

source "../../../../../device/MySoCVendor/peripheral/Kconfig"

  • 创建构建脚本
    //drivers/hdf_core/adapter/khdf/linux/model/network/wifi/Makefile 文件末尾增加配置,模板如下:
HDF_DEVICE_ROOT := $(HDF_DIR_PREFIX)/../device
obj-$(CONFIG_DRIVERS_WLAN_XXX) += $(HDF_DEVICE_ROOT)/MySoCVendor/peripheral/build/standard/


当在内核中开启 DRIVERS_WLAN_XXX 开关时,会调用 //device/MySoCVendor/peripheral/build/standard/ 中的 makefile。

为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》,希望对大家有所帮助:

《鸿蒙(Harmony OS)开发学习手册》

入门必看https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.应用开发导读(ArKTS)
2.……

鸿蒙

HarmonyOS概念https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.系统定义
2.技术框架
3.技术特性
4.系统安全

鸿蒙

快速入门https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.基本概念
2.构建第一个ArkTS应用
3.……

鸿蒙

开发基础知识https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS
9…

鸿蒙

基于ArkTS 开发https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16………

鸿蒙

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分