7d83e88a创建于 2022年2月14日历史提交
/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <hdf_device_object.h>
#include <hdf_dlist.h>
#include <hdf_log.h>
#include <hdf_remote_service.h>
#include <hdi_smq.h>
#include <thread>
#include "sample_hdi.h"

#define HDF_LOG_TAG sample_driver
using OHOS::HDI::Base::SharedMemQueue;
using OHOS::HDI::Base::SharedMemQueueMeta;
using OHOS::HDI::Base::SmqType;

constexpr int SMQ_TRANS_ELEMENT_MAX = 5;
constexpr int SMQ_TRANS_WAIT_TIME = 100;

struct SampleDevice {
    struct DListHead listNode;
    struct HdfDeviceObject *devobj;
};

static struct DListHead g_sampleDeviceList = { nullptr };

static int32_t SampleServicePing(struct HdfDeviceObject *device, const char *info, char **infoOut)
{
    (void)device;
    HDF_LOGI("Sample:info is %{public}s", info);
    *infoOut = strdup(info);
    return 0;
}

static int32_t SampleServiceSum(struct HdfDeviceObject *device, int32_t x0, int32_t x1, int32_t *result)
{
    (void)device;
    *result = x0 + x1;
    return 0;
}

static int32_t SampleServiceCallback(struct HdfDeviceObject *device, struct HdfRemoteService *callback, int32_t code)
{
    (void)device;
    struct HdfSBuf *dataSbuf = HdfSbufTypedObtain(SBUF_IPC);
    HdfSbufWriteInt32(dataSbuf, code);
    int ret = callback->dispatcher->Dispatch(callback, 0, dataSbuf, nullptr);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("failed to do callback, ret = %{public}d", ret);
    }
    HdfSbufRecycle(dataSbuf);
    return ret;
}

static int32_t SampleServiceRegisterDevice(struct HdfDeviceObject *device, const char *servName)
{
    struct HdfDeviceObject *dev = HdfDeviceObjectAlloc(device, "libsample_driver.z.so");
    if (dev == nullptr) {
        HDF_LOGE("failed to alloc device object");
        return HDF_DEV_ERR_NO_DEVICE;
    }

    if (HdfDeviceObjectRegister(dev) != HDF_SUCCESS) {
        HDF_LOGE("failed to register device");
        HdfDeviceObjectRelease(dev);
        return HDF_DEV_ERR_NO_DEVICE;
    }

    if (HdfDeviceObjectPublishService(dev, servName, SERVICE_POLICY_CAPACITY, 0) != HDF_SUCCESS) {
        HDF_LOGE("failed to publish device service %{public}s", servName);
        HdfDeviceObjectRelease(dev);
        return HDF_DEV_ERR_NO_DEVICE;
    }

    HDF_LOGE("publish device service %{public}s success", servName);
    struct SampleDevice *sampleDev = (struct SampleDevice *)OsalMemAlloc(sizeof(struct SampleDevice));
    if (sampleDev == nullptr) {
        HdfDeviceObjectRelease(dev);
        return HDF_DEV_ERR_NO_MEMORY;
    }

    sampleDev->devobj = dev;
    if (g_sampleDeviceList.next == nullptr) {
        DListHeadInit(&g_sampleDeviceList);
    }
    DListInsertTail(&sampleDev->listNode, &g_sampleDeviceList);

    HDF_LOGI("register device %{public}s success", servName);
    return HDF_SUCCESS;
}

static int32_t SampleServiceUnregisterDevice(struct HdfDeviceObject *device, const char *servName)
{
    struct SampleDevice *sampleDev = nullptr;
    struct SampleDevice *sampleDevTmp = nullptr;
    HDF_LOGI("remove device %{public}s in", servName);
    DLIST_FOR_EACH_ENTRY_SAFE(sampleDev, sampleDevTmp, &g_sampleDeviceList, struct SampleDevice, listNode)
    {
        if (sampleDev->devobj == nullptr || HdfDeviceGetServiceName(sampleDev->devobj) == nullptr) {
            DListRemove(&sampleDev->listNode);
            OsalMemFree(sampleDev);
            continue;
        }

        if (strcmp(HdfDeviceGetServiceName(sampleDev->devobj), servName) == 0) {
            HdfDeviceObjectRelease(sampleDev->devobj);
            DListRemove(&sampleDev->listNode);
            OsalMemFree(sampleDev);
            HDF_LOGI("remove device %{public}s success", servName);
        }
    }

    return HDF_SUCCESS;
}

static int32_t SampleServiceUpdateDevice(struct HdfDeviceObject *device, const char *servInfo)
{
    if (HdfDeviceObjectSetServInfo(device, servInfo) != HDF_SUCCESS) {
        HDF_LOGE("failed to set service info");
        return HDF_FAILURE;
    }
    return HdfDeviceObjectUpdate(device);
}

static int32_t SampleServiceTansSmq(
    struct HdfDeviceObject *device, SharedMemQueueMeta<SampleSmqElement> *smqMeta, uint32_t element)
{
    HDF_LOGI("SampleServiceTansSmq in, element=%{public}u", element);
    if (element > SMQ_TRANS_ELEMENT_MAX) {
        return HDF_ERR_INVALID_PARAM;
    }
    static std::shared_ptr<SharedMemQueue<SampleSmqElement>> smq = nullptr;
    smq = std::make_shared<SharedMemQueue<SampleSmqElement>>(*smqMeta);
    if (!smq->IsGood()) {
        HDF_LOGE("failed to create fmq from meta");
        return HDF_FAILURE;
    }
    static size_t elem = static_cast<size_t>(element);
    std::thread t([&]() {
        HDF_LOGI("SampleServiceTansSmq:smq read thread start, elem=%{public}zu", elem);
        std::shared_ptr<SharedMemQueue<SampleSmqElement>> smqLocal = smq;
        size_t elemLocal = elem;
        smq = nullptr;

        while (true) {
            SampleSmqElement t[SMQ_TRANS_ELEMENT_MAX] = {};
            int ret;
            if (smqLocal->GetMeta()->GetType() == SmqType::SYNCED_SMQ) {
                ret = smqLocal->Read(&t[0], elemLocal, OHOS::MillisecToNanosec(SMQ_TRANS_WAIT_TIME));
            } else {
                ret = smqLocal->ReadNonBlocking(&t[0], elemLocal);
            }
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("failed to read message from smq, %{public}d", ret);
                break;
            }
            for (size_t i = 0; i < elemLocal; i++) {
                HDF_LOGI(
                    "read message from smq, info[%{public}zu]:%{public}d, %{public}llu",
                    i, t[i].data32, (unsigned long long)t[i].data64);
            }
        }
    });
    t.detach();

    return HDF_SUCCESS;
}

static const struct SampleHdi g_sampleHdiImpl = {
    .ping = SampleServicePing,
    .sum = SampleServiceSum,
    .callback = SampleServiceCallback,
    .registerDevice = SampleServiceRegisterDevice,
    .unregisterDevice = SampleServiceUnregisterDevice,
    .updateService = SampleServiceUpdateDevice,
    .tansSmq = SampleServiceTansSmq,
};

const struct SampleHdi *SampleHdiImplInstance(void)
{
    return &g_sampleHdiImpl;
}