/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2026-present Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** USBX Component                                                        */
/**                                                                       */
/**   Host Stack                                                          */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/


/* Include necessary system files.  */

#define UX_SOURCE_CODE

#include "ux_api.h"
#include "ux_host_stack.h"


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _ux_host_stack_hcd_unregister                       PORTABLE C      */
/*                                                           6.1.2        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Chaoqiong Xiao, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function unregisters a USB host controller driver (HCD) with   */
/*    the USBX stack, removes all devices rooted from that controller and */
/*    disable/stop the controller.                                        */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    hcd_name                              Name of HCD to unregister     */
/*    hcd_param1                            Parameter 1 of HCD            */
/*    hcd_param2                            Parameter 2 of HCD            */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Completion Status                                                   */
/*    UX_SUCCESS                            HCD unregistered, related     */
/*                                          devices removed and hardware  */
/*                                          disabled/stopped success      */
/*    UX_ERROR                              HCD not found                 */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _ux_utility_string_length_check       Check and return C string     */
/*                                          length if no error            */
/*    _ux_utility_memory_compare            Memory compare                */
/*    (ux_hcd_entry_function)               HCD dispatch entry function   */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application                                                         */
/*                                                                        */
/**************************************************************************/
UINT  _ux_host_stack_hcd_unregister(UCHAR *hcd_name,
                                    ULONG hcd_param1, ULONG hcd_param2)
{

UINT        status;
UX_DEVICE   *device;
UX_HCD      *hcd;
#if UX_MAX_CLASS_DRIVER > 1 || UX_MAX_DEVICES > 1
ULONG       scan_index;
#endif
#if !defined(UX_NAME_REFERENCED_BY_POINTER)
UINT        hcd_name_length =  0;
#endif


    /* If trace is enabled, insert this event into the trace buffer.  */
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_HCD_UNREGISTER, hcd_name, hcd_param1, hcd_param2, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)

#if !defined(UX_NAME_REFERENCED_BY_POINTER)
    /* Get the length of the class name (exclude null-terminator).  */
    status =  _ux_utility_string_length_check(hcd_name,
                                    &hcd_name_length, UX_MAX_HCD_NAME_LENGTH);
    if (status)
        return(status);
#endif

    /* Get first HCD.  */
    hcd =  _ux_system_host -> ux_system_host_hcd_array;

    /* Default to not found status.  */
    status = UX_FALSE;

#if UX_MAX_CLASS_DRIVER > 1
    /* We need to parse the controller driver table to find an empty spot.  */
    for (scan_index = 0;
         scan_index < UX_SYSTEM_HOST_MAX_HCD_GET();
         scan_index++)
    {
#endif

        /* Is this slot available and saved hcd_parameters match?  */
        if (hcd -> ux_hcd_status != UX_UNUSED &&
            hcd -> ux_hcd_io == hcd_param1 &&
            hcd -> ux_hcd_irq == hcd_param2)
        {


            /* Yes, compare the name (with null terminator).  */
            status = ux_utility_name_match(hcd -> ux_hcd_name,
                                            hcd_name, hcd_name_length + 1);
#if UX_MAX_CLASS_DRIVER > 1

            /* Break if name match (found HCD).  */
            if (status == UX_TRUE)
                break;
#endif
         }

#if UX_MAX_CLASS_DRIVER > 1
        /* Try the next HCD structure */
        hcd ++;
    }
#endif

    /* No valid HCD found.  */
    if (status != UX_TRUE)
        return(UX_ERROR);

    /* Stop USB host low-level.  */
    hcd -> ux_hcd_entry_function(hcd, UX_HCD_DISABLE_PORT, UX_NULL);

    /* Now disable controller.  */
    hcd -> ux_hcd_entry_function(hcd, UX_HCD_UNINITIALIZE, UX_NULL);

    /* Get first device.  */
    device = _ux_system_host -> ux_system_host_device_array;

#if UX_MAX_DEVICES > 1
    /* Remove all devices connected to the controller.  */
    for (scan_index = 0;
         scan_index < _ux_system_host -> ux_system_host_max_devices;
         scan_index ++)
    {
#else

        /* No device.  */
        if (device -> ux_device_handle == UX_UNUSED)
            return(UX_SUCCESS);
#endif

        /* Is this device on the HCD root hub?  */
        if (UX_DEVICE_HCD_MATCH(device, hcd) &&
            UX_DEVICE_PARENT_IS_ROOTHUB(device))
        {

            /* Remove the device (and downstream things connected to it).  */
            _ux_host_stack_device_remove(hcd, UX_DEVICE_PARENT_GET(device),
                                         UX_DEVICE_PORT_LOCATION_GET(device));

            /* The device has been removed, so the port is free again.  */
            hcd -> ux_hcd_rh_device_connection &= (ULONG)
                                    ~(1 << device -> ux_device_port_location);
        }

#if UX_MAX_DEVICES > 1

        /* Try the next device.  */
        device ++;
    }
#endif

    /* And we have one new controller unregistered.  */
    _ux_system_host -> ux_system_host_registered_hcd --;

    return(UX_SUCCESS);
}


/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _uxe_host_stack_hcd_unregister                      PORTABLE C      */
/*                                                           6.3.0        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Chaoqiong Xiao, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function checks errors in host stack HCD unregister function   */
/*    call.                                                               */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    hcd_name                              Name of HCD to unregister     */
/*    hcd_param1                            Parameter 1 of HCD            */
/*    hcd_param2                            Parameter 2 of HCD            */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    None                                                                */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _ux_host_stack_hcd_unregister         HCD unregister                */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application                                                         */
/*                                                                        */
/**************************************************************************/
UINT  _uxe_host_stack_hcd_unregister(UCHAR *hcd_name,
                                    ULONG hcd_param1, ULONG hcd_param2)
{

    /* Sanity check.  */
    if (hcd_name == UX_NULL)
        return(UX_INVALID_PARAMETER);

    /* Invoke HCD unregister function.  */
    return(_ux_host_stack_hcd_unregister(hcd_name, hcd_param1, hcd_param2));
}
