/*
 * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
 * Copyright 2016 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"

#include "usb_device_class.h"

#if ((defined(USB_DEVICE_CONFIG_VIDEO)) && (USB_DEVICE_CONFIG_VIDEO > 0U))
#include "usb_device_video.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

static usb_status_t USB_DeviceVideoAllocateHandle(usb_device_video_struct_t **handle);
static usb_status_t USB_DeviceVideoFreeHandle(usb_device_video_struct_t *handle);
static usb_status_t USB_DeviceVideoControlIn(usb_device_handle handle,
                                             usb_device_endpoint_callback_message_struct_t *message,
                                             void *callbackParam);
static usb_status_t USB_DeviceVideoStreamIn(usb_device_handle handle,
                                            usb_device_endpoint_callback_message_struct_t *message,
                                            void *callbackParam);
static usb_status_t USB_DeviceVideoStreamOut(usb_device_handle handle,
                                             usb_device_endpoint_callback_message_struct_t *message,
                                             void *callbackParam);
static usb_status_t USB_DeviceVideoStreamEndpointsInit(usb_device_video_struct_t *videoHandle);
static usb_status_t USB_DeviceVideoStreamEndpointsDeinit(usb_device_video_struct_t *videoHandle);
static usb_status_t USB_DeviceVideoControlEndpointsInit(usb_device_video_struct_t *videoHandle);
static usb_status_t USB_DeviceVideoControlEndpointsDeinit(usb_device_video_struct_t *videoHandle);

static usb_status_t USB_DeviceVideoVcPowerModeControl(usb_device_video_struct_t *videoHandle,
                                                      usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVcInterfaceRequest(usb_device_video_struct_t *videoHandle,
                                                      usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVcCameraTerminalRequest(usb_device_video_struct_t *videoHandle,
                                                           usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVcProcessingUnitRequest(usb_device_video_struct_t *videoHandle,
                                                           usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVcRequest(usb_device_video_struct_t *videoHandle,
                                             usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVsProbeRequest(usb_device_video_struct_t *videoHandle,
                                                  usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVsCommitRequest(usb_device_video_struct_t *videoHandle,
                                                   usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVsStillProbeRequest(usb_device_video_struct_t *videoHandle,
                                                       usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVsStillCommitRequest(usb_device_video_struct_t *videoHandle,
                                                        usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVsStillImageTriggerRequest(usb_device_video_struct_t *videoHandle,
                                                              usb_device_control_request_struct_t *controlRequest);
static usb_status_t USB_DeviceVideoVsRequest(usb_device_video_struct_t *videoHandle,
                                             usb_device_control_request_struct_t *controlRequest);

/*******************************************************************************
 * Variables
 ******************************************************************************/

USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_video_struct_t
    s_UsbDeviceVideoHandle[USB_DEVICE_CONFIG_VIDEO];

/*******************************************************************************
 * Code
 ******************************************************************************/

/*!
 * @brief Allocate a device video class handle.
 *
 * This function allocates a device video class handle.
 *
 * @param handle          It is out parameter, is used to return pointer of the device video class handle to the caller.
 *
 * @retval kStatus_USB_Success              Get a device video class handle successfully.
 * @retval kStatus_USB_Busy                 Cannot allocate a device video class handle.
 */
static usb_status_t USB_DeviceVideoAllocateHandle(usb_device_video_struct_t **handle)
{
    uint32_t count;
    OSA_SR_ALLOC();

    OSA_ENTER_CRITICAL();
    for (count = 0U; count < USB_DEVICE_CONFIG_VIDEO; count++)
    {
        if (NULL == s_UsbDeviceVideoHandle[count].handle)
        {
            *handle = &s_UsbDeviceVideoHandle[count];
            OSA_EXIT_CRITICAL();
            return kStatus_USB_Success;
        }
    }
    OSA_EXIT_CRITICAL();
    return kStatus_USB_Busy;
}

/*!
 * @brief Free a device video class handle.
 *
 * This function frees a device video class handle.
 *
 * @param handle          The device video class handle.
 *
 * @retval kStatus_USB_Success              Free device video class handle successfully.
 */
static usb_status_t USB_DeviceVideoFreeHandle(usb_device_video_struct_t *handle)
{
    OSA_SR_ALLOC();

    OSA_ENTER_CRITICAL();
    handle->handle           = NULL;
    handle->configStruct     = (usb_device_class_config_struct_t *)NULL;
    handle->configuration    = 0U;
    handle->controlAlternate = 0U;
    handle->streamAlternate  = 0U;
    OSA_EXIT_CRITICAL();
    return kStatus_USB_Success;
}

/*!
 * @brief Interrupt IN endpoint callback function.
 *
 * This callback function is used to notify uplayer the transfser result of a transfer.
 * This callback pointer is passed when the interrupt IN pipe initialized.
 *
 * @param handle          The device handle. It equals the value returned from USB_DeviceInit.
 * @param message         The result of the interrupt IN pipe transfer.
 * @param callbackParam  The parameter for this callback. It is same with
 * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the video class handle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoControlIn(usb_device_handle handle,
                                             usb_device_endpoint_callback_message_struct_t *message,
                                             void *callbackParam)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error = kStatus_USB_Error;

    /* Get the video class handle */
    videoHandle = (usb_device_video_struct_t *)callbackParam;

    if (NULL == videoHandle)
    {
        return kStatus_USB_InvalidHandle;
    }

    if ((NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* Notify the application control data sent by calling the video class callback.
        ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        error = videoHandle->configStruct->classCallback((class_handle_t)videoHandle,
                                                         kUSB_DeviceVideoEventControlSendResponse, message);
    }

    return error;
}

