【鸿蒙南向开发】OpenHarmony-HDF驱动框架介绍及加载过程

51 篇文章 0 订阅
51 篇文章 0 订阅

前言

互联网经历了移动互联网的大发展之后,将迎来万物互联时代,而万物互联除了包含传统的网络设备,如服务器,手持终端等等富设备,还需要连接大量的微小型终端硬件设备,这些设备硬件的离散度很高,它们的使用场景,可用计算资源差异都很大。,所以这要求使用一个更灵活、功能更强大、能耗更低的驱动框架。OpenHarmony 系统 HDF 驱动框架正是为了满足这些需要而设计,采用 C 语言面向对象编程模型构建,通过平台解耦、内核解耦,来达到兼容富设备以及轻设备的不同大小内核,统一平台底座的目的,从而帮助开发者实现驱动一次开发,多系统部署的效果。

1.HDF 驱动框架

OpenHarmony 系统 HDF 驱动框架主要由驱动管理框架、驱动程序、驱动配置文件和驱动接口这四个部分组成。

1)HDF 驱动管理框架由 Device Manager 和 Device Host 组成,提供统一的硬件资源管理,驱动加载管理以及设备节点管理等功能。驱动框架采用的是主从模式设计。Device Manager 提供了统一的驱动管理,Device Manager 启动时根据 Device Information 驱动配置文件提供的驱动设备信息加载相应的驱动 Device Host,并控制 Host 完成驱动的加载。Device Host 提供驱动运行的环境,同时预置 Host Framework 与 Device Manager 进行协同,完成驱动加载和调用。根据业务的需求 Device Host 可以有多个实例。

2)驱动程序 Driver 实现驱动具体的功能,每个驱动由一个或者多个驱动程序组成,每个驱动程序都对应着一个 Driver Entry。Driver Entry 主要完成驱动的初始化和驱动接口绑定功能。

3)驱动配置文件主要由设备信息(Device Information)和设备资源(Device Resource)组成,分别对应 deviceInfo.hcs 和 deviceRes.hcs 两个配置文件。Device Information 完成设备信息的配置。如配置接口发布策略,驱动加载的方式等。Device Resource 完成设备资源的配置。如 GPIO 管脚、寄存器等资源信息的配置。另外还可以通过 deviceMatchAttr 来指定自定义参数配置文件。

4)驱动接口 HDI(Hardware Driver interface )提供标准化的接口定义和实现,驱动框架提供 IO Service 和 IO Dispatcher 机制,使得不同部署形态下驱动接口趋于形式一致。具体的驱动实现不需要再重复定义 HDI 接口,只需要按 HDI 接口实现即可将设备接入系统,从而保证了上层调用者无需改动即可访问操作新适配的设备。

HDF 框架以组件化的驱动模型作为核心设计思路,通过 HCS 配置文件为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF 框架将一类设备驱动放在同一个 host 里面,一个驱动可包含多个驱动程序,HDF 驱动模型的配置文件以及对应结构图示如下所示:

distributed_camera_host :: host {
            hostName = "dcamera_host";
            priority = 50;
            distributed_camera_device :: device {
                device0 :: deviceNode {
                    policy = 2;
                    priority = 100;
                    preload = 2;
                    moduleName = "libdistributed_camera_host_config.z.so";
                    serviceName = "distributed_camera_service";
                }
                device1 :: deviceNode {
                    policy = 2;
                    priority = 100;
                    preload = 2;
                    moduleName = "libdistributed_camera_provider_config.z.so";
                    serviceName = "distributed_camera_provider_service";
                }
            }
        }
        codec :: host {
            hostName = "codec_host";
            priority = 50;
            gid = ["codec_host", "uhdf_driver", "vendor_mpp_driver"];
            codec_omx_device :: device {
                device0 :: deviceNode {
                    policy = 2;
                    priority = 100;
                    moduleName = "libcodec_hdi_omx_server.z.so";
                    serviceName = "codec_hdi_omx_service";
                    deviceMatchAttr = "media_codec_capabilities";
                }
            }
        }
​

2.HDF 驱动开发

基于 HDF 框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示:

2.1 驱动实现

驱动实现包含驱动业务代码和驱动入口注册。

