/*
 * 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 "adapter_if.h"

#include <dirent.h>
#include <endian.h>
#include <fcntl.h>
#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "osal_time.h"
#include "usbd_wrapper.h"

#define HDF_LOG_TAG adapter_if
#define SLEEP_DELAY 100000
#define OPEN_CNT    30

static bool IsDirExist(const char *path)
{
    DIR *dir = NULL;

    if (path == NULL) {
        HDF_LOGE("%{public}s:%{public}d invalid param path.", __func__, __LINE__);
        return false;
    }

    dir = opendir(path);
    if (dir == NULL) {
        HDF_LOGE("%{public}s: %{public}d: opendir failed!, path is %{public}s, errno is %{public}d", __func__, __LINE__,
            path, errno);
        return false;
    }
    closedir(dir);
    return true;
}

static bool IsDir(const char *path)
{
    struct stat statBuf;
    if (lstat(path, &statBuf) == 0) {
        return S_ISDIR(statBuf.st_mode) != 0;
    }
    return false;
}

static void GetFilePath(const char *path, const char *fileName, char *filePath)
{
    int32_t ret = strcpy_s(filePath, MAX_PATHLEN - 1, path);
    if (ret != EOK) {
        HDF_LOGE("%{public}s: strcpy_s failed", __func__);
        return;
    }

    if (strlen(path) > 0 && filePath[strlen(path) - 1] != '/') {
        if (strlen(path) + 1 >= MAX_PATHLEN - strlen(fileName)) {
            HDF_LOGE("%{public}s: file path too long", __func__);
            return;
        }
        ret = strcat_s(filePath, MAX_PATHLEN - 1, "/");
        if (ret != EOK) {
            HDF_LOGE("%{public}s: strcat_s failed", __func__);
            return;
        }
    }

    ret = strcat_s(filePath, MAX_PATHLEN - 1, fileName);
    if (ret != EOK) {
        HDF_LOGE("%{public}s: strcat_s failed", __func__);
    }
}

static bool IsSpecialDir(const char *path)
{
    return (strcmp(path, ".") == 0) || strcmp(path, "..") == 0;
}

static void DeleteFile(const char *path)
{
    DIR *dir = NULL;
    struct dirent *dirInfo = NULL;

    if (IsDir(path)) {
        if ((dir = opendir(path)) == NULL) {
            return;
        }
        char filePath[PATH_MAX];
        while ((dirInfo = readdir(dir)) != NULL) {
            GetFilePath(path, dirInfo->d_name, filePath);
            if (IsSpecialDir(dirInfo->d_name)) {
                continue;
            }
            DeleteFile(filePath);
            (void)remove(filePath);
        }
        closedir(dir);
    }
}

static bool IsDeviceDirExist(const char *deviceName)
{
    char tmp[MAX_PATHLEN] = {0};
    int32_t ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s", CONFIGFS_DIR, deviceName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return false;
    }

    return IsDirExist(tmp);
}

static int32_t UsbFnWriteFile(const char *path, const char *str)
{
    size_t ret;
    if (strlen(str) == 0) {
        return 0;
    }

    FILE *fp = fopen(path, "w");
    if (fp == NULL) {
        HDF_LOGE("%{public}s: UsbFnWriteFile failed", __func__);
        return HDF_ERR_BAD_FD;
    }

    ret = fwrite(str, strlen(str), 1, fp);
    if (ret != 1) {
        (void)fclose(fp);
        return HDF_FAILURE;
    }
    (void)fclose(fp);
    return 0;
}

static int32_t UsbFnWriteProp(const char *deviceName, const char *propName, uint32_t propValue)
{
    char tmp[MAX_PATHLEN] = {0};
    char tmpVal[MAX_NAMELEN] = {0};
    int32_t ret;
    if (deviceName == NULL || propName == NULL) {
        HDF_LOGE("%{public}s: INVALID PARAM", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/%s", CONFIGFS_DIR, deviceName, propName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }

    ret = snprintf_s(tmpVal, MAX_NAMELEN, MAX_NAMELEN - 1, "0x%x", propValue);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }

    return UsbFnWriteFile(tmp, tmpVal);
}

static int32_t UsbFnWriteConfString(const char *deviceName, int32_t configVal, uint16_t lang, const char *stringValue)
{
    int32_t ret;
    char tmp[MAX_PATHLEN] = {0};
    char tmpPath[MAX_PATHLEN] = {0};
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/configs/b.%d/strings/0x%x", CONFIGFS_DIR, deviceName,
        configVal, lang);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }

    if (!IsDirExist(tmp)) {
        ret = mkdir(tmp, S_IREAD | S_IWRITE);
        if (ret != 0) {
            HDF_LOGE("%{public}s: mkdir failed", __func__);
            return HDF_ERR_IO;
        }
    }

    ret = snprintf_s(tmpPath, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/configuration", tmp);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }

    ret = UsbFnWriteFile(tmpPath, stringValue);
    return ret;
}

static int32_t UsbFnWriteDesString(
    const char *deviceName, uint16_t lang, const char *stringName, const char *stringValue)
{
    int32_t ret;
    char tmp[MAX_PATHLEN] = {0};
    char tmpPath[MAX_PATHLEN] = {0};
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/strings/0x%x", CONFIGFS_DIR, deviceName, lang);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }
    if (!IsDirExist(tmp)) {
        ret = mkdir(tmp, S_IREAD | S_IWRITE);
        if (ret != 0) {
            HDF_LOGE("%{public}s: mkdir failed", __func__);
            return HDF_ERR_IO;
        }
    }

    ret = snprintf_s(tmpPath, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s", tmp, stringName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }

    ret = UsbFnWriteFile(tmpPath, stringValue);
    return ret;
}

static int32_t UsbFnAdapterCreateFunc(const char *configPath, const char *funcPath)
{
    int32_t ret;

    ret = mkdir(funcPath, S_IREAD | S_IWRITE);
    if (ret != 0) {
        HDF_LOGE("%{public}s: mkdir failed", __func__);
        return HDF_ERR_IO;
    }

    ret = symlink(funcPath, configPath);
    if (ret != 0) {
        HDF_LOGE("%{public}s: symlink failed", __func__);
        return HDF_ERR_IO;
    }
    usleep(SLEEP_DELAY);
    return 0;
}

static int32_t UsbFnReadFile(const char *path, char *str, uint16_t len)
{
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        HDF_LOGE("%{public}s: fopen failed", __func__);
        return HDF_ERR_BAD_FD;
    }
    if (fread(str, len, 1, fp) != 1) {
        HDF_LOGE("%{public}s: fread failed", __func__);
        (void)fclose(fp);
        return HDF_ERR_IO;
    }
    (void)fclose(fp);
    return 0;
}

static int32_t UsbFnAdapterWriteUDC(const char *deviceName, const char *udcName, int32_t enable)
{
    char tmp[MAX_PATHLEN] = {0};
    if (deviceName == NULL || udcName == NULL || IsDeviceDirExist(deviceName) == false) {
        return HDF_ERR_INVALID_PARAM;
    }

    int32_t ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/UDC", CONFIGFS_DIR, deviceName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }
    if (enable != 0) {
        (void)UsbFnWriteFile(tmp, udcName);
        char udcTmp[MAX_NAMELEN] = {0};
        for (int32_t i = 0; i < OPEN_CNT; i++) {
            (void)UsbFnReadFile(tmp, udcTmp, strlen(udcName));
            if (!strcmp(udcName, udcTmp)) {
                return 0;
            }
            usleep(SLEEP_DELAY);
        }
        if (strcmp(udcName, udcTmp)) {
            return HDF_ERR_IO;
        }
    } else {
        (void)UsbFnWriteFile(tmp, "\n");
    }
    return 0;
}

static int32_t UsbFnAdapterOpenFn(void)
{
    int32_t i;
    int32_t ep = -1;
    for (i = 0; i < OPEN_CNT; i++) {
        ep = open(USBFN_DEV, O_RDWR);
        if (ep > 0) {
            break;
        }
        usleep(SLEEP_DELAY);
    }
    if (ep < 0) {
        HDF_LOGE("func not alloc");
    }
    return ep;
}

static int32_t UsbFnAdapterClosefn(int32_t fd)
{
    if (fd <= 0) {
        return HDF_ERR_INVALID_PARAM;
    }
    return close(fd);
}

static int32_t UsbFnAdapterCreatInterface(const char *interfaceName, int32_t nameLen)
{
    int32_t ret;
    int32_t fd;
    struct FuncNew fnnew;
    if (interfaceName == NULL || nameLen <= 0) {
        return HDF_ERR_INVALID_PARAM;
    }
    fd = UsbFnAdapterOpenFn();
    if (fd <= 0) {
        HDF_LOGE("%{public}s: UsbFnAdapterOpenFn failed", __func__);
        return HDF_ERR_IO;
    }

    fnnew.nameLen = (uint32_t)nameLen;
    ret = snprintf_s(fnnew.name, MAX_NAMELEN, MAX_NAMELEN - 1, "%s", interfaceName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        UsbFnAdapterClosefn(fd);
        return HDF_ERR_IO;
    }
    ret = ioctl(fd, FUNCTIONFS_NEWFN, &fnnew);
    if (ret != 0) {
        HDF_LOGE("%{public}s: FUNCTIONFS_NEWFN failed", __func__);
        UsbFnAdapterClosefn(fd);
        return HDF_ERR_IO;
    }
    ret = UsbFnAdapterClosefn(fd);
    usleep(SLEEP_DELAY);
    return ret;
}

static int32_t UsbFnAdapterDelInterface(const char *interfaceName, int32_t nameLen)
{
    int32_t ret;
    struct FuncNew fnnew;
    if (interfaceName == NULL || nameLen <= 0) {
        return HDF_ERR_INVALID_PARAM;
    }

    int32_t fd = UsbFnAdapterOpenFn();
    if (fd <= 0) {
        return HDF_ERR_IO;
    }

    fnnew.nameLen = (uint32_t)nameLen;
    ret = snprintf_s(fnnew.name, MAX_NAMELEN, MAX_NAMELEN - 1, "%s", interfaceName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        UsbFnAdapterClosefn(fd);
        return HDF_ERR_IO;
    }
    ret = ioctl(fd, FUNCTIONFS_DELFN, &fnnew);
    if (ret != 0) {
        HDF_LOGE("%{public}s: FUNCTIONFS_DELFN failed", __func__);
        UsbFnAdapterClosefn(fd);
        return HDF_ERR_IO;
    }
    ret = UsbFnAdapterClosefn(fd);
    return ret;
}

static int32_t UsbFnAdapterOpenPipe(const char *interfaceName, int32_t epIndex)
{
    if (interfaceName == NULL || epIndex < 0) {
        return HDF_ERR_INVALID_PARAM;
    }

    char epName[MAX_NAMELEN];
    int32_t ret = snprintf_s(epName, MAX_NAMELEN, MAX_NAMELEN - 1, "/dev/functionfs/%s.ep%d", interfaceName, epIndex);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return HDF_ERR_IO;
    }

    int32_t ep = -1;
    for (int32_t i = 0; i < OPEN_CNT; i++) {
        ep = open(epName, O_RDWR);
        if (ep > 0) {
            break;
        }
        usleep(SLEEP_DELAY);
    }
    if (ep < 0) {
        HDF_LOGE("unable to open %{public}s", epName);
        return HDF_DEV_ERR_NO_DEVICE;
    }
    return ep;
}

static int32_t UsbFnAdapterClosePipe(int32_t ep)
{
    if (ep <= 0) {
        return HDF_ERR_INVALID_PARAM;
    }

    return close(ep);
}

static void GetHeaderStr(struct UsbFnStrings ** const strings, struct UsbFunctionfsStringsHead *headerStr)
{
    uint32_t i, j;
    uint32_t langCount = 0;
    uint32_t strCount = 0;
    uint32_t len = 0;
    for (i = 0; strings[i] != NULL; i++) {
        langCount++;
        for (j = 0; strings[i]->strings[j].s; j++) {
            len += strlen(strings[i]->strings[j].s) + sizeof(char);
        }
        strCount = j;
    }
    headerStr->magic = htole32(FUNCTIONFS_STRINGS_MAGIC);
    headerStr->length = htole32(sizeof(struct UsbFunctionfsStringsHead) + langCount * sizeof(uint16_t) + len);
    headerStr->strCount = strCount;
    headerStr->langCount = langCount;
}

static int32_t UsbFnWriteStrings(int32_t ep0, struct UsbFnStrings ** const strings)
{
    uint8_t *str = NULL;
    uint8_t *whereDec = NULL;
    uint32_t i, j;
    int32_t ret;
    struct UsbFunctionfsStringsHead headerStr = {0};

    GetHeaderStr(strings, &headerStr);
    str = UsbFnMemCalloc(headerStr.length);
    if (str == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }

    whereDec = str;
    ret = memcpy_s(whereDec, headerStr.length, &headerStr, sizeof(struct UsbFunctionfsStringsHead));
    if (ret != EOK) {
        goto ERR;
    }
    whereDec += sizeof(struct UsbFunctionfsStringsHead);

    for (i = 0; i < headerStr.langCount; i++) {
        ret = memcpy_s(whereDec, headerStr.length - (whereDec - str), &strings[i]->language, sizeof(uint16_t));
        if (ret != EOK) {
            goto ERR;
        }
        whereDec += sizeof(uint16_t);
        for (j = 0; j < headerStr.strCount; j++) {
            if (strlen(strings[i]->strings[j].s)) {
                ret = memcpy_s(whereDec, headerStr.length - (whereDec - str), strings[i]->strings[j].s,
                    strlen(strings[i]->strings[j].s));
                whereDec += strlen(strings[i]->strings[j].s) + sizeof(char);
            } else {
                break;
            }
            if (ret != EOK) {
                goto ERR;
            }
        }
    }

    if (write(ep0, str, headerStr.length) < 0) {
        goto ERR;
    }
    UsbFnMemFree(str);
    return 0;
ERR:
    UsbFnMemFree(str);
    return HDF_FAILURE;
}

static int32_t CopyCount(uint8_t **whereDec, uint32_t fsCount, uint32_t hsCount, uint32_t ssCount)
{
    int32_t ret;
    if (fsCount != 0) {
        ret = memcpy_s(*whereDec, sizeof(uint32_t), &fsCount, sizeof(uint32_t));
        if (ret != EOK) {
            return HDF_FAILURE;
        }
        *whereDec += sizeof(uint32_t);
    }
    if (hsCount != 0) {
        ret = memcpy_s(*whereDec, sizeof(uint32_t), &hsCount, sizeof(uint32_t));
        if (ret != EOK) {
            return HDF_FAILURE;
        }
        *whereDec += sizeof(uint32_t);
    }
    if (ssCount != 0) {
        ret = memcpy_s(*whereDec, sizeof(uint32_t), &ssCount, sizeof(uint32_t));
        if (ret != EOK) {
            return HDF_FAILURE;
        }
        *whereDec += sizeof(uint32_t);
    }

    return 0;
}

static int32_t WriteFuncDescriptors(uint8_t ** const whereDec, struct UsbDescriptorHeader ** const headDes)
{
    for (uint32_t i = 0; headDes[i] != NULL; i++) {
        if (memcpy_s(*whereDec, headDes[i]->bLength, headDes[i], headDes[i]->bLength) != EOK) {
            HDF_LOGE("%{public}s: memcpy_s failed", __func__);
            return HDF_FAILURE;
        }
        *whereDec += headDes[i]->bLength;
    }
    return 0;
}

static void GetCountAndHead(struct UsbFunctionfsDescsHeadV2 *header, uint32_t *fsCount, uint32_t *hsCount,
    uint32_t *ssCount, const struct UsbFnFunction *func)
{
    int32_t i;
    uint32_t lenCount = 0;
    uint32_t lenDes = 0;
    *fsCount = 0;
    *hsCount = 0;
    *ssCount = 0;

    for (i = 0; func->fsDescriptors[i] != NULL; i++) {
        (*fsCount)++;
        lenDes += func->fsDescriptors[i]->bLength;
    }
    for (i = 0; func->hsDescriptors[i] != NULL; i++) {
        (*hsCount)++;
        lenDes += func->hsDescriptors[i]->bLength;
    }
    for (i = 0; func->ssDescriptors[i] != NULL; i++) {
        (*ssCount)++;
        lenDes += func->ssDescriptors[i]->bLength;
    }

    if (*fsCount != 0) {
        lenCount += sizeof(uint32_t);
        header->flags |= htole32(FUNCTIONFS_HAS_FS_DESC);
    }
    if (*hsCount != 0) {
        lenCount += sizeof(uint32_t);
        header->flags |= htole32(FUNCTIONFS_HAS_HS_DESC);
    }
    if (*ssCount != 0) {
        lenCount += sizeof(uint32_t);
        header->flags |= htole32(FUNCTIONFS_HAS_SS_DESC);
    }

    header->magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
    header->length = htole32(sizeof(struct UsbFunctionfsDescsHeadV2) + lenCount + lenDes);
}

static int32_t UsbFnAdapterCreatPipes(int32_t ep0, const struct UsbFnFunction *func)
{
    uint8_t *dec = NULL;
    uint8_t *whereDec = NULL;
    uint32_t fsCount;
    uint32_t hsCount;
    uint32_t ssCount;
    struct UsbFunctionfsDescsHeadV2 header = {0};

    GetCountAndHead(&header, &fsCount, &hsCount, &ssCount, func);

    dec = UsbFnMemCalloc(header.length);
    if (dec == NULL) {
        HDF_LOGE("%{public}s: UsbFnMemCalloc failed", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }
    whereDec = dec;

    int32_t ret = memcpy_s(whereDec, header.length, &header, sizeof(struct UsbFunctionfsDescsHeadV2));
    if (ret != EOK) {
        UsbFnMemFree(dec);
        return HDF_FAILURE;
    }
    whereDec += sizeof(struct UsbFunctionfsDescsHeadV2);

    ret = CopyCount(&whereDec, fsCount, hsCount, ssCount);
    if (ret != EOK) {
        UsbFnMemFree(dec);
        return HDF_FAILURE;
    }

    ret = WriteFuncDescriptors(&whereDec, func->fsDescriptors);
    if (ret != EOK) {
        UsbFnMemFree(dec);
        return HDF_FAILURE;
    }

    ret = WriteFuncDescriptors(&whereDec, func->hsDescriptors);
    if (ret != EOK) {
        UsbFnMemFree(dec);
        return HDF_FAILURE;
    }

    ret = WriteFuncDescriptors(&whereDec, func->ssDescriptors);
    if (ret != EOK) {
        UsbFnMemFree(dec);
        return HDF_FAILURE;
    }

    if (write(ep0, dec, header.length) < 0) {
        HDF_LOGE("unable do write descriptors");
        UsbFnMemFree(dec);
        return HDF_ERR_IO;
    }

    UsbFnMemFree(dec);
    ret = UsbFnWriteStrings(ep0, func->strings);

    usleep(SLEEP_DELAY);
    return ret;
}

static int32_t WriteDeviceId(const char *devName, const struct UsbDeviceDescriptor *desc)
{
    int32_t ret;
    ret = UsbFnWriteProp(devName, "idVendor", desc->idVendor);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "idProduct", desc->idProduct);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "bcdUSB", desc->bcdUSB);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "bcdDevice", desc->bcdDevice);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "bDeviceClass", desc->bDeviceClass);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "bDeviceSubClass", desc->bDeviceSubClass);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "bDeviceProtocol", desc->bDeviceProtocol);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnWriteProp(devName, "bMaxPacketSize0", desc->bMaxPacketSize0);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }
    return 0;
}

static int32_t WriteDeviceDescriptor(
    const char *devName, const struct UsbDeviceDescriptor *desc, struct UsbFnStrings **strings)
{
    int32_t i, ret;
    ret = WriteDeviceId(devName, desc);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_INVALID_PARAM;
    }

    for (i = 0; strings[i] != NULL; i++) {
        ret = UsbFnWriteDesString(
            devName, strings[i]->language, "manufacturer", strings[i]->strings[desc->iManufacturer].s);
        if (ret != HDF_SUCCESS) {
            return HDF_ERR_INVALID_PARAM;
        }
        ret = UsbFnWriteDesString(devName, strings[i]->language, "product", strings[i]->strings[desc->iProduct].s);
        if (ret != HDF_SUCCESS) {
            return HDF_ERR_INVALID_PARAM;
        }
    }
    return 0;
}

static int32_t CreatDeviceDir(const char *devName)
{
    int32_t ret;
    char tmp[MAX_PATHLEN];
    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s", CONFIGFS_DIR, devName);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    if (!IsDirExist(tmp)) {
        ret = mkdir(tmp, S_IREAD | S_IWRITE);
        if (ret != 0) {
            HDF_LOGE("%{public}s: mkdir failed", __func__);
            return HDF_ERR_IO;
        }
    }
    return 0;
}

static int32_t WriteConfPowerAttributes(const char *devName, struct UsbFnConfiguration *config, uint8_t confVal)
{
    int32_t ret;
    char configName[MAX_PATHLEN];
    char tmp[MAX_PATHLEN], val[MAX_NAMELEN];
    (void)memset_s(configName, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(configName, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/configs/b.%u", CONFIGFS_DIR, devName, confVal);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    if (!IsDirExist(configName)) {
        ret = mkdir(configName, S_IREAD | S_IWRITE);
        if (ret != 0) {
            return HDF_ERR_IO;
        }
    }
    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/MaxPower", configName);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    (void)memset_s(val, MAX_NAMELEN, 0, MAX_NAMELEN);
    ret = snprintf_s(val, MAX_NAMELEN, MAX_NAMELEN - 1, "%u", config->maxPower);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    ret = UsbFnWriteFile(tmp, val);
    if (ret < 0) {
        return HDF_ERR_INVALID_PARAM;
    }

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/bmAttributes", configName);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    (void)memset_s(val, MAX_NAMELEN, 0, MAX_NAMELEN);
    ret = snprintf_s(val, MAX_NAMELEN, MAX_NAMELEN - 1, "0x%x", config->attributes);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    ret = UsbFnWriteFile(tmp, val);
    if (ret < 0) {
        return HDF_ERR_INVALID_PARAM;
    }
    return 0;
}

static int32_t CreatKernelFunc(const char *devName, const struct UsbFnFunction *functions, uint8_t confVal)
{
    int32_t ret;
    char configPath[MAX_PATHLEN];
    char funcPath[MAX_PATHLEN];

    (void)memset_s(funcPath, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(
        funcPath, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/functions/%s", CONFIGFS_DIR, devName, functions->funcName);
    if (ret < 0) {
        return HDF_ERR_IO;
    }

    (void)memset_s(configPath, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(configPath, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/configs/b.%u/%s", CONFIGFS_DIR, devName, confVal,
        functions->funcName);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    ret = UsbFnAdapterCreateFunc(configPath, funcPath);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%{public}s: UsbFnAdapterCreateFunc failed", __func__);
        return HDF_ERR_IO;
    }
    return ret;
}

static void CleanConfigFs(const char *devName, const char *funcName);
static int32_t CreatFunc(const char *devName, const struct UsbFnFunction *functions, uint8_t confVal)
{
    int32_t fd, ret;
    char interfaceName[MAX_NAMELEN];

    ret = CreatKernelFunc(devName, functions, confVal);
    if (ret < 0) {
        return HDF_ERR_IO;
    }

    (void)memset_s(interfaceName, MAX_NAMELEN, 0, MAX_NAMELEN);
    ret = snprintf_s(interfaceName, MAX_NAMELEN, MAX_NAMELEN - 1, "%s", functions->funcName);
    if (ret < 0) {
        return HDF_ERR_IO;
    }
    ret = UsbFnAdapterCreatInterface(interfaceName, strlen(interfaceName));
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%{public}s: UsbFnAdapterCreatInterface failed", __func__);
        CleanConfigFs(devName, interfaceName);
        return HDF_ERR_IO;
    }

    fd = UsbFnAdapterOpenPipe(interfaceName, 0);
    if (fd <= 0) {
        HDF_LOGE("%{public}s: UsbFnAdapterOpenPipe failed", __func__);
        CleanConfigFs(devName, interfaceName);
        return HDF_ERR_IO;
    }
    ret = UsbFnAdapterCreatPipes(fd, functions);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%{public}s: UsbFnAdapterCreatPipes failed", __func__);
        UsbFnAdapterClosePipe(fd);
        return HDF_ERR_IO;
    }
    ret = UsbFnAdapterClosePipe(fd);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%{public}s: UsbFnAdapterClosePipe failed", __func__);
        return HDF_ERR_IO;
    }
    return 0;
}

static void DelConfigDevice(const char *deviceName)
{
    int32_t ret;
    char tmp[MAX_PATHLEN];
    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/configs", CONFIGFS_DIR, deviceName);
    if (ret < 0) {
        return;
    }
    DeleteFile(tmp);

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/functions", CONFIGFS_DIR, deviceName);
    if (ret < 0) {
        return;
    }
    DeleteFile(tmp);

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/strings", CONFIGFS_DIR, deviceName);
    if (ret < 0) {
        return;
    }
    DeleteFile(tmp);

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s", CONFIGFS_DIR, deviceName);
    if (ret < 0) {
        return;
    }
    rmdir(tmp);
}

static void CleanConfigFs(const char *devName, const char *funcName)
{
    int32_t ret;
    char tmp[MAX_PATHLEN];

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/configs/b.1/%s", CONFIGFS_DIR, devName, funcName);
    if (ret < 0) {
        return;
    }
    (void)remove(tmp);

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/functions/%s", CONFIGFS_DIR, devName, funcName);
    if (ret < 0) {
        return;
    }
    (void)remove(tmp);
}

static void CleanFunction(const char *devName, const char *funcName)
{
    int32_t ret;
    int32_t nameLength = (int32_t)strlen(funcName);
    ret = UsbFnAdapterDelInterface(funcName, nameLength);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%{public}s: UsbFnAdapterDelInterface failed", __func__);
        return;
    }
    CleanConfigFs(devName, funcName);
}

static void UsbFnAdapterCleanDevice(const char *devName)
{
    int32_t ret;
    char tmp[MAX_PATHLEN];
    DIR *dir = NULL;
    struct dirent *ptr = NULL;

    (void)memset_s(tmp, MAX_PATHLEN, 0, MAX_PATHLEN);
    ret = snprintf_s(tmp, MAX_PATHLEN, MAX_PATHLEN - 1, "%s/%s/functions/", CONFIGFS_DIR, devName);
    if (ret < 0) {
        HDF_LOGE("%{public}s: snprintf_s failed", __func__);
        return;
    }
    if ((dir = opendir(tmp)) == NULL) {
        return;
    }
    while ((ptr = readdir(dir)) != NULL) {
        if (strncmp(ptr->d_name, FUNCTION_GENERIC, strlen(FUNCTION_GENERIC))) {
            continue;
        }
        CleanFunction(devName, ptr->d_name);
    }
    closedir(dir);
}

static int32_t UsbFnAdapterDelDevice(const char *deviceName, const char *udcName, struct UsbFnDeviceDesc *des)
{
    uint32_t i, j;
    int32_t ret;
    if (deviceName == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }
    ret = UsbFnAdapterWriteUDC(deviceName, udcName, 0);
    if (ret < 0) {
        return ret;
    }
    for (i = 0; des->configs[i] != NULL; i++) {
        for (j = 0; des->configs[i]->functions[j] != NULL; j++) {
            if (des->configs[i]->functions[j]->enable == false) {
                continue;
            }
            if (strncmp(des->configs[i]->functions[j]->funcName, FUNCTION_GENERIC, strlen(FUNCTION_GENERIC)) != 0) {
                CleanConfigFs(deviceName, des->configs[i]->functions[j]->funcName);
                continue;
            }
            CleanFunction(deviceName, des->configs[i]->functions[j]->funcName);
        }
    }

    if (strcmp("g1", deviceName) != 0) {
        DelConfigDevice(deviceName);
    }
    return 0;
}

static bool CreateFun(struct UsbFnFunction *function, const char *devName, uint8_t *confVal, int32_t *ret)
{
    if (function == NULL || devName == NULL || confVal == NULL || ret == NULL) {
        return false;
    }

    if (function->enable == false) {
        return false;
    }
    if (strncmp(function->funcName, FUNCTION_GENERIC, strlen(FUNCTION_GENERIC)) != 0) {
        *ret = CreatKernelFunc(devName, function, *confVal);
    } else {
        *ret = CreatFunc(devName, function, *confVal);
    }
    return true;
}

static int32_t UsbFnAdapterCreateDevice(const char *udcName, const char *devName, struct UsbFnDeviceDesc *descriptor)
{
    uint32_t i, j;
    int32_t ret;
    uint8_t confVal;

    UsbFnAdapterCleanDevice(devName);

    ret = CreatDeviceDir(devName);
    if (ret != HDF_SUCCESS) {
        return HDF_ERR_IO;
    }

    ret = WriteDeviceDescriptor(devName, descriptor->deviceDesc, descriptor->deviceStrings);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%{public}s: WriteDeviceDescriptor failed", __func__);
        return HDF_ERR_IO;
    }

    for (i = 0; descriptor->configs[i] != NULL; i++) {
        confVal = descriptor->configs[i]->configurationValue;
        ret = WriteConfPowerAttributes(devName, descriptor->configs[i], confVal);
        if (ret != HDF_SUCCESS) {
            HDF_LOGE("%{public}s: WriteConfPowerAttributes failed", __func__);
            return HDF_ERR_IO;
        }

        for (j = 0; descriptor->deviceStrings[j] != NULL; j++) {
            ret = UsbFnWriteConfString(devName, confVal, descriptor->deviceStrings[j]->language,
                descriptor->deviceStrings[j]->strings[descriptor->configs[i]->iConfiguration].s);
            if (ret < 0) {
                HDF_LOGE("%{public}s: UsbFnWriteConfString failed", __func__);
                return HDF_ERR_INVALID_PARAM;
            }
        }

        for (j = 0; descriptor->configs[i]->functions[j] != NULL; j++) {
            if (!CreateFun(descriptor->configs[i]->functions[j], devName, &confVal, &ret)) {
                continue;
            }
            if (ret < 0) {
                HDF_LOGE("%{public}s: CreatFunc failed", __func__);
                (void)UsbFnAdapterWriteUDC(devName, "none", 0);
                (void)UsbFnAdapterWriteUDC(devName, udcName, 1);
                return HDF_ERR_INVALID_PARAM;
            }
        }
    }

    return HDF_SUCCESS;
}

static int32_t UsbFnAdapterGetPipeInfo(int32_t ep, struct UsbFnPipeInfo * const pipeInfo)
{
    int32_t ret;
    if (ep <= 0 || pipeInfo == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    struct UsbEndpointDescriptor desc;
    ret = ioctl(ep, FUNCTIONFS_ENDPOINT_DESC, &desc);
    if (ret != 0) {
        HDF_LOGE("%{public}s: FUNCTIONFS_ENDPOINT_DESC failed", __func__);
        return HDF_ERR_IO;
    }

    pipeInfo->type = desc.bmAttributes;
    pipeInfo->dir = USB_PIPE_DIRECTION_OUT;
    if (desc.bEndpointAddress & 0x80) {
        pipeInfo->dir = USB_PIPE_DIRECTION_IN;
    }

    pipeInfo->maxPacketSize = desc.wMaxPacketSize;
    pipeInfo->interval = desc.bInterval;

    return ret;
}

static int32_t UsbFnAdapterQueueInit(int32_t ep)
{
    if (ep <= 0) {
        return HDF_ERR_INVALID_PARAM;
    }
    return ioctl(ep, FUNCTIONFS_ENDPOINT_QUEUE_INIT, 0);
}

static int32_t UsbFnAdapterQueueDel(int32_t ep)
{
    if (ep <= 0) {
        return HDF_ERR_INVALID_PARAM;
    }

    return ioctl(ep, FUNCTIONFS_ENDPOINT_QUEUE_DEL, 0);
}

static int32_t UsbFnAdapterReleaseBuf(int32_t ep, const struct GenericMemory *mem)
{
    if (ep <= 0 || mem == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    return ioctl(ep, FUNCTIONFS_ENDPOINT_RELEASE_BUF, mem);
}

static int32_t UsbFnAdapterPipeIo(int32_t ep, struct IoData *ioData)
{
    int32_t ret;
    if (ep <= 0 || ioData == NULL) {
        HDF_LOGE("%{public}s: invalid param", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    if (ioData->read) {
        ret = ioctl(ep, FUNCTIONFS_ENDPOINT_READ, ioData);
    } else {
        ret = ioctl(ep, FUNCTIONFS_ENDPOINT_WRITE, ioData);
    }

    if (ret < 0) {
        HDF_LOGE("%{public}s: handle endpoint failed errno:%{public}d", __func__, errno);
    }

    return ret;
}

static int32_t UsbFnAdapterCancelIo(int32_t ep, const struct IoData * const ioData)
{
    if (ep <= 0 || ioData == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }
    return ioctl(ep, FUNCTIONFS_ENDPOINT_RW_CANCEL, ioData);
}

static uint8_t *UsbFnAdapterMapAddr(int32_t ep, uint32_t len)
{
    if (ep <= 0) {
        return NULL;
    }

    return mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, ep, 0);
}

static int32_t UsbFnAdapterUnmapAddr(uint8_t * const mapAddr, uint32_t len)
{
    if (mapAddr == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }

    return munmap(mapAddr, len);
}

static void Ep0Event(struct UsbFnEventAll *event, struct pollfd *pfds)
{
    int32_t ret;
    uint8_t i;
    for (i = 0; i < event->ep0Num; i++) {
        if ((uint32_t)pfds[i].revents & POLLIN) {
            ret = read(event->ep0[i], &event->ep0Event[i].ctrlEvent, sizeof(struct UsbFnCtrlEvent));
            if (!ret) {
                HDF_LOGE("unable to read event from ep0");
            }
            event->ep0Event[i].type = USB_EP0_CTRL_EVENT;
        } else if ((uint32_t)pfds[i].revents & POLLOUT) {
            ret = ioctl(event->ep0[i], FUNCTIONFS_ENDPOINT_GET_EP0_EVENT, &event->ep0Event[i].reqEvent);
            if (!ret) {
                HDF_LOGE("unable to read reqEvent from ep0");
            }
            event->ep0Event[i].type = USB_EP0_IO_COMPLETED;
        }
    }
}

static void EpEvent(struct UsbFnEventAll *event, struct pollfd *pfds)
{
    uint8_t i;
    for (i = 0; i < event->epNum; i++) {
        if ((pfds[i + event->ep0Num].revents & POLLIN)) {
            event->numEvent[i] = read(event->epx[i], event->reqEvent[i], MAX_REQUEST * sizeof(struct UsbFnReqEvent)) /
                sizeof(struct UsbFnReqEvent);
            if (!event->numEvent[i]) {
                HDF_LOGE("unable to read indexBuf from ep#");
            }
        }
    }
}

static int32_t UsbFnAdapterPollEvent(struct UsbFnEventAll *event, int32_t timeout)
{
    int32_t ret;
    uint8_t i;
    struct pollfd *pfds = NULL;

    if (event == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }
    if (event->ep0Num + event->epNum == 0) {
        return HDF_ERR_INVALID_PARAM;
    }
    pfds = UsbFnMemCalloc((event->ep0Num + event->epNum) * sizeof(struct pollfd));
    if (pfds == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }
    for (i = 0; i < event->ep0Num; i++) {
        if (event->ep0[i] <= 0) {
            UsbFnMemFree(pfds);
            HDF_LOGE("%{public}s: ep[%{public}d] = %{public}d", __func__, i, event->ep0[i]);
            return HDF_ERR_INVALID_PARAM;
        }
        pfds[i].fd = event->ep0[i];
        pfds[i].events = POLLIN | POLLOUT;
    }
    for (i = 0; i < event->epNum; i++) {
        if (event->epx[i] <= 0) {
            UsbFnMemFree(pfds);
            HDF_LOGE("%{public}s: ep[%{public}d] = %{public}d", __func__, i, event->epx[i]);
            return HDF_ERR_INVALID_PARAM;
        }
        pfds[i + event->ep0Num].fd = event->epx[i];
        pfds[i + event->ep0Num].events = POLLIN;
    }
    ret = poll(pfds, event->ep0Num + event->epNum, timeout);
    if (ret == 0) {
        UsbFnMemFree(pfds);
        return HDF_ERR_TIMEOUT;
    } else if (ret < 0) {
        HDF_LOGE("%{public}s: interrupt", __func__);
        UsbFnMemFree(pfds);
        return HDF_ERR_IO;
    }
    Ep0Event(event, pfds);
    EpEvent(event, pfds);
    UsbFnMemFree(pfds);
    return 0;
}

static int32_t UsbFnAdapterRequestGetStatus(int32_t ep, const struct IoData *ioData)
{
    if (ep <= 0 || ioData == NULL) {
        return HDF_ERR_INVALID_PARAM;
    }
    return ioctl(ep, FUNCTIONFS_ENDPOINT_GET_REQ_STATUS, ioData);
}

void *UsbFnMemAlloc(size_t size)
{
    return UsbFnMemCalloc(size);
}

void *UsbFnMemCalloc(size_t size)
{
    void *buf = OsalMemCalloc(size);
    if (buf == NULL) {
        HDF_LOGE("%{public}s: %{public}d, OsalMemCalloc failed", __func__, __LINE__);
        return NULL;
    }

    return buf;
}

void UsbFnMemFree(const void *mem)
{
    if (mem == NULL) {
        HDF_LOGE("%{public}s:%{public}d invalid param mem.", __func__, __LINE__);
        return;
    }

    if (mem != NULL) {
        OsalMemFree((void *)mem);
        mem = NULL;
    }
}

static struct UsbFnAdapterOps g_usbFnAdapter = {
    .createDevice = UsbFnAdapterCreateDevice,
    .delDevice = UsbFnAdapterDelDevice,

    .openPipe = UsbFnAdapterOpenPipe,
    .closePipe = UsbFnAdapterClosePipe,
    .getPipeInfo = UsbFnAdapterGetPipeInfo,

    .queueInit = UsbFnAdapterQueueInit,
    .queueDel = UsbFnAdapterQueueDel,
    .releaseBuf = UsbFnAdapterReleaseBuf,
    .pipeIo = UsbFnAdapterPipeIo,
    .cancelIo = UsbFnAdapterCancelIo,
    .getReqStatus = UsbFnAdapterRequestGetStatus,
    .mapAddr = UsbFnAdapterMapAddr,
    .unmapAddr = UsbFnAdapterUnmapAddr,
    .pollEvent = UsbFnAdapterPollEvent,
    .writeUDC = UsbFnAdapterWriteUDC,
    .writeProp = UsbFnWriteProp,
    .writeDesString = UsbFnWriteDesString,
};

struct UsbFnAdapterOps *UsbFnAdapterGetOps(void)
{
    return &g_usbFnAdapter;
}