HDF驱动框架探路(三):基于3516配置一套可以打通的HDF驱动程序 原创 精华

Mr_qzk
发布于 2021-11-30 10:05
浏览
8收藏

【本文正在参与优质创作者激励】
老规矩还是将最终希望跑出来的效果放出来。如下:
HDF驱动框架探路(三):基于3516配置一套可以打通的HDF驱动程序-鸿蒙开发者社区

@toc

前言

  • 大家如果有读过第二篇文章的话,可能发现了在该文中内核态的驱动程序是直接引用了源码中已经存在的一个HDF驱动模块。所以本文的就是着重解决这个问题,也就是自己去配置一个HDF驱动模块。
  • 本文是基于3516的小型系统去验证的。

本文框架图

HDF驱动框架探路(三):基于3516配置一套可以打通的HDF驱动程序-鸿蒙开发者社区
观察上图,其实本文是将上文的流程进一步细化,上文中的驱动程序细分成了三个部分,分别是:HCS文件配置、内核态代码、liteos_a配置编译进内核。这三个部分合起来就是自己搭建HDF驱动程序的步骤。

1. HDF配置

这里的HDF配置是按照源码中已经存在的sample_driver模块来的
打开文件vendor/hisilicon/hispark_taurus/hdf_config/hdf_test/hdf_test_manager/device_info.hcs,然后加入下述代码中的device2。

                device1 :: deviceNode {
                    policy = 2;
                    priority = 10;
                    preload = 0;
                    permission = 0644;
                    moduleName = "sample_driver";
                    serviceName = "sample_service";
                }
                device2 :: deviceNode {             // DeviceNode of the sample driver
		            policy = 2;                     // Driver service release policy. For details, see section Driver Service Management.
		            priority= 10;                  // Driver startup priority (0-200). A larger value indicates a lower priority. The default value 100 is recommended. If the priorities are the same, the device loading sequence is random.
		            preload = 0;                    // On-demand loading of the driver. For details, see "NOTE" at the end of this section.
		            permission = 0664;              // Permission for the driver to create device nodes.
		            moduleName = "talkweb_driver";       // Driver name. The value of this field must be the same as the value of moduleName in the driver entry structure.
		            serviceName = "talkweb_service";     // Name of the service released by the driver. The name must be unique.
		        }
            }
            device_platform_test :: device {
                platform_test:: deviceNode {
                    policy = 1;
                    priority = 150;
                    preload = 0;
                    permission = 0644;
                    moduleName = "PLATFORM_TEST_DRIVER";
                    serviceName = "PLATFORM_TEST";
                    deviceMatchAttr = "platform_test";
                }
            }

2. liteos_a编译配置

该步骤的作用是将第三步中的驱动程序编译进入内核。

2.1 在BUILD.gn文件中配置

打开drivers/adapter/khdf/liteos/test/BUILD.gn文件

