/*************************************************************************** * 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_device_remove PORTABLE C */ /* 6.1.12 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function will remove a USB device from the bus. */ /* */ /* INPUT */ /* */ /* HCD Pointer to the HCD */ /* parent The parent device address */ /* port_index Index of the port on which the*/ /* change of status occurred */ /* */ /* OUTPUT */ /* */ /* Completion Status */ /* */ /* CALLS */ /* */ /* _ux_host_stack_device_resources_free Free all device resources */ /* */ /* CALLED BY */ /* */ /* USBX Components */ /* */ /**************************************************************************/ UINT _ux_host_stack_device_remove(UX_HCD *hcd, UX_DEVICE *parent, UINT port_index) { #if UX_MAX_DEVICES > 1 ULONG container_index; #endif UX_DEVICE *device; UX_CONFIGURATION *configuration; UX_INTERFACE *interface_ptr; UX_HOST_CLASS_COMMAND command; /* We need to find the device descriptor for the removed device. We can find it with the parent device and the port it was attached to. Start with the first device. */ device = _ux_system_host -> ux_system_host_device_array; #if UX_MAX_DEVICES > 1 /* Start at the beginning of the list. */ container_index = 0; /* Search the list until the end. */ while (container_index++ < _ux_system_host -> ux_system_host_max_devices) { /* Until we have found a used entry. */ if (device -> ux_device_handle != UX_UNUSED) { /* Check for the parent device and the port location and the controller. */ if( UX_DEVICE_PARENT_MATCH(device, parent) && UX_DEVICE_PORT_LOCATION_MATCH(device, port_index) && UX_DEVICE_HCD_MATCH(device, hcd)) break; } /* Move to the next device entry. */ device++; } /* Device not found. */ if (container_index > _ux_system_host -> ux_system_host_max_devices) #else UX_PARAMETER_NOT_USED(parent); UX_PARAMETER_NOT_USED(port_index); /* Device is available and HCD is expected. */ if (device -> ux_device_handle == UX_UNUSED || !UX_DEVICE_HCD_MATCH(device, hcd)) #endif { /* Error trap. */ _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DEVICE_HANDLE_UNKNOWN); /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0) /* We get here when we could not find the device. */ return(UX_DEVICE_HANDLE_UNKNOWN); } /* If trace is enabled, insert this event into the trace buffer. */ UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_DEVICE_REMOVE, hcd, parent, port_index, device, UX_TRACE_HOST_STACK_EVENTS, 0, 0) /* If trace is enabled, unregister this object. */ UX_TRACE_OBJECT_UNREGISTER(device); /* We have found the device to be removed. */ device -> ux_device_state = UX_DEVICE_REMOVED; /* We have found the device to be removed. Initialize the class command with the generic parameters. */ command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_DEACTIVATE; /* The device may have a class associated with the device container or its interfaces. */ if (device -> ux_device_class_instance != UX_NULL) { /* We need to stop the class instance for the device. */ command.ux_host_class_command_instance = device -> ux_device_class_instance; /* Call the class. */ device -> ux_device_class -> ux_host_class_entry_function(&command); } else { /* Search for the active configuration. */ configuration = device -> ux_device_current_configuration; /* If configuration is activated. */ if (configuration != UX_NULL) { /* We have the correct configuration, search the interface(s). */ interface_ptr = configuration -> ux_configuration_first_interface; /* Loop to perform the search. */ while (interface_ptr != UX_NULL) { /* Check if an instance of the interface is present. */ if (interface_ptr -> ux_interface_class_instance != UX_NULL) { /* We need to stop the class instance for the device. */ command.ux_host_class_command_instance = interface_ptr -> ux_interface_class_instance; /* Call the class. */ interface_ptr -> ux_interface_class -> ux_host_class_entry_function(&command); } /* Move to next interface. */ interface_ptr = interface_ptr -> ux_interface_next_interface; } } } /* Notify application for disconnection of existing physical device. */ if (_ux_system_host -> ux_system_host_change_function) { _ux_system_host -> ux_system_host_change_function(UX_DEVICE_DISCONNECTION, UX_NULL, (VOID*)device); } /* Now all the resources for this device must be free. */ _ux_host_stack_device_resources_free(device); /* Decrement the number of devices on this bus. */ hcd -> ux_hcd_nb_devices--; /* We are done with this device removal. */ return(UX_SUCCESS); }