/*!
 * @brief ISO IN endpoint callback function.
 *
 * This callback function is used to notify uplayer the transfser result of a transfer.
 * This callback pointer is passed when the ISO IN pipe initialized.
 *
 * @param handle          The device handle. It equals the value returned from USB_DeviceInit.
 * @param message         The result of the ISO IN pipe transfer.
 * @param callbackParam  The parameter for this callback. It is same with
 * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the video class handle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoStreamIn(usb_device_handle handle,
                                            usb_device_endpoint_callback_message_struct_t *message,
                                            void *callbackParam)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error = kStatus_USB_Error;

    /* Get the video class handle */
    videoHandle = (usb_device_video_struct_t *)callbackParam;

    if (NULL == videoHandle)
    {
        return kStatus_USB_InvalidHandle;
    }
    videoHandle->streamInPipeBusy = 0U;
    if ((NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* Notify the application stream data sent by calling the video class callback.
        ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        error = videoHandle->configStruct->classCallback((class_handle_t)videoHandle,
                                                         kUSB_DeviceVideoEventStreamSendResponse, message);
    }

    return error;
}

/*!
 * @brief ISO OUT endpoint callback function.
 *
 * This callback function is used to notify uplayer the transfser result of a transfer.
 * This callback pointer is passed when the ISO OUT pipe initialized.
 *
 * @param handle          The device handle. It equals the value returned from USB_DeviceInit.
 * @param message         The result of the ISO OUT pipe transfer.
 * @param callbackParam  The parameter for this callback. It is same with
 * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the video class handle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoStreamOut(usb_device_handle handle,
                                             usb_device_endpoint_callback_message_struct_t *message,
                                             void *callbackParam)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error = kStatus_USB_Error;

    /* Get the video class handle */
    videoHandle = (usb_device_video_struct_t *)callbackParam;

    if (NULL == videoHandle)
    {
        return kStatus_USB_InvalidHandle;
    }
    videoHandle->streamOutPipeBusy = 0U;
    if ((NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* Notify the application stream data sent by calling the video class callback.
        ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        error = videoHandle->configStruct->classCallback((class_handle_t)videoHandle,
                                                         kUSB_DeviceVideoEventStreamRecvResponse, message);
    }

    return error;
}

/*!
 * @brief Initialize the stream endpoints of the video class.
 *
 * This callback function is used to initialize the stream endpoints of the video class.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoStreamEndpointsInit(usb_device_video_struct_t *videoHandle)
{
    usb_device_interface_list_t *interfaceList;
    usb_device_interface_struct_t *interface = (usb_device_interface_struct_t *)NULL;
    usb_status_t status                      = kStatus_USB_Error;

    /* Check the configuration is valid or not. */
    if (0U == videoHandle->configuration)
    {
        return status;
    }

    if (videoHandle->configuration > videoHandle->configStruct->classInfomation->configurations)
    {
        return status;
    }

    /* Get the interface list of the new configuration. */
    if (NULL == videoHandle->configStruct->classInfomation->interfaceList)
    {
        return status;
    }
    interfaceList = &videoHandle->configStruct->classInfomation->interfaceList[videoHandle->configuration - 1U];

    /* Find stream interface by using the alternate setting of the interface. */
    for (uint32_t count = 0U; count < interfaceList->count; count++)
    {
        if ((USB_DEVICE_VIDEO_CC_VIDEO == interfaceList->interfaces[count].classCode) &&
            (USB_DEVICE_VIDEO_SC_VIDEOSTREAMING == interfaceList->interfaces[count].subclassCode))
        {
            for (uint32_t index = 0U; index < interfaceList->interfaces[count].count; index++)
            {
                if (interfaceList->interfaces[count].interface[index].alternateSetting == videoHandle->streamAlternate)
                {
                    interface = &interfaceList->interfaces[count].interface[index];
                    break;
                }
            }
            videoHandle->streamInterfaceNumber = interfaceList->interfaces[count].interfaceNumber;
            break;
        }
    }
    if (NULL == interface)
    {
        /* Return status if the stream interface is not found. */
        return status;
    }

    /* Keep new stream interface handle. */
    videoHandle->streamInterfaceHandle = interface;

    /* Initialize the endpoints of the new interface. */
    for (uint32_t count = 0U; count < interface->endpointList.count; count++)
    {
        usb_device_endpoint_init_struct_t epInitStruct;
        usb_device_endpoint_callback_struct_t epCallback;
        epInitStruct.zlt             = 0U;
        epInitStruct.interval        = interface->endpointList.endpoint[count].interval;
        epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
        epInitStruct.maxPacketSize   = interface->endpointList.endpoint[count].maxPacketSize;
        epInitStruct.transferType    = interface->endpointList.endpoint[count].transferType;

        if ((USB_ENDPOINT_ISOCHRONOUS == (epInitStruct.transferType & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK)) &&
            (USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
                        USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)))
        {
            epCallback.callbackFn = USB_DeviceVideoStreamIn;
        }
        else if ((USB_ENDPOINT_ISOCHRONOUS ==
                  (epInitStruct.transferType & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK)) &&
                 (USB_OUT == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
                              USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)))
        {
            epCallback.callbackFn = USB_DeviceVideoStreamOut;
        }
        else
        {
            continue;
        }
        epCallback.callbackParam = videoHandle;

        status = USB_DeviceInitEndpoint(videoHandle->handle, &epInitStruct, &epCallback);
    }
    return status;
}

