OpenHarmony开发者论坛

标题: OpenHarmony-HDF驱动框架介绍及加载过程 [打印本页]

作者: 深开鸿_王皓    时间: 2023-10-30 08:56
标题: OpenHarmony-HDF驱动框架介绍及加载过程
[md]## 前言

  互联网经历了移动互联网的大发展之后,将迎来万物互联时代,而万物互联除了包含传统的网络设备,如服务器,手持终端等等富设备,还需要连接大量的微小型终端硬件设备,这些设备硬件的离散度很高,它们的使用场景,可用计算资源差异都很大。,所以这要求使用一个更灵活、功能更强大、能耗更低的驱动框架。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](data/attachment/forum/202310/30/085223uyei3st96n6ihbie.png "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](data/attachment/forum/202310/30/085305o8vohzuhgvygtbus.png "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](data/attachment/forum/202310/30/085503xkwprvpzqountuod.png "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](data/attachment/forum/202310/30/085359ljtmw6sxcx46ebxs.png "208193915242505.png")
  可以看到 HDF_INIT 宏是定义了一个“驱动模块名+HdfEntry”的符号放到".hdf.driver"所在 section,该符号指向的内存地址即为驱动程序入口结构体的地址。这个特殊的 section 将用于开机启动时查找设备驱动。

## 3.2 获取驱动列表


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

## 3.3 获取设备列表

![295434215260385.png](data/attachment/forum/202310/30/085424umtz9rtod5bi7mzb.png "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 将被调用,用于释放驱动申请的各类资源。

[/md]
作者: ZXC    时间: 2024-6-12 11:21
和安卓那种基于linux驱动框架和设备树的方式比有哪些优势?




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5