积分1215 / 贡献70

提问2答案被采纳57文章2

作者动态

[经验分享] OpenHarmony-HDF驱动框架介绍及加载过程 精华

深开鸿_王皓 显示全部楼层 发表于 2023-10-30 08:56:17

前言

  互联网经历了移动互联网的大发展之后,将迎来万物互联时代,而万物互联除了包含传统的网络设备,如服务器,手持终端等等富设备,还需要连接大量的微小型终端硬件设备,这些设备硬件的离散度很高,它们的使用场景,可用计算资源差异都很大。,所以这要求使用一个更灵活、功能更强大、能耗更低的驱动框架。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 接口实现即可将设备接入系统,从而保证了上层调用者无需改动即可访问操作新适配的设备。

45721214249494.png

  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";
                }
            }
        }

86601415250196.png

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))

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

3.2 获取驱动列表

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

3.3 获取设备列表

295434215260385.png   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 将被调用,用于释放驱动申请的各类资源。

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

精彩评论1

ZXC

沙发 发表于 2024-6-12 11:21:13
和安卓那种基于linux驱动框架和设备树的方式比有哪些优势?

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部