/*!
 * @brief De-initialize the stream endpoints of the video class.
 *
 * This callback function is used to de-initialize the stream endpoints of the video class.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoStreamEndpointsDeinit(usb_device_video_struct_t *videoHandle)
{
    usb_status_t status = kStatus_USB_Error;

    if (NULL == videoHandle->streamInterfaceHandle)
    {
        return status;
    }
    /* De-initialize all stream endpoints of the interface */
    for (uint32_t count = 0U; count < videoHandle->streamInterfaceHandle->endpointList.count; count++)
    {
        status = USB_DeviceDeinitEndpoint(
            videoHandle->handle, videoHandle->streamInterfaceHandle->endpointList.endpoint[count].endpointAddress);
    }
    videoHandle->streamInterfaceHandle = NULL;
    return status;
}

/*!
 * @brief Initialize the control endpoints of the video class.
 *
 * This callback function is used to initialize the control endpoints of the video class.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoControlEndpointsInit(usb_device_video_struct_t *videoHandle)
{
    usb_device_interface_list_t *interfaceList;
    usb_device_interface_struct_t *interface = (usb_device_interface_struct_t *)NULL;
    usb_status_t status                      = kStatus_USB_Error;

    /* Check the configuration is valid or not. */
    if (0U == videoHandle->configuration)
    {
        return status;
    }

    if (videoHandle->configuration > videoHandle->configStruct->classInfomation->configurations)
    {
        return status;
    }

    /* Get the control interface list of the new configuration. */
    if (NULL == videoHandle->configStruct->classInfomation->interfaceList)
    {
        return status;
    }
    interfaceList = &videoHandle->configStruct->classInfomation->interfaceList[videoHandle->configuration - 1U];

    /* Find control interface by using the alternate setting of the interface. */
    for (uint32_t count = 0U; count < interfaceList->count; count++)
    {
        if ((USB_DEVICE_VIDEO_CC_VIDEO == interfaceList->interfaces[count].classCode) &&
            (USB_DEVICE_VIDEO_SC_VIDEOCONTROL == interfaceList->interfaces[count].subclassCode))
        {
            for (uint32_t index = 0U; index < interfaceList->interfaces[count].count; index++)
            {
                if (interfaceList->interfaces[count].interface[index].alternateSetting == videoHandle->controlAlternate)
                {
                    interface = &interfaceList->interfaces[count].interface[index];
                    break;
                }
            }
            videoHandle->controlInterfaceNumber = interfaceList->interfaces[count].interfaceNumber;
            break;
        }
    }
    if (NULL == interface)
    {
        /* Return status if the control interface is not found. */
        return status;
    }
    /* Keep new control interface handle. */
    videoHandle->controlInterfaceHandle = interface;

    /* Initialize the control endpoints of the new interface. */
    for (uint32_t count = 0U; count < interface->endpointList.count; count++)
    {
        usb_device_endpoint_init_struct_t epInitStruct;
        usb_device_endpoint_callback_struct_t epCallback;
        epInitStruct.zlt             = 0U;
        epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
        epInitStruct.maxPacketSize   = interface->endpointList.endpoint[count].maxPacketSize;
        epInitStruct.transferType    = interface->endpointList.endpoint[count].transferType;

        if ((USB_ENDPOINT_INTERRUPT == (epInitStruct.transferType & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK)) &&
            (USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
                        USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)))
        {
            epCallback.callbackFn = USB_DeviceVideoControlIn;
        }
        else
        {
            continue;
        }
        epCallback.callbackParam = videoHandle;

        status = USB_DeviceInitEndpoint(videoHandle->handle, &epInitStruct, &epCallback);
    }
    return status;
}

/*!
 * @brief De-initialize the control endpoints of the video class.
 *
 * This callback function is used to de-initialize the control endpoints of the video class.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoControlEndpointsDeinit(usb_device_video_struct_t *videoHandle)
{
    usb_status_t status = kStatus_USB_Error;

    if (NULL == videoHandle->controlInterfaceHandle)
    {
        return status;
    }
    /* De-initialize all control endpoints of the interface */
    for (uint32_t count = 0U; count < videoHandle->controlInterfaceHandle->endpointList.count; count++)
    {
        status = USB_DeviceDeinitEndpoint(
            videoHandle->handle, videoHandle->controlInterfaceHandle->endpointList.endpoint[count].endpointAddress);
    }
    videoHandle->controlInterfaceHandle = NULL;
    return status;
}

/*!
 * @brief Handle the video device vc power modex control request.
 *
 * This callback function is used to handle the video device vc power modex control request.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVcPowerModeControl(usb_device_video_struct_t *videoHandle,
                                                      usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint32_t command    = 0U;
    uint32_t length     = 1U;

    switch (controlRequest->setup->bRequest)
    {
        case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
            command = USB_DEVICE_VIDEO_SET_CUR_VC_POWER_MODE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
            command = USB_DEVICE_VIDEO_GET_CUR_VC_POWER_MODE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
            command = USB_DEVICE_VIDEO_GET_INFO_VC_POWER_MODE_CONTROL;
            break;
        default:
            /*no action*/
            break;
    }
    if ((0U != command) && (NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        status = videoHandle->configStruct->classCallback((class_handle_t)videoHandle, command, controlRequest);
        if (controlRequest->length > length)
        {
            status = kStatus_USB_InvalidRequest;
        }
    }
    return status;
}

/*!
 * @brief Handle the video device control interface class-specific request.
 *
 * This callback function is used to handle the video device control pipe class-specific request.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVcInterfaceRequest(usb_device_video_struct_t *videoHandle,
                                                      usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint8_t cs          = (uint8_t)((controlRequest->setup->wValue >> 0x08U) & 0xFFU);

    if (USB_DEVICE_VIDEO_VC_VIDEO_POWER_MODE_CONTROL == cs)
    {
        /* handle the video device vc power modex control request */
        status = USB_DeviceVideoVcPowerModeControl(videoHandle, controlRequest);
    }
    else if (USB_DEVICE_VIDEO_VC_REQUEST_ERROR_CODE_CONTROL == cs)
    {
    }
    else
    {
        /*no action*/
    }
    return status;
}

/*!
 * @brief Handle the video device camera terminal control request.
 *
 * This callback function is used to handle the video device camera terminal control request.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVcCameraTerminalRequest(usb_device_video_struct_t *videoHandle,
                                                           usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint8_t cs          = (uint8_t)((controlRequest->setup->wValue >> 0x08U) & 0xFFU);

    switch (cs)
    {
        case USB_DEVICE_VIDEO_CT_SCANNING_MODE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_AE_MODE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_AE_PRIORITY_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_EXPOSURE_TIME_RELATIVE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_FOCUS_ABSOLUTE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_FOCUS_RELATIVE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_FOCUS_AUTO_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_IRIS_ABSOLUTE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_IRIS_RELATIVE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_ZOOM_ABSOLUTE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_ZOOM_RELATIVE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_PANTILT_ABSOLUTE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_PANTILT_RELATIVE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_ROLL_ABSOLUTE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_ROLL_RELATIVE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_PRIVACY_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_FOCUS_SIMPLE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_WINDOW_CONTROL:
            break;
        case USB_DEVICE_VIDEO_CT_REGION_OF_INTEREST_CONTROL:
            break;
        default:
            /*no action*/
            break;
    }
    return status;
}

/*!
 * @brief Handle the video device processing uint control request.
 *
 * This callback function is used to handle the video device processing uint control request.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVcProcessingUnitRequest(usb_device_video_struct_t *videoHandle,
                                                           usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint8_t cs          = (uint8_t)((controlRequest->setup->wValue >> 0x08U) & 0xFFU);

    switch (cs)
    {
        case USB_DEVICE_VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_BRIGHTNESS_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_CONTRAST_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_GAIN_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_HUE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_SATURATION_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_SHARPNESS_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_GAMMA_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_WHITE_BALANCE_COMPONENT_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_DIGITAL_MULTIPLIER_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_HUE_AUTO_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_ANALOG_VIDEO_STANDARD_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_ANALOG_LOCK_STATUS_CONTROL:
            break;
        case USB_DEVICE_VIDEO_PU_CONTRAST_AUTO_CONTROL:
            break;
        default:
            /*no action*/
            break;
    }

    return status;
}

/*!
 * @brief Handle the video device control request.
 *
 * This callback function is used to handle the video device control request,
 * including the control interface, uint or terminal control.
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVcRequest(usb_device_video_struct_t *videoHandle,
                                             usb_device_control_request_struct_t *controlRequest)
{
    usb_device_video_entities_struct_t *entity_list;
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint8_t entityId    = (uint8_t)(controlRequest->setup->wIndex >> 0x08U);

    if (NULL == videoHandle->controlInterfaceHandle)
    {
        return status;
    }

    /* Get the video class-specific information. */
    entity_list = (usb_device_video_entities_struct_t *)videoHandle->controlInterfaceHandle->classSpecific;

    if (0U == entityId)
    {
        /* Handle the video control interface request. */
        status = USB_DeviceVideoVcInterfaceRequest(videoHandle, controlRequest);
    }
    else
    {
        for (uint32_t i = 0U; i < entity_list->count; i++)
        {
            if (entityId == entity_list->entity[i].entityId)
            {
                switch (entity_list->entity[i].entityType)
                {
                    case USB_DESCRIPTOR_SUBTYPE_VIDEO_VC_INPUT_TERMINAL:
                        if (USB_DEVICE_VIDEO_ITT_CAMERA == entity_list->entity[i].terminalType)
                        {
                            /* Handle the video camera terminal control request. */
                            status = USB_DeviceVideoVcCameraTerminalRequest(videoHandle, controlRequest);
                        }
                        break;
                    case USB_DESCRIPTOR_SUBTYPE_VIDEO_VC_OUTPUT_TERMINAL:
                        break;
                    case USB_DESCRIPTOR_SUBTYPE_VIDEO_VC_SELECTOR_UNIT:
                        break;
                    case USB_DESCRIPTOR_SUBTYPE_VIDEO_VC_PROCESSING_UNIT:
                        /* Handle the video processing uint control request. */
                        status = USB_DeviceVideoVcProcessingUnitRequest(videoHandle, controlRequest);
                        break;
                    case USB_DESCRIPTOR_SUBTYPE_VIDEO_VC_EXTENSION_UNIT:
                        break;
                    case USB_DESCRIPTOR_SUBTYPE_VIDEO_VC_ENCODING_UNIT:
                        break;
                    default:
                        /*no action*/
                        break;
                }
            }
        }
    }
    return status;
}

/*!
 * @brief Handle the video device probe control request.
 *
 * This callback function is used to handle the video device probe control request,
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVsProbeRequest(usb_device_video_struct_t *videoHandle,
                                                  usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint32_t command    = 0U;
    uint32_t length     = sizeof(usb_device_video_probe_and_commit_controls_struct_t);

    switch (controlRequest->setup->bRequest)
    {
        case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
            command = USB_DEVICE_VIDEO_SET_CUR_VS_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
            command = USB_DEVICE_VIDEO_GET_CUR_VS_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MIN:
            command = USB_DEVICE_VIDEO_GET_MIN_VS_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MAX:
            command = USB_DEVICE_VIDEO_GET_MAX_VS_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_RES:
            command = USB_DEVICE_VIDEO_GET_RES_VS_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_LEN:
            command = USB_DEVICE_VIDEO_GET_LEN_VS_PROBE_CONTROL;
            length  = 1U;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
            command = USB_DEVICE_VIDEO_GET_INFO_VS_PROBE_CONTROL;
            length  = 1U;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_DEF:
            command = USB_DEVICE_VIDEO_GET_DEF_VS_PROBE_CONTROL;
            break;
        default:
            /*no action*/
            break;
    }
    if ((0U != command) && (NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /*ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
  it is from the second parameter of classInit*/
        status = videoHandle->configStruct->classCallback((class_handle_t)videoHandle, command, controlRequest);
        if (controlRequest->length > length)
        {
            status = kStatus_USB_InvalidRequest;
        }
    }
    return status;
}

/*!
 * @brief Handle the video device commit control request.
 *
 * This callback function is used to handle the video device commit control request,
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVsCommitRequest(usb_device_video_struct_t *videoHandle,
                                                   usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint32_t command    = 0U;
    uint32_t length     = sizeof(usb_device_video_probe_and_commit_controls_struct_t);

    switch (controlRequest->setup->bRequest)
    {
        case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
            command = USB_DEVICE_VIDEO_SET_CUR_VS_COMMIT_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
            command = USB_DEVICE_VIDEO_GET_CUR_VS_COMMIT_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_LEN:
            command = USB_DEVICE_VIDEO_GET_LEN_VS_COMMIT_CONTROL;
            length  = 1U;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
            command = USB_DEVICE_VIDEO_GET_INFO_VS_COMMIT_CONTROL;
            length  = 1U;
            break;
        default:
            /*no action*/
            break;
    }
    if ((0U != command) && (NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        status = videoHandle->configStruct->classCallback((class_handle_t)videoHandle, command, controlRequest);
        if (controlRequest->length > length)
        {
            status = kStatus_USB_InvalidRequest;
        }
    }
    return status;
}

/*!
 * @brief Handle the video device still probe control request.
 *
 * This callback function is used to handle the video device still probe control request,
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVsStillProbeRequest(usb_device_video_struct_t *videoHandle,
                                                       usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint32_t command    = 0U;
    uint32_t length     = sizeof(usb_device_video_still_probe_and_commit_controls_struct_t);

    switch (controlRequest->setup->bRequest)
    {
        case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
            command = USB_DEVICE_VIDEO_SET_CUR_VS_STILL_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
            command = USB_DEVICE_VIDEO_GET_CUR_VS_STILL_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MIN:
            command = USB_DEVICE_VIDEO_GET_MIN_VS_STILL_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MAX:
            command = USB_DEVICE_VIDEO_GET_MAX_VS_STILL_PROBE_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_LEN:
            command = USB_DEVICE_VIDEO_GET_LEN_VS_STILL_PROBE_CONTROL;
            length  = 1U;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
            command = USB_DEVICE_VIDEO_GET_INFO_VS_STILL_PROBE_CONTROL;
            length  = 1U;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_DEF:
            command = USB_DEVICE_VIDEO_GET_DEF_VS_STILL_PROBE_CONTROL;
            break;
        default:
            /*no action*/
            break;
    }
    if ((0U != command) && (NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /*ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
  it is from the second parameter of classInit*/
        status = videoHandle->configStruct->classCallback((class_handle_t)videoHandle, command, controlRequest);
        if (controlRequest->length > length)
        {
            status = kStatus_USB_InvalidRequest;
        }
    }
    return status;
}

/*!
 * @brief Handle the video device still commit control request.
 *
 * This callback function is used to handle the video device still commit control request,
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVsStillCommitRequest(usb_device_video_struct_t *videoHandle,
                                                        usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint32_t command    = 0U;
    uint32_t length     = sizeof(usb_device_video_still_probe_and_commit_controls_struct_t);

    switch (controlRequest->setup->bRequest)
    {
        case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
            command = USB_DEVICE_VIDEO_SET_CUR_VS_STILL_COMMIT_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
            command = USB_DEVICE_VIDEO_GET_CUR_VS_STILL_COMMIT_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_LEN:
            command = USB_DEVICE_VIDEO_GET_LEN_VS_STILL_COMMIT_CONTROL;
            length  = 1U;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
            command = USB_DEVICE_VIDEO_GET_INFO_VS_STILL_COMMIT_CONTROL;
            length  = 1U;
            break;
        default:
            /*no action*/
            break;
    }
    if ((0U != command) && (NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        status = videoHandle->configStruct->classCallback((class_handle_t)videoHandle, command, controlRequest);
        if (controlRequest->length > length)
        {
            status = kStatus_USB_InvalidRequest;
        }
    }
    return status;
}

/*!
 * @brief Handle the video device still image trigger control request.
 *
 * This callback function is used to handle the video device still image trigger control request,
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVsStillImageTriggerRequest(usb_device_video_struct_t *videoHandle,
                                                              usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint32_t command    = 0U;
    uint32_t length     = 1U;

    switch (controlRequest->setup->bRequest)
    {
        case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
            command = USB_DEVICE_VIDEO_SET_CUR_VS_STILL_IMAGE_TRIGGER_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
            command = USB_DEVICE_VIDEO_GET_CUR_VS_STILL_IMAGE_TRIGGER_CONTROL;
            break;
        case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
            command = USB_DEVICE_VIDEO_GET_INFO_VS_STILL_IMAGE_TRIGGER_CONTROL;
            break;
        default:
            /*no action*/
            break;
    }
    if ((0U != command) && (NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
    {
        /* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
        it is from the second parameter of classInit */
        status = videoHandle->configStruct->classCallback((class_handle_t)videoHandle, command, controlRequest);
        if (controlRequest->length > length)
        {
            status = kStatus_USB_InvalidRequest;
        }
    }
    return status;
}

/*!
 * @brief Handle the video device stream interface control request.
 *
 * This callback function is used to handle the video devicestream interface controll request,
 *
 * @param videoHandle          The device video class handle. It equals the value returned from
 * usb_device_class_config_struct_t::classHandle.
 * @param controlRequest       The pointer of the control request structure.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
static usb_status_t USB_DeviceVideoVsRequest(usb_device_video_struct_t *videoHandle,
                                             usb_device_control_request_struct_t *controlRequest)
{
    usb_status_t status = kStatus_USB_InvalidRequest;
    uint8_t cs          = (uint8_t)((controlRequest->setup->wValue >> 0x08U) & 0xFFU);

    switch (cs)
    {
        case USB_DEVICE_VIDEO_VS_PROBE_CONTROL:
            /* Handle device video probe control request. */
            status = USB_DeviceVideoVsProbeRequest(videoHandle, controlRequest);
            break;
        case USB_DEVICE_VIDEO_VS_COMMIT_CONTROL:
            /* Handle device video commit control request. */
            status = USB_DeviceVideoVsCommitRequest(videoHandle, controlRequest);
            break;
        case USB_DEVICE_VIDEO_VS_STILL_PROBE_CONTROL:
            /* Handle device video still probe control request. */
            status = USB_DeviceVideoVsStillProbeRequest(videoHandle, controlRequest);
            break;
        case USB_DEVICE_VIDEO_VS_STILL_COMMIT_CONTROL:
            /* Handle device video still commit control request. */
            status = USB_DeviceVideoVsStillCommitRequest(videoHandle, controlRequest);
            break;
        case USB_DEVICE_VIDEO_VS_STILL_IMAGE_TRIGGER_CONTROL:
            /* Handle device video still image trigger control request. */
            status = USB_DeviceVideoVsStillImageTriggerRequest(videoHandle, controlRequest);
            break;
        case USB_DEVICE_VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
            break;
        case USB_DEVICE_VIDEO_VS_GENERATE_KEY_FRAME_CONTROL:
            break;
        case USB_DEVICE_VIDEO_VS_UPDATE_FRAME_SEGMENT_CONTROL:
            break;
        case USB_DEVICE_VIDEO_VS_SYNCH_DELAY_CONTROL:
            break;
        default:
            /*no action*/
            break;
    }

    return status;
}

/*!
 * @brief Handle the event passed to the video class.
 *
 * This function handles the event passed to the video class.
 *
 * @param handle          The video class handle, got from the usb_device_class_config_struct_t::classHandle.
 * @param event           The event codes. Please refer to the enumeration usb_device_class_event_t.
 * @param param           The param type is determined by the event code.
 *
 * @return A USB error code or kStatus_USB_Success.
 * @retval kStatus_USB_Success              Free device handle successfully.
 * @retval kStatus_USB_InvalidParameter     The device handle not be found.
 * @retval kStatus_USB_InvalidRequest       The request is invalid, and the control pipe will be stalled by the caller.
 */
usb_status_t USB_DeviceVideoEvent(void *handle, uint32_t event, void *param)
{
    usb_device_video_struct_t *videoHandle;
    ;
    usb_status_t error = kStatus_USB_Error;
    uint16_t interfaceAlternate;
    uint8_t *temp8;
    uint8_t alternate;
    usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
    if ((NULL == param) || (NULL == handle))
    {
        return kStatus_USB_InvalidHandle;
    }

    /* Get the video class handle. */
    videoHandle = (usb_device_video_struct_t *)handle;

    switch (eventCode)
    {
        case kUSB_DeviceClassEventDeviceReset:
            /* Bus reset, clear the configuration. */
            videoHandle->configuration     = 0U;
            videoHandle->streamOutPipeBusy = 0U;
            videoHandle->streamInPipeBusy  = 0U;
            error                          = kStatus_USB_Success;
            break;
        case kUSB_DeviceClassEventSetConfiguration:
            /* Get the new configuration. */
            temp8 = ((uint8_t *)param);
            if (NULL == videoHandle->configStruct)
            {
                break;
            }
            if (*temp8 == videoHandle->configuration)
            {
                error = kStatus_USB_Success;
                break;
            }
            /* De-initialize the endpoints when current configuration is none zero. */
            if (0U != videoHandle->configuration)
            {
                (void)USB_DeviceVideoControlEndpointsDeinit(videoHandle);
                (void)USB_DeviceVideoStreamEndpointsDeinit(videoHandle);
            }
            /* Save new configuration. */
            videoHandle->configuration = *temp8;
            /* Clear the alternate setting value. */
            videoHandle->controlAlternate = 0U;
            /* Clear the alternate setting value. */
            videoHandle->streamAlternate        = 0U;
            videoHandle->controlInterfaceHandle = NULL;
            videoHandle->streamInterfaceHandle  = NULL;
            /* Initialize the control endpoints of the new current configuration by using the alternate setting 0. */
            error = USB_DeviceVideoControlEndpointsInit(videoHandle);
            /*for cvoerity unused value*/
            if (kStatus_USB_Success != error)
            {
#ifdef DEBUG
                usb_echo("kUSB_DeviceClassEventSetConfiguration, USB_DeviceInitEndpoint fail\r\n");
#endif
            }
            /* Initialize the stream endpoints of the new current configuration by using the alternate setting 0. */
            error = USB_DeviceVideoStreamEndpointsInit(videoHandle);
            break;
        case kUSB_DeviceClassEventSetInterface:
            if (NULL == videoHandle->configStruct)
            {
                break;
            }
            /* Get the new alternate setting of the interface */
            interfaceAlternate = *((uint16_t *)param);
            /* Get the alternate setting value */
            alternate = (uint8_t)(interfaceAlternate & 0xFFU);

            /* Whether the interface belongs to the class. */
            if (videoHandle->controlInterfaceNumber == ((uint8_t)(interfaceAlternate >> 8U)))
            {
                /* When the interface is control interface. */
                /* Only handle new alternate setting. */
                if (alternate == videoHandle->controlAlternate)
                {
                    error = kStatus_USB_Success;
                    break;
                }
                /* De-initialize old endpoints */
                (void)USB_DeviceVideoControlEndpointsDeinit(videoHandle);
                videoHandle->controlAlternate = alternate;
                /* Initialize new endpoints */
                error = USB_DeviceVideoControlEndpointsInit(videoHandle);
            }
            else if (videoHandle->streamInterfaceNumber == ((uint8_t)(interfaceAlternate >> 8U)))
            {
                /* When the interface is stream interface. */
                /* Only handle new alternate setting. */
                if (alternate == videoHandle->streamAlternate)
                {
                    error = kStatus_USB_Success;
                    break;
                }
                /* De-initialize old endpoints */
                error                        = USB_DeviceVideoStreamEndpointsDeinit(videoHandle);
                videoHandle->streamAlternate = alternate;
                /* Initialize new endpoints */
                error = USB_DeviceVideoStreamEndpointsInit(videoHandle);
            }
            else
            {
                /*no action*/
            }
            break;
        case kUSB_DeviceClassEventSetEndpointHalt:
            if (NULL == videoHandle->configStruct)
            {
                break;
            }
            /* Get the endpoint address */
            temp8 = ((uint8_t *)param);
            if (NULL != videoHandle->controlInterfaceHandle)
            {
                for (uint32_t count = 0U; count < videoHandle->controlInterfaceHandle->endpointList.count; count++)
                {
                    if (*temp8 == videoHandle->controlInterfaceHandle->endpointList.endpoint[count].endpointAddress)
                    {
                        /* Only stall the endpoint belongs to control interface of the class */
                        error = USB_DeviceStallEndpoint(videoHandle->handle, *temp8);
                    }
                }
            }
            if (NULL != videoHandle->streamInterfaceHandle)
            {
                for (uint32_t count = 0U; count < videoHandle->streamInterfaceHandle->endpointList.count; count++)
                {
                    if (*temp8 == videoHandle->streamInterfaceHandle->endpointList.endpoint[count].endpointAddress)
                    {
                        /* Only stall the endpoint belongs to stream interface of the class */
                        error = USB_DeviceStallEndpoint(videoHandle->handle, *temp8);
                    }
                }
            }
            break;
        case kUSB_DeviceClassEventClearEndpointHalt:
            if (NULL == videoHandle->configStruct)
            {
                break;
            }
            /* Get the endpoint address */
            temp8 = ((uint8_t *)param);
            if (NULL != videoHandle->controlInterfaceHandle)
            {
                for (uint32_t count = 0U; count < videoHandle->controlInterfaceHandle->endpointList.count; count++)
                {
                    if (*temp8 == videoHandle->controlInterfaceHandle->endpointList.endpoint[count].endpointAddress)
                    {
                        /* Only un-stall the endpoint belongs to control interface of the class */
                        error = USB_DeviceUnstallEndpoint(videoHandle->handle, *temp8);
                    }
                }
            }
            if (NULL != videoHandle->streamInterfaceHandle)
            {
                for (uint32_t count = 0U; count < videoHandle->streamInterfaceHandle->endpointList.count; count++)
                {
                    if (*temp8 == videoHandle->streamInterfaceHandle->endpointList.endpoint[count].endpointAddress)
                    {
                        /* Only un-stall the endpoint belongs to stream interface of the class */
                        error = USB_DeviceUnstallEndpoint(videoHandle->handle, *temp8);
                    }
                }
            }
            break;
        case kUSB_DeviceClassEventClassRequest:
        {
            /* Handle the video class specific request. */
            usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
            uint8_t interface_index                             = (uint8_t)controlRequest->setup->wIndex;
            uint8_t process;

            if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
                USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
            {
                break;
            }

            if ((videoHandle->controlInterfaceNumber != interface_index) &&
                (videoHandle->streamInterfaceNumber != interface_index))
            {
                break;
            }

            process = 0U;
            error   = kStatus_USB_InvalidRequest;
            switch (controlRequest->setup->bRequest)
            {
                /* Set */
                case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR:
                case USB_DEVICE_VIDEO_REQUEST_CODE_SET_CUR_ALL:
                    if (controlRequest->setup->bmRequestType == USB_DEVICE_VIDEO_SET_REQUEST_INTERFACE)
                    {
                        if (0U != controlRequest->isSetup)
                        {
                            /* Get the buffer to receive the data sent from the host. */
                            if ((NULL != videoHandle->configStruct) && (NULL != videoHandle->configStruct->classCallback))
                            {
                                /*ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
                                                  it is from the second parameter of classInit*/
                                error = videoHandle->configStruct->classCallback(
                                    (class_handle_t)videoHandle, kUSB_DeviceVideoEventClassRequestBuffer, controlRequest);
                            }
                        }
                        else
                        {
                            process = 1;
                        }
                    }
                    break;
                /* Get */
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MIN:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MAX:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_RES:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_LEN:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_INFO:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_DEF:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_CUR_ALL:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MIN_ALL:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_MAX_ALL:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_RES_ALL:
                case USB_DEVICE_VIDEO_REQUEST_CODE_GET_DEF_ALL:
                    if (controlRequest->setup->bmRequestType == USB_DEVICE_VIDEO_GET_REQUEST_INTERFACE)
                    {
                        process = 1;
                    }
                    break;
                default:
                    /* no action */
                    break;
            }
            if (process != 0U)
            {
                if (videoHandle->controlInterfaceNumber == interface_index)
                {
                    error = USB_DeviceVideoVcRequest(videoHandle, controlRequest);
                }
                else if (videoHandle->streamInterfaceNumber == interface_index)
                {
                    error = USB_DeviceVideoVsRequest(videoHandle, controlRequest);
                }
                else
                {
                    /*no action*/
                }
            }
        }
        break;
        default:
            /*no action*/
            break;
    }
    return error;
}

/*!
 * @brief Initialize the video class.
 *
 * This function is used to initialize the video class.
 *
 * @param controllerId   The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
 * @param config          The class configuration information.
 * @param handle          It is out parameter, is used to return pointer of the video class handle to the caller.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
usb_status_t USB_DeviceVideoInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error;

    /* Allocate a video class handle. */
    error = USB_DeviceVideoAllocateHandle(&videoHandle);

    if (kStatus_USB_Success != error)
    {
        return error;
    }

    /* Get the device handle according to the controller id. */
    error = USB_DeviceClassGetDeviceHandle(controllerId, &videoHandle->handle);

    if (kStatus_USB_Success != error)
    {
        return error;
    }

    if (NULL == videoHandle->handle)
    {
        return kStatus_USB_InvalidHandle;
    }
    /* Save the configuration of the class. */
    videoHandle->configStruct = config;
    /* Clear the configuration value. */
    videoHandle->configuration    = 0U;
    videoHandle->streamAlternate  = 0xffU;
    videoHandle->controlAlternate = 0xffU;

    *handle = (class_handle_t)videoHandle;
    return error;
}

/*!
 * @brief De-initialize the device video class.
 *
 * The function de-initializes the device video class.
 *
 * @param handle The ccid class handle got from usb_device_class_config_struct_t::classHandle.
 *
 * @return A USB error code or kStatus_USB_Success.
 */
usb_status_t USB_DeviceVideoDeinit(class_handle_t handle)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error;

    videoHandle = (usb_device_video_struct_t *)handle;

    if (NULL == videoHandle)
    {
        return kStatus_USB_InvalidHandle;
    }
    /* De-initialzie the stream endpoints. */
    error = USB_DeviceVideoStreamEndpointsDeinit(videoHandle);
    if (kStatus_USB_Success != error)
    {
#ifdef DEBUG
        usb_echo("USB_DeviceVideoStreamEndpointsDeinit fail\r\n");
#endif
    }
    /* De-initialzie the control endpoints. */
    (void)USB_DeviceVideoControlEndpointsDeinit(videoHandle);
    /* Free the video class handle. */
    error = USB_DeviceVideoFreeHandle(videoHandle);
    return error;
}

/*!
 * @brief Send data through a specified endpoint.
 *
 * The function is used to send data through a specified endpoint.
 * The function calls USB_DeviceSendRequest internally.
 *
 * @param handle The video class handle got from usb_device_class_config_struct_t::classHandle.
 * @param endpointAddress Endpoint index.
 * @param buffer The memory address to hold the data need to be sent.
 * @param length The data length need to be sent.
 *
 * @return A USB error code or kStatus_USB_Success.
 *
 * @note The return value just means if the sending request is successful or not; the transfer done is notified by
 * USB_DeviceVideoStreamIn or USB_DeviceVideoControlIn.
 * Currently, only one transfer request can be supported for one specific endpoint.
 * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application
 * should implement a queue in the application level.
 * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint
 * callback).
 */
usb_status_t USB_DeviceVideoSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error;

    if (NULL == handle)
    {
        return kStatus_USB_InvalidHandle;
    }
    videoHandle = (usb_device_video_struct_t *)handle;

    if (0U != videoHandle->streamInPipeBusy)
    {
        return kStatus_USB_Busy;
    }
    videoHandle->streamInPipeBusy = 1U;

    error = USB_DeviceSendRequest(videoHandle->handle, ep, buffer, length);
    if (kStatus_USB_Success != error)
    {
        videoHandle->streamInPipeBusy = 0U;
    }
    return error;
}

/*!
 * @brief Receive data through a specified endpoint.
 *
 * The function is used to receive data through a specified endpoint.
 * The function calls USB_DeviceRecvRequest internally.
 *
 * @param handle The video class handle got from usb_device_class_config_struct_t::classHandle.
 * @param endpointAddress Endpoint index.
 * @param buffer The memory address to save the received data.
 * @param length The data length want to be received.
 *
 * @return A USB error code or kStatus_USB_Success.
 *
 * @note The return value just means if the receiving request is successful or not; the transfer done is notified by
 * USB_DeviceVideoStreamOut.
 * Currently, only one transfer request can be supported for one specific endpoint.
 * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application
 * should implement a queue in the application level.
 * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint
 * callback).
 */
usb_status_t USB_DeviceVideoRecv(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
{
    usb_device_video_struct_t *videoHandle;
    usb_status_t error;

    if (NULL == handle)
    {
        return kStatus_USB_InvalidHandle;
    }
    videoHandle = (usb_device_video_struct_t *)handle;

    if (0U != videoHandle->streamOutPipeBusy)
    {
        return kStatus_USB_Busy;
    }
    videoHandle->streamOutPipeBusy = 1U;

    error = USB_DeviceRecvRequest(videoHandle->handle, ep, buffer, length);
    if (kStatus_USB_Success != error)
    {
        videoHandle->streamOutPipeBusy = 0U;
    }
    return error;
}

#endif