2.1.1 驱动业务代码

#include "hdf_device_desc.h"          // HDF框架对驱动开发相关能力接口的头文件
#include "hdf_log.h"                  // HDF框架提供的日志接口头文件

#define HDF_LOG_TAG sample_driver     // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签。

// 将驱动对外提供的服务能力接口绑定到HDF框架。
int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("Sample driver bind success");
    return HDF_SUCCESS;
}

// 驱动自身业务初始化的接口
int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("Sample driver Init success");
    return HDF_SUCCESS;
}

// 驱动资源释放的接口
void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGD("Sample driver release success");
    return;
}

2.1.2 驱动入口注册到 HDF 框架

// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量。
struct HdfDriverEntry g_sampleDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "sample_driver",
    .Bind = HdfSampleDriverBind,
    .Init = HdfSampleDriverInit,
    .Release = HdfSampleDriverRelease,
};

// 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动;当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
HDF_INIT(g_sampleDriverEntry);

2.2 驱动配置

驱动配置的实现以驱动配置文件作为载体,为开发者提供更精细化的驱动管理。HDF 使用 HCS 文件作为配置描述源码,内容以 Key-Value 键值对为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。HC-GEN (全称 HDF Configuration Generator) 是 HCS 配置转换工具,可以将 HDF 配置文件转换为软件可读取的文件格式:在弱性能环境中,转换为配置树源码,驱动可直接调用 C 代码获取配置;在高性能环境中,转换为 HCB(HDF Configuration Binary)二进制文件,驱动可使用 HDF 框架提供的配置解析接口获取配置。
  HCS 经过 HC-GEN 编译生成 HCB 文件,HDF 驱动框架中的 HCS Parser 模块会从 HCB 文件中重建配置树,HDF 驱动模块使用 HCS Parser 提供的配置读取接口获取配置内容。驱动配置过程的原理图如下所示:
395721415246751.png

2.2.1 驱动设备描述(必选)

HDF 框架加载驱动所需要的信息来源于 HDF 框架定义的 device_info.hcs 配置文件,因此需要在其中添加对应的设备描述,驱动的设备描述填写如下所示:

sample_host :: host{
        hostName = "host0"; //host名称,host节点是用来存放某一类驱动的容器。
        priority = 100; //host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序。
        device_sample :: device { //sample设备节点。
                device0 :: deviceNode { //sample驱动的DeviceNode节点。
                policy = 1; //驱动服务发布的策略
                priority = 100; //驱动启动优先级(0-200),值越大优先级越低,建议默认配 100,优先级相同则不保证 device 的加载顺序
                preload = 0; //驱动按需加载字段
                permission = 0664;//驱动创建设备节点权限
                moduleName = "sample_driver"; //驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
                serviceName = "sample_service"; //驱动对外发布服务的名称,必须唯一
                deviceMatchAttr = "sample_config";//驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等。
                }
        }
}

2.2.2 驱动私有配置信息(可选)

如果驱动有设置 deviceMatchAttr 私有配置,如 2.2.1 中所示,则可以添加一个驱动的配置文件,如 sample_config.hcs ,用来填写一些驱动的默认配置信息,HDF 框架在加载驱动的时候,会将对应的配置信息获取并保存在 HdfDeviceObject 中的 property 里面,通过 Bind 和 Init 传递给驱动,sample_config.hcs 中驱动的配置信息示例如下:

root {  
        SampleDriverConfig {
                sample_version = 1; 
                sample_bus = "I2C_0"; 
                match_attr = "sample_config";   //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致
        }
}

3 HDF 驱动加载

HDF 驱动加载包括按需加载和按序加载。按需加载是 HDF 框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载;按序加载是 HDF 框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。HDF 框架定义的驱动按需加载方式的策略是由配置文件中的 preload 字段来控制,preload 字段的取值范围以及含义如下:

typedef enum {
    DEVICE_PRELOAD_ENABLE = 0,
    DEVICE_PRELOAD_ENABLE_STEP2 = 1,
    DEVICE_PRELOAD_DISABLE = 2,
    DEVICE_PRELOAD_INVALID
} DevicePreload;
preload字段配置为0(DEVICE_PRELOAD_ENABLE),则系统启动过程中默认加载。
preload字段配置为1(DEVICE_PRELOAD_ENABLE_STEP2),当系统支持快速启动的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE_PRELOAD_ENABLE含义相同。
preload字段配置为2(DEVICE_PRELOAD_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务消息机制时,如果驱动服务不存在,HDF框架会尝试动态加载该驱动。

驱动的按序加载是通过配置文件中的 priority(取值范围为整数 0 到 200)来决定的,priority 值越小,表示的优先级越高。驱动的加载顺序,优先根据 host 的 priority 决定,如果 host 的 priority 相同,再根据 host 内的驱动 priority 值来决定加载顺序。

3.1 HDF_INIT 注册驱动入口

驱动管理框架启动驱动之前需要找到其驱动入口,入口使用 HDF_INIT(g_sampleDriverEntry) 注册到 HDF 框架。 将 HDF_INIT 宏展开

#define HDF\_SECTION\_\_attribute\_\_((section(“.hdf.driver”)))  
#define HDF\_DRIVER\_INIT(module) \\  
const size\_t USED\_ATTR module##HdfEntry HDF\_SECTION = (size\_t)(&(module))

可以看到 HDF_INIT 宏是定义了一个“驱动模块名 +HdfEntry”的符号放到".hdf.driver"所在 section,该符号指向的内存地址即为驱动程序入口结构体的地址。这个特殊的 section 将用于开机启动时查找设备驱动。

3.2 获取驱动列表

配置文本编译后会变成二进制格式的配置文件,其中设备相关信息被存放在一个用“hdf_manager”标记的 device_info 配置块中,host 的内容以块的形式在 device_info 块中依次排列,host 块中记录了 host 名称、启动优先级和设备列表信息。设备信息中的 moduleName 字段将用于和驱动程序入口中的 moduleName 进行匹配,从而为设备匹配到正确的驱动程序,完成设备与驱动的匹配,具体流程图如下:

3.3 获取设备列表

HDF 驱动框架通过将驱动程序入口符号的地址集中存放到一个特殊的 section 来实现对驱动的索引,这个 section 的开头和末尾插入了_hdf_drivers_start、_hdf_drivers_end 两个特殊符号,用于标记这个 section 的范围,两个特殊符号之间的数据即为驱动实现指针。

`

3.4 驱动框架启动过程

驱动入口位置已经明确,那么运行过程中如何加载,下面结合代码来说明。

3.4.1 驱动框架启动入口

static int __init DeviceManagerInit(void)
{
    int ret;

    HDF_LOGD("%s enter", __func__);
    ret = DeviceManagerStart();
    if (ret < 0) {
        HDF_LOGE("%s start failed %d", __func__, ret);
    } else {
        HDF_LOGD("%s start success", __func__);
    }
    return ret;
}

late_initcall(DeviceManagerInit);
​

late_initcall 宏的作用是在系统启动时调用 DeviceManagerInit 方法。并调用 DeviceManagerStart,其中调用了 StartService,实际上调用 DevmgrServiceStartService。代码如下:

int DeviceManagerStart(void)
{
    struct HdfIoService *ioService = NULL;
    int ret;
    struct IDevmgrService *instance = DevmgrServiceGetInstance();
    ...
    ret = instance->StartService(instance);
    ...
    return HdfPowerManagerInit();
}

3.4.2 启动 Device Manager 服务,读取 Host 数据,建立 Host 客户端 DevHostServiceClnt 列表

DevmgrServiceStartService 方法中会启动 Device Manager 的服务,调用 DevmgrServiceStartDeviceHosts,其目的是为每个 host 设备创建 DevHostServiceClnt ,并启动对应的 Host 设备在 Host 域内的 DevHostService,如此 DeviceManager 可通过客户端接口访问 host 服务。代码如下:

int DevmgrServiceStartService(struct IDevmgrService *inst)
{
    int ret;
    struct DevmgrService *dmService = (struct DevmgrService *)inst;
    if (dmService == NULL) {
        HDF_LOGE("failed to start device manager service, dmService is null");
        return HDF_FAILURE;
    }

    ret = DevSvcManagerStartService();
    HDF_LOGI("start svcmgr result %{public}d", ret);

    return DevmgrServiceStartDeviceHosts(dmService);
}
​

DevmgrServiceStartDeviceHosts 中继续调用 HdfAttributeManagerGetHostList 读取配置文件中所有 host 节点,并且按照 priority 排序添加到 hostList,然后回到 DevmgrServiceStartDeviceHosts 中循环调用 DevmgrServiceStartDeviceHost 方法,遍历 hostList 中所有 host 节点,为每个 host 创建 DevHostServiceClnt 客户端 hostClnt,作为参数传给 HdfAttributeManagerGetDeviceList 方法,用于读取并存储 host 所包含的所有 DevcieNode。接着再调用 DevmgrServiceStartHostProcess 方法启动 host 服务。
DevmgrServiceStartDeviceHosts,HdfAttributeManagerGetHostList, DevmgrServiceStartDeviceHost 和 HdfAttributeManagerGetDeviceList 方法代码如下:

static int DevmgrServiceStartDeviceHosts(struct DevmgrService *inst)
{
    int ret;
    struct HdfSList hostList;
    struct HdfSListIterator it;
    struct HdfHostInfo *hostAttr = NULL;

    HdfSListInit(&hostList);
    if (!HdfAttributeManagerGetHostList(&hostList)) {
        HDF_LOGW("%s: host list is null", __func__);
        return HDF_SUCCESS;
    }
    HdfSListIteratorInit(&it, &hostList);
    while (HdfSListIteratorHasNext(&it)) {
        hostAttr = (struct HdfHostInfo *)HdfSListIteratorNext(&it);
        ret = DevmgrServiceStartDeviceHost(inst, hostAttr);
        if (ret != HDF_SUCCESS) {
            HDF_LOGW("%{public}s failed to start device host, host id is %{public}u, host name is '%{public}s'",
                __func__, hostAttr->hostId, hostAttr->hostName);
        }
    }
    HdfSListFlush(&hostList, HdfHostInfoDelete);
    return HDF_SUCCESS;
}

bool HdfAttributeManagerGetHostList(struct HdfSList *hostList)
{
    const struct DeviceResourceNode *hdfManagerNode = NULL;
    const struct DeviceResourceNode *hostNode = NULL;
    uint16_t hostId = 0;
    if (hostList == NULL) {
        return false;
    }

    hdfManagerNode = GetHdfManagerNode(HdfGetHcsRootNode());
    if (hdfManagerNode == NULL) {
        HDF_LOGE("%s: get hdf manager node is null", __func__);
        return false;
    }

    hostNode = hdfManagerNode->child;
    for (; hostNode != NULL; hostNode = hostNode->sibling) {
        struct HdfHostInfo *hostInfo = HdfHostInfoNewInstance();
        if (hostInfo == NULL) {
            HdfSListFlush(hostList, HdfHostInfoDelete);
            HDF_LOGE("%s: new hostInfo is null", __func__);
            return false;
        }
        if (!GetHostInfo(hostNode, hostInfo)) {
            HdfHostInfoFreeInstance(hostInfo);
            continue;
        }
        hostInfo->hostId = hostId;
        if (!HdfSListAddOrder(hostList, &hostInfo->node, HdfHostListCompare)) {
            HdfHostInfoFreeInstance(hostInfo);
            continue;
        }
        hostId++;
    }
    return true;
}

static int DevmgrServiceStartDeviceHost(struct DevmgrService *devmgr, struct HdfHostInfo *hostAttr)
{
    struct DevHostServiceClnt *hostClnt = DevHostServiceClntNewInstance(hostAttr->hostId, hostAttr->hostName);
    if (hostClnt == NULL) {
        HDF_LOGW("failed to create new device host client");
        return HDF_FAILURE;
    }

    if (HdfAttributeManagerGetDeviceList(hostClnt) != HDF_SUCCESS) {
        HDF_LOGW("failed to get device list for host %{public}s", hostClnt->hostName);
        return HDF_FAILURE;
    }

    DListInsertTail(&hostClnt->node, &devmgr->hosts);

    // not start the host which only have dynamic devices
    if (HdfSListIsEmpty(&hostClnt->unloadDevInfos)) {
        return HDF_SUCCESS;
    }

    if (DevmgrServiceStartHostProcess(hostClnt, false, false) != HDF_SUCCESS) {
        HDF_LOGW("failed to start device host, host id is %{public}u", hostAttr->hostId);
        DListRemove(&hostClnt->node);
        DevHostServiceClntFreeInstance(hostClnt);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

int HdfAttributeManagerGetDeviceList(struct DevHostServiceClnt *hostClnt)
{
    uint16_t deviceIdx = 1;
    const struct DeviceResourceNode *hostNode = NULL;
    const struct DeviceResourceNode *device = NULL;
    int ret = HDF_DEV_ERR_NO_DEVICE;

    if (hostClnt == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    hostNode = GetHostNode(hostClnt->hostName);
    if (hostNode == NULL) {
        return ret;
    }

    for (device = hostNode->child; device != NULL; device = device->sibling, deviceIdx++) {
        if (!GetDevcieNodeList(device, hostClnt, deviceIdx)) {
            return ret;
        }
    }

    return HDF_SUCCESS;
}
​

3.4.3 启动 Host 服务端,并将其绑定到 Device Manager 服务持有的 Host 客户端

接上 DevmgrServiceStartHostProcess 方法中调用 DriverInstaller 的 StartDeviceHost 方法,即 DriverInstallerStartDeviceHost 方法,这里先创建 IDevHostService 实例,又继续调用该实例的 StartService 方法,即 DevHostServiceStartService 方法。继续调用 DevmgrServiceClntAttachDeviceHost,其中又获取到 Device Manager 的客户端 DevmgrServiceClnt,并调用其 AttachDeviceHost 方法,即 DevmgrServiceAttachDeviceHost,把 DevHostService 服务对象 Attach 到 Device Manager 服务 保存的 DevHostServiceClnt 对象。然后继续调用 DevHostServiceClntInstallDriver。代码如下:

static int DriverInstallerStartDeviceHost(uint32_t devHostId, const char *devHostName, bool dynamic)
{
    struct IDevHostService *hostServiceIf = DevHostServiceNewInstance(devHostId, devHostName);
    int ret;
    (void)dynamic;
    if ((hostServiceIf == NULL) || (hostServiceIf->StartService == NULL)) {
        HDF_LOGE("hostServiceIf or hostServiceIf->StartService is null");
        return HDF_FAILURE;
    }
    ret = hostServiceIf->StartService(hostServiceIf);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("failed to start host service, ret: %d", ret);
        DevHostServiceFreeInstance(hostServiceIf);
    }
    return ret;
}

static int DevHostServiceStartService(struct IDevHostService *service)
{
    struct DevHostService *hostService = (struct DevHostService*)service;
    if (hostService == NULL) {
        HDF_LOGE("failed to start device service, hostService is null");
        return HDF_FAILURE;
    }
    return DevmgrServiceClntAttachDeviceHost(hostService->hostId, service);
}

int DevmgrServiceClntAttachDeviceHost(uint16_t hostId, struct IDevHostService *hostService)
{
    struct IDevmgrService *devMgrSvcIf = NULL;
    struct DevmgrServiceClnt *inst = DevmgrServiceClntGetInstance();
    if (inst == NULL || inst->devMgrSvcIf == NULL) {
        HDF_LOGE("failed to attach device host, get device manager service client is null");
        return HDF_FAILURE;
    }

    devMgrSvcIf = inst->devMgrSvcIf;
    if (devMgrSvcIf->AttachDeviceHost == NULL) {
        HDF_LOGE("failed to attach device host, attach device host function is null");
        return HDF_FAILURE;
    }
    return devMgrSvcIf->AttachDeviceHost(devMgrSvcIf, hostId, hostService);
}

static int DevmgrServiceAttachDeviceHost(
    struct IDevmgrService *inst, uint16_t hostId, struct IDevHostService *hostService)
{
    struct DevHostServiceClnt *hostClnt = DevmgrServiceFindDeviceHost(inst, hostId);
    if (hostClnt == NULL) {
        HDF_LOGE("failed to attach device host, hostClnt is null");
        return HDF_FAILURE;
    }
    if (hostService == NULL) {
        HDF_LOGE("failed to attach device host, hostService is null");
        return HDF_FAILURE;
    }

    (void)OsalMutexLock(&hostClnt->hostLock);
    hostClnt->hostService = hostService;
    (void)OsalMutexUnlock(&hostClnt->hostLock);
    return DevHostServiceClntInstallDriver(hostClnt);
}
​

3.4.3 Host 服务端驱动加载

接上调用 DevHostServiceClntInstallDriver,通过 DevHostServiceClnt 调用其服务端 DevHostService 的 AddDevice,即 DevHostServiceAddDevice,一个一个的加载 host 包含的所有设备驱动。根据 moduleName 先调用 driverLoader->GetDriver,即 HdfDriverLoaderGetDriver 方法,调用 HdfDriverManagerGetDriver -> HdfDriverManagerFoundDriver,最终根据 moduleName 获取到 HdfDriver,其中包含了驱动入口 HdfDriverEntry,
然后返回到 DevHostServiceAddDevice,创建 HdfDeviceNode 对象,把获取到的 HdfDriver 设置给该对象,并调用 HdfDevice 的 Attach 方法,即 HdfDeviceAttach ,将 HdfDeviceNode 对象挂载到 HdfDevice,同时对该对象调用 IDeviceNode->LaunchNode 方法,即 HdfDeviceLaunchNode,启动驱动初始化。代码如下:

int DevHostServiceClntInstallDriver(struct DevHostServiceClnt *hostClnt)
{
    int ret;
    struct HdfSListIterator it;
    struct HdfDeviceInfo *deviceInfo = NULL;
    struct IDevHostService *devHostSvcIf = NULL;
    ...
    devHostSvcIf = (struct IDevHostService *)hostClnt->hostService;
    ...
    HdfSListIteratorInit(&it, &hostClnt->unloadDevInfos);
    while (HdfSListIteratorHasNext(&it)) {
        deviceInfo = (struct HdfDeviceInfo *)HdfSListIteratorNext(&it);
        ...
        ret = devHostSvcIf->AddDevice(devHostSvcIf, deviceInfo);
        ...
        deviceInfo->status = HDF_SERVICE_USABLE;
        ...
    }
    return HDF_SUCCESS;
}

int DevHostServiceAddDevice(struct IDevHostService *inst, const struct HdfDeviceInfo *deviceInfo)
{
    int ret = HDF_FAILURE;
    struct HdfDevice *device = NULL;
    struct HdfDeviceNode *devNode = NULL;
    struct HdfDriver *driver = NULL;
    struct DevHostService *hostService = CONTAINER_OF(inst, struct DevHostService, super);
    struct IDriverLoader *driverLoader = HdfDriverLoaderGetInstance();
    ...
    driver = driverLoader->GetDriver(deviceInfo->moduleName);
    if (driver == NULL) {
        ret = HDF_DEV_ERR_NODATA;
        goto ERROR;
    }

    devNode = HdfDeviceNodeNewInstance(deviceInfo, driver);
    if (devNode == NULL) {
        driverLoader->ReclaimDriver(driver);
        return HDF_DEV_ERR_NO_MEMORY;
    }

    devNode->hostService = hostService;
    devNode->device = device;
    devNode->driver = driver;
    ret = device->super.Attach(&device->super, devNode);
    ...
    return ret;
}

static struct HdfDriver *HdfDriverManagerFoundDriver(const char *driverName)
{
    struct DListHead *driverHead = NULL;
    struct HdfDriver *driver = NULL;
    driverHead = HdfDriverHead();
    DLIST_FOR_EACH_ENTRY(driver, driverHead, struct HdfDriver, node) {
        if (driver->entry != NULL && driver->entry->moduleName != NULL &&
            !strcmp(driver->entry->moduleName, driverName)) {
            return driver;
        }
    }

    return NULL;
}

static int HdfDeviceAttach(struct IHdfDevice *devInst, struct HdfDeviceNode *devNode)
{
    int ret;
    struct HdfDevice *device = (struct HdfDevice *)devInst;
    struct IDeviceNode *nodeIf = (struct IDeviceNode *)devNode;

    if (device == NULL || nodeIf == NULL || nodeIf->LaunchNode == NULL) {
        HDF_LOGE("failed to attach device, input params invalid");
        return HDF_ERR_INVALID_PARAM;
    }

    // for dynamic added device node, assign device id here
    if (devNode->devId == 0 && AcquireNodeDeivceId(device, &devNode->devId) != HDF_SUCCESS) {
        HDF_LOGE("failed to attach device, invalid device id");
        return HDF_ERR_INVALID_PARAM;
    }
    devNode->token->devid = devNode->devId;
    ret = nodeIf->LaunchNode(devNode);
    if (ret == HDF_SUCCESS) {
        DListInsertTail(&devNode->entry, &device->devNodes);
        UpdateDeivceNodeIdIndex(device, devNode->devId);
    }

    return ret;
}

3.4.4 驱动初始化

接上进入 HdfDeviceLaunchNode 方法后,获取到 driverEntry,依次调用 Bind 和 Init 方法,接着将驱动服务发布到 Device Manager ,再把相关节点 token 挂载到 DevMgrService,完成服务注册。代码如下:

int HdfDeviceLaunchNode(struct HdfDeviceNode *devNode)
{
    const struct HdfDriverEntry *driverEntry = NULL;
    int ret;
    if (devNode == NULL) {
        HDF_LOGE("failed to launch service, device or service is null");
        return HDF_ERR_INVALID_PARAM;
    }

    HDF_LOGI("launch devnode %{public}s", devNode->servName ? devNode->servName : "");
    driverEntry = devNode->driver->entry;
    if (driverEntry == NULL || driverEntry->Init == NULL) {
        HDF_LOGE("failed to launch service, deviceEntry invalid");
        return HDF_ERR_INVALID_PARAM;
    }
    devNode->devStatus = DEVNODE_LAUNCHED;

    ret = DeviceDriverBind(devNode);
    if (ret != HDF_SUCCESS) {
        return ret;
    }

    ret = driverEntry->Init(&devNode->deviceObject);
    if (ret != HDF_SUCCESS) {
        return HDF_DEV_ERR_DEV_INIT_FAIL;
    }

    ret = HdfDeviceNodePublishService(devNode);
    if (ret != HDF_SUCCESS) {
        return HDF_DEV_ERR_PUBLISH_FAIL;
    }

    ret = DevmgrServiceClntAttachDevice(devNode->token);
    if (ret != HDF_SUCCESS) {
        return HDF_DEV_ERR_ATTACHDEV_FAIL;
    }
    return ret;
}

4 驱动程序加载流程总结

1)在系统启动时,DeviceManagerInit 通过 late_initcall 先启动。
2) Device Manager 根据 Device Information 信息,解析配置文件中的 Host 列表,根据 Host 列表中的信息来实例化对应的 Host 对象。
3)Host 遍历设备列表去获取与之匹配的驱动程序名称,然后基于驱动程序名称遍历.hdf.driver section 获得驱动程序地址。
4)设备与驱动匹配成功之后,获取指定驱动的入口地址,加载对应的设备驱动程序。
5)调用指定驱动的 Bind 接口,用于关联设备和服务实例。
6)调用指定驱动的 Init 接口,用于完成驱动的相关初始化工作。
7)如果驱动被卸载或者因为硬件等原因 Init 接口返回失败,Release 将被调用,用于释放驱动申请的各类资源。

写在最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)用来跟着学习是非常有必要的。

这份鸿蒙(HarmonyOS NEXT)文档包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习文档能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

鸿蒙(HarmonyOS NEXT)5.0最新学习路线

在这里插入图片描述

有了路线图,怎么能没有学习文档呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

《鸿蒙 (OpenHarmony)开发入门教学视频》

在这里插入图片描述

《鸿蒙生态应用开发V3.0白皮书》

在这里插入图片描述

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

在这里插入图片描述

《鸿蒙开发基础》

●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
在这里插入图片描述

《鸿蒙开发进阶》

●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
在这里插入图片描述

《鸿蒙进阶实战》

●ArkTS实践
●UIAbility应用
●网络案例
……
在这里插入图片描述

获取以上完整鸿蒙HarmonyOS学习文档,请点击→纯血版全套鸿蒙HarmonyOS学习文档

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值