--- a/khdf/liteos/test/BUILD.gn
+++ b/khdf/liteos/test/BUILD.gn
@@ -37,6 +37,7 @@ hdf_driver(module_name) {
   sources = [
     "$HDF_TEST_FRAMWORK_ROOT/common/hdf_main_test.c",
     "$HDF_TEST_FRAMWORK_ROOT/manager/sample_driver_test.c",
+    "$HDF_TEST_FRAMWORK_ROOT/talkwebtest/talkweb.c",
     "$HDF_TEST_FRAMWORK_ROOT/osal/osal_all_test.c",
     "$HDF_TEST_FRAMWORK_ROOT/osal/osal_file_test.c",
     "$HDF_TEST_FRAMWORK_ROOT/osal/osal_get_case_test.c",

2.2 在Makefile中进行添加配置

drivers/adapter/khdf/liteos/test/Makefile

--- a/khdf/liteos/test/Makefile
+++ b/khdf/liteos/test/Makefile
@@ -34,6 +34,7 @@ HDF_TEST_FRAMWORK_ROOT = $(LITEOSTOPDIR)/../../drivers/framework/test/unittest
 
 LOCAL_SRCS := $(HDF_TEST_FRAMWORK_ROOT)/common/hdf_main_test.c \
               $(HDF_TEST_FRAMWORK_ROOT)/manager/sample_driver_test.c \
+              $(HDF_TEST_FRAMWORK_ROOT)/talkwebtest/talkweb.c \
               $(HDF_TEST_FRAMWORK_ROOT)/osal/osal_test_entry.c \
               $(HDF_TEST_FRAMWORK_ROOT)/osal/osal_all_test.c \
               $(HDF_TEST_FRAMWORK_ROOT)/osal/osal_file_test.c \

3. 驱动程序

进入drivers/framework/test/unittest目录下,新建talkwebtest目录

3.1 在上述目录下新建talkweb.h文件,将下述代码放入

#ifndef HDF_SAMPLE_DRIVER_H
#define HDF_SAMPLE_DRIVER_H

#include "hdf_object.h"

#define SAMPLE_SERVICE "sample_service"

typedef enum {
    SAMPLE_DRIVER_REGISTER_DEVICE = 0,
    SAMPLE_DRIVER_UNREGISTER_DEVICE,
    SAMPLE_DRIVER_SENDEVENT_SINGLE_DEVICE,
    SAMPLE_DRIVER_SENDEVENT_BROADCAST_DEVICE,
    SAMPLE_DRIVER_PM_STATE_INJECT,
} SAMPLE_DRIVER_CMDID;

struct HdfDeviceObject *GetDeviceObject(void);

#endif // HDF_MAIN_TEST_H

3.2 在上述目录下新建talkweb.c文件,将下述代码放入

/*
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
 *
 * HDF is dual licensed: you can use it either under the terms of
 * the GPL, or the BSD license, at your option.
 * See the LICENSE file in the root of this repository for complete details.
 */
#include "talkweb.h"
#include "devsvc_manager_clnt.h"
#include "devmgr_service.h"
#include "hdf_log.h"
#include "hdf_device_desc.h"
#include "hdf_pm.h"

#include "device_resource_if.h"
#include "osal_io.h"
#include "osal_mem.h"
#include "gpio_if.h"
#include "osal_irq.h"
#include "osal_time.h" 
//#define HDF_LOG_TAG led_driver // 打印日志所包含的标签,如果不定义则用默认>    定义的HDF_TAG标签
#define LED_WRITE_READ 88  

#define HDF_LOG_TAG sample_driver_test

#ifndef INT32_MAX
#define INT32_MAX 0x7fffffff
#endif

void HdftalkwebDriverRelease(struct HdfDeviceObject *deviceObject)
{
    (void)deviceObject;
    return;
}

int32_t talkwebDriverRegisterDevice(struct HdfSBuf *data)
{
    const char *moduleName = NULL;
    const char *serviceName = NULL;
    struct HdfDeviceObject *devObj = NULL;
    if (data == NULL) {
        return HDF_FAILURE;
    }

    moduleName = HdfSbufReadString(data);
    if (moduleName == NULL) {
        return HDF_FAILURE;
    }
    serviceName = HdfSbufReadString(data);
    if (serviceName == NULL) {
        return HDF_FAILURE;
    }

    devObj = HdfRegisterDevice(moduleName, serviceName, NULL);
    if (devObj == NULL) {
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

int32_t talkwebDriverUnregisterDevice(struct HdfSBuf *data)
{
    const char *moduleName = NULL;
    const char *serviceName = NULL;
    if (data == NULL) {
        return HDF_FAILURE;
    }

    moduleName = HdfSbufReadString(data);
    if (moduleName == NULL) {
        return HDF_FAILURE;
    }
    serviceName = HdfSbufReadString(data);
    if (serviceName == NULL) {
        return HDF_FAILURE;
    }
    HdfUnregisterDevice(moduleName, serviceName);
    return HDF_SUCCESS;
}

int32_t talkwebDriverSendEvent(struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, bool broadcast)
{
    return broadcast ? HdfDeviceSendEvent(client->device, id, data) : HdfDeviceSendEventToClient(client, id, data);
}

int32_t talkwebDriverPowerStateInject(uint32_t powerState)
{
    int ret;
    struct IDevmgrService *devmgrService = DevmgrServiceGetInstance();
    if (devmgrService == NULL || devmgrService->PowerStateChange == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }
    ret = devmgrService->PowerStateChange(devmgrService, powerState);

    HDF_LOGI("%s: inject power state(%d) done, ret = %d", __func__, powerState, ret);
    return ret;
}

 
static int32_t CtlLED(int mode)
{
    int32_t ret;
    uint16_t valRead;
    /* LED的GPIO管脚号 */
    uint16_t gpio = 5 * 8 + 1;  // 红外补光灯
    // uint16_t gpio = 2 * 8 + 3;  // 绿色指示灯
    // uint16_t gpio = 3 * 8 + 4;  // 红色指示灯
 
    /* 将GPIO管脚配置为输出 */
    ret = GpioSetDir(gpio, GPIO_DIR_OUT);
    if (ret != 0)
    {   
        HDF_LOGE("GpioSerDir: failed, ret %d\n", ret);
        return ret;
    }   
 
    if (mode == -1) 
    {   
        // 翻转输出口
        (void)GpioRead(gpio, &valRead);
        ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
    }   
    else
    {   
        ret = GpioWrite(gpio, mode);
    }   
 
    if (ret != 0)
    {   
        HDF_LOGE("GpioWrite: failed, ret %d\n", ret);
        return ret;
    }   
    return ret;
}


int32_t talkwebDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
{
		HDF_LOGD("%s::qzk-enter", __func__);
    uint32_t powerState = 0;
    int32_t ret = HDF_SUCCESS;
    if (reply == NULL || client == NULL) {
        return HDF_FAILURE;
    }
    int32_t result = HDF_FAILURE;
    switch (cmdId) {
        case LED_WRITE_READ:
            const char *recv = HdfSbufReadString(data);
            if (recv != NULL)
            {
                //HDF_LOGI("recv: %s", recv);
                result = CtlLED(-1);
                // CtlLED(GPIO_VAL_HIGH);
                if (!HdfSbufWriteInt32(reply, result)){
                    //HDF_LOGE("replay is fail");
                }
                return HdfDeviceSendEvent(client->device, cmdId, data);
            }
            break;
        case SAMPLE_DRIVER_REGISTER_DEVICE: {
            ret = talkwebDriverRegisterDevice(data);
            HdfSbufWriteInt32(reply, ret);
            break;
        }
        case SAMPLE_DRIVER_UNREGISTER_DEVICE:
            ret = talkwebDriverUnregisterDevice(data);
            HdfSbufWriteInt32(reply, ret);
            break;
        case SAMPLE_DRIVER_SENDEVENT_SINGLE_DEVICE:
            ret =  talkwebDriverSendEvent(client, cmdId, data, false);
            HdfSbufWriteInt32(reply, INT32_MAX);
            break;
        case SAMPLE_DRIVER_SENDEVENT_BROADCAST_DEVICE:
            ret = talkwebDriverSendEvent(client, cmdId, data, true);
            HdfSbufWriteInt32(reply, INT32_MAX);
            break;
        case SAMPLE_DRIVER_PM_STATE_INJECT:
            HdfSbufReadUint32(data, &powerState);
            return talkwebDriverPowerStateInject(powerState);
        default:
            break;
    }

    return ret;
}

int HdftalkwebDriverBind(struct HdfDeviceObject *deviceObject)
{
    static struct IDeviceIoService testService = {
        .Dispatch = talkwebDriverDispatch,
        .Open = NULL,
        .Release = NULL,
    };
    HDF_LOGD("%s::enter", __func__);
    if (deviceObject == NULL) {
        return HDF_FAILURE;
    }

    deviceObject->service = &testService;
    return HDF_SUCCESS;
}

int HdftalkwebDozeResume(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("%s:called", __func__);
    return HDF_SUCCESS;
}

int HdftalkwebDozeSuspend(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("%s:called", __func__);
    return HDF_SUCCESS;
}

int HdftalkwebResume(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("%s:called", __func__);
    return HDF_SUCCESS;
}

int HdftalkwebSuspend(struct HdfDeviceObject *deviceObject)
{
    HDF_LOGI("%s:called", __func__);
    return HDF_SUCCESS;
}

struct talkwebDriverPmListener {
    struct IPowerEventListener powerListener;
    void *p;
};

int HdftalkwebDriverInit(struct HdfDeviceObject *deviceObject)
{
    static struct talkwebDriverPmListener pmListener = {0};
    int ret;
    HDF_LOGI("%s::enter!", __func__);
    if (deviceObject == NULL) {
        HDF_LOGE("%s::ptr is null!", __func__);
        return HDF_FAILURE;
    }
    HDF_LOGD("%s:Init success", __func__);

    pmListener.powerListener.DozeResume = HdftalkwebDozeResume;
    pmListener.powerListener.DozeSuspend = HdftalkwebDozeSuspend;
    pmListener.powerListener.Resume = HdftalkwebResume;
    pmListener.powerListener.Suspend = HdftalkwebSuspend;

    ret = HdfPmRegisterPowerListener(deviceObject, &pmListener.powerListener);
    HDF_LOGI("%s:register power listener, ret = %d", __func__, ret);

    return HDF_SUCCESS;
}


struct HdfDriverEntry g_talkwebDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "talkweb_driver",
    .Bind = HdftalkwebDriverBind,
    .Init = HdftalkwebDriverInit,
    .Release = HdftalkwebDriverRelease,
};

HDF_INIT(g_talkwebDriverEntry);

4. 应用态程序

这里的应用态程序的代码和编译方法,直接可以采用上文的就可以。
这里只需要修改SAMPLE_SERVICE_NAME这个宏。

#define SAMPLE_SERVICE_NAME "talkweb_service"

5.hb build -f 进行编译烧录

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-11-30 10:05:16修改
10
收藏 8
回复
举报
回复
    相关推荐