/*

 * Copyright (c) 2025 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.

 */



#ifndef HDC_USBFFS_H

#define HDC_USBFFS_H

// clang-format off

#include <linux/usb/functionfs.h>

#include <linux/types.h>

#include <endian.h>

// clang-format on



namespace OHOS {

constexpr auto HDC_CLASS = 0xff;

constexpr auto HDC_SUBCLASS = 0x50;

constexpr auto HDC_FSPKT_SIZE_MAX = 64;

constexpr auto HDC_HSPKT_SIZE_MAX = 512;

constexpr uint16_t HDC_SSPKT_SIZE_MAX = 1024;

constexpr auto PROPERTY_NAME_LENGTH = 20;

constexpr auto PROPERTY_DATA_LENGTH = 39;

constexpr uint16_t VER_PROTOCOL = 0x01;



#define SHORT_LE(x) htole16(x)

#define LONG_LE(x) htole32(x)

#define HDC_INTERFACE_NAME "UsbTestDevice"



struct UsbFunctionDesc {

    struct usb_interface_descriptor ifDesc;

    struct usb_endpoint_descriptor_no_audio from;

    struct usb_endpoint_descriptor_no_audio to;

} __attribute__((packed));



static const struct {

    struct usb_functionfs_strings_head head;

    struct {

        __le16 code;

        const char name[sizeof(HDC_INTERFACE_NAME)];

    } __attribute__((packed)) firstItem;

} __attribute__((packed)) USB_FFS_VALUE = {

    .head =

        {

            .magic = LONG_LE(FUNCTIONFS_STRINGS_MAGIC),

            .length = LONG_LE(sizeof(USB_FFS_VALUE)),

            .str_count = LONG_LE(1),

            .lang_count = LONG_LE(1),

        },

    .firstItem =

        {

            SHORT_LE(0x0409),

            HDC_INTERFACE_NAME,

        },

};



struct UsbFunctionfsDescsHeadOld {

    __le32 magic;

    __le32 length;

    __le32 config1Count;

    __le32 config2Count;

} __attribute__((packed));



struct UsbFuncConfig {

    struct usb_interface_descriptor ifDesc;

    struct usb_endpoint_descriptor_no_audio from;

    struct usb_ss_ep_comp_descriptor pairFrom;

    struct usb_endpoint_descriptor_no_audio to;

    struct usb_ss_ep_comp_descriptor pairTo;

} __attribute__((packed));



static struct UsbFuncConfig config3 = {

    .ifDesc = {

        .bLength = sizeof(config3.ifDesc),

        .bDescriptorType = USB_DT_INTERFACE,

        .bInterfaceNumber = 0,

        .bNumEndpoints = 2,

        .bInterfaceClass = HDC_CLASS,

        .bInterfaceSubClass = HDC_SUBCLASS,

        .bInterfaceProtocol = VER_PROTOCOL,

        .iInterface = 1

    },

    .from = {

        .bLength = sizeof(config3.from),

        .bDescriptorType = USB_DT_ENDPOINT,

        .bEndpointAddress = 1 | USB_DIR_OUT,

        .bmAttributes = USB_ENDPOINT_XFER_BULK,

        .wMaxPacketSize = HDC_SSPKT_SIZE_MAX,

    },

    .pairFrom = {

        .bLength = sizeof(config3.pairFrom),

        .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,

        .bMaxBurst = 4,

    },

    .to = {

        .bLength = sizeof(config3.to),

        .bDescriptorType = USB_DT_ENDPOINT,

        .bEndpointAddress = 2 | USB_DIR_IN,

        .bmAttributes = USB_ENDPOINT_XFER_BULK,

        .wMaxPacketSize = HDC_SSPKT_SIZE_MAX,

    },

    .pairTo = {

        .bLength = sizeof(config3.pairTo),

        .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,

        .bMaxBurst = 4,

    },

};



static struct UsbFunctionDesc config1 = {

    .ifDesc = {

        .bLength = sizeof(config1.ifDesc),

        .bDescriptorType = USB_DT_INTERFACE,

        .bInterfaceNumber = 0,

        .bNumEndpoints = 2,

        .bInterfaceClass = HDC_CLASS,

        .bInterfaceSubClass = HDC_SUBCLASS,

        .bInterfaceProtocol = VER_PROTOCOL,

        .iInterface = 1

    },

    .from = {

        .bLength = sizeof(config1.from),

        .bDescriptorType = USB_DT_ENDPOINT,

        .bEndpointAddress = 1 | USB_DIR_OUT,

        .bmAttributes = USB_ENDPOINT_XFER_BULK,

        .wMaxPacketSize = HDC_FSPKT_SIZE_MAX,

    },

    .to = {

        .bLength = sizeof(config1.to),

        .bDescriptorType = USB_DT_ENDPOINT,

        .bEndpointAddress = 2 | USB_DIR_IN,

        .bmAttributes = USB_ENDPOINT_XFER_BULK,

        .wMaxPacketSize = HDC_FSPKT_SIZE_MAX,

    },

};



static struct UsbFunctionDesc config2 = {

    .ifDesc = {

        .bLength = sizeof(config2.ifDesc),

        .bDescriptorType = USB_DT_INTERFACE,

        .bInterfaceNumber = 0,

        .bNumEndpoints = 2,

        .bInterfaceClass = HDC_CLASS,

        .bInterfaceSubClass = HDC_SUBCLASS,

        .bInterfaceProtocol = VER_PROTOCOL,

        .iInterface = 1

    },

    .from = {

        .bLength = sizeof(config2.from),

        .bDescriptorType = USB_DT_ENDPOINT,

        .bEndpointAddress = 1 | USB_DIR_OUT,

        .bmAttributes = USB_ENDPOINT_XFER_BULK,

        .wMaxPacketSize = HDC_HSPKT_SIZE_MAX,

    },

    .to = {

        .bLength = sizeof(config2.to),

        .bDescriptorType = USB_DT_ENDPOINT,

        .bEndpointAddress = 2 | USB_DIR_IN,

        .bmAttributes = USB_ENDPOINT_XFER_BULK,

        .wMaxPacketSize = HDC_HSPKT_SIZE_MAX,

    },

};



template <size_t PropertyNameLength, size_t PropertyDataLength>

struct UsbOsDescExtProp {

    uint32_t size = sizeof(*this);

    uint32_t propertyDataTypen = LONG_LE(1);

    uint16_t propertyNameLength = SHORT_LE(PropertyNameLength);

    char propertyName [PropertyNameLength];

    uint32_t propertyDataLength = LONG_LE(PropertyDataLength);

    char property [PropertyDataLength];

} __attribute__((packed));



using UsbOsDescGuid = UsbOsDescExtProp<PROPERTY_NAME_LENGTH, PROPERTY_DATA_LENGTH>;

UsbOsDescGuid g_osDescGuid = {

    .propertyName = "DeviceInterfaceGUID",

    .property = "{f21cc96b-063d-52e1-e3fd-f39cc7a34c40}",

};



struct UsbExtPropValues {

    UsbOsDescGuid guid;

} __attribute__((packed));



UsbExtPropValues g_osPropValues = {

    .guid = g_osDescGuid,

};



struct usb_ext_compat_desc g_wosDesc = {

    .bFirstInterfaceNumber = 0,

    .Reserved1 = LONG_LE(1),

    .CompatibleID = {'W', 'I', 'N', 'U', 'S', 'B', '\0', '\0'},

    .SubCompatibleID = { 0 },

    .Reserved2 = { 0 },

};



struct usb_os_desc_header g_wosHead = {

    .interface = LONG_LE(0),

    .dwLength = LONG_LE(sizeof(g_wosHead) + sizeof(g_wosDesc)),

    .bcdVersion = LONG_LE(1),

    .wIndex = LONG_LE(4),

    .bCount = LONG_LE(1),

    .Reserved = LONG_LE(0),

};



struct usb_os_desc_header g_osPropHead = {

    .interface = LONG_LE(0),

    .dwLength = LONG_LE(sizeof(g_wosHead) + sizeof(g_osPropValues)),

    .bcdVersion = LONG_LE(1),

    .wIndex = LONG_LE(5),

    .wCount = SHORT_LE(1),

};



struct UsbFunctionfsDescV2 {

    struct usb_functionfs_descs_head_v2 head;

    __le32 config1Count;

    __le32 config2Count;

    __le32 config3Count;

    __le32 configWosCount;

    struct UsbFunctionDesc config1Desc, config2Desc;

    struct UsbFuncConfig config3Desc;

    struct usb_os_desc_header wosHead;

    struct usb_ext_compat_desc wosDesc;

    struct usb_os_desc_header osPropHead;

    struct UsbExtPropValues osPropValues;

} __attribute__((packed));



}  // namespace OHOS

#endif