/*************************************************************************** * 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 */ /** */ /** Device CDC_ECM Class */ /** */ /**************************************************************************/ /**************************************************************************/ #define UX_SOURCE_CODE /* Include necessary system files. */ #include "ux_api.h" #include "ux_device_class_cdc_ecm.h" #include "ux_device_stack.h" /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_cdc_ecm_initialize PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function initializes the USB CDC_ECM device. */ /* */ /* INPUT */ /* */ /* command Pointer to cdc_ecm command */ /* */ /* OUTPUT */ /* */ /* Completion Status */ /* */ /* CALLS */ /* */ /* _ux_utility_memory_allocate Allocate memory */ /* _ux_utility_memory_free Free memory */ /* _ux_utility_mutex_create Create Mutex */ /* _ux_device_mutex_delete Delete Mutex */ /* _ux_utility_event_flags_create Create Flag group */ /* _ux_utility_event_flags_delete Delete Flag group */ /* _ux_device_thread_create Create Thread */ /* _ux_device_thread_delete Delete Thread */ /* */ /* CALLED BY */ /* */ /* USBX Source Code */ /* */ /**************************************************************************/ UINT _ux_device_class_cdc_ecm_initialize(UX_SLAVE_CLASS_COMMAND *command) { #if defined(UX_DEVICE_STANDALONE) UX_PARAMETER_NOT_USED(command); return(UX_FUNCTION_NOT_SUPPORTED); #else UX_SLAVE_CLASS_CDC_ECM *cdc_ecm; UX_SLAVE_CLASS_CDC_ECM_PARAMETER *cdc_ecm_parameter; UX_SLAVE_CLASS *class_ptr; UINT status; /* Get the class container. */ class_ptr = command -> ux_slave_class_command_class_ptr; /* Create an instance of the device cdc_ecm class. */ cdc_ecm = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_CDC_ECM)); /* Check for successful allocation. */ if (cdc_ecm == UX_NULL) return(UX_MEMORY_INSUFFICIENT); /* Create a mutex to protect the CDC_ECM thread and the application messing up the transmit queue. */ status = _ux_utility_mutex_create(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex, "ux_slave_class_cdc_ecm_mutex"); if (status != UX_SUCCESS) { _ux_utility_memory_free(cdc_ecm); return(UX_MUTEX_ERROR); } /* Assume good result. */ status = UX_SUCCESS; #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1 /* Allocate buffer for endpoints. */ UX_ASSERT(!UX_DEVICE_CLASS_CDC_ECM_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW); cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_DEVICE_CLASS_CDC_ECM_ENDPOINT_BUFFER_SIZE); if (cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer == UX_NULL) status = (UX_MEMORY_INSUFFICIENT); #endif /* Allocate some memory for the bulk out thread stack. */ cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE); if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack == UX_NULL) status = (UX_MEMORY_INSUFFICIENT); /* Allocate some memory for the interrupt thread stack. */ if (status == UX_SUCCESS) { cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE); /* Check for successful allocation. */ if (cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack == UX_NULL) status = (UX_MEMORY_INSUFFICIENT); } /* Allocate some memory for the bulk in thread stack. */ if (status == UX_SUCCESS) { cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE); /* Check for successful allocation. */ if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack == UX_NULL) status = (UX_MEMORY_INSUFFICIENT); } /* Interrupt endpoint treatment needs to be running in a different thread. So start a new thread. We pass a pointer to the cdc_ecm instance to the new thread. This thread does not start until we have a instance of the class. */ if (status == UX_SUCCESS) { status = _ux_device_thread_create(&cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread , "ux_slave_class_cdc_ecm_interrupt_thread", _ux_device_class_cdc_ecm_interrupt_thread, (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack , UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START); if (status != UX_SUCCESS) status = (UX_THREAD_ERROR); } UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread), class_ptr) /* Check the creation of this thread. */ if (status == UX_SUCCESS) { /* Bulk endpoint treatment needs to be running in a different thread. So start a new thread. We pass a pointer to the cdc_ecm instance to the new thread. This thread does not start until we have a instance of the class. */ status = _ux_device_thread_create(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread , "ux_slave_class_cdc_ecm_bulkout_thread", _ux_device_class_cdc_ecm_bulkout_thread, (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack , UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START); if (status != UX_SUCCESS) status = (UX_THREAD_ERROR); else { UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread), class_ptr) /* Bulk endpoint treatment needs to be running in a different thread. So start a new thread. We pass a pointer to the cdc_ecm instance to the new thread. This thread does not start until we have a instance of the class. */ status = _ux_device_thread_create(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread , "ux_slave_class_cdc_ecm_bulkin_thread", _ux_device_class_cdc_ecm_bulkin_thread, (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack , UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START); if (status != UX_SUCCESS) status = (UX_THREAD_ERROR); else { UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread), class_ptr) /* Create a event flag group for the cdc_ecm class to synchronize with the event interrupt thread. */ status = _ux_utility_event_flags_create(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, "ux_device_class_cdc_ecm_event_flag"); if (status != UX_SUCCESS) status = (UX_EVENT_ERROR); else { /* Save the address of the CDC_ECM instance inside the CDC_ECM container. */ class_ptr -> ux_slave_class_instance = (VOID *) cdc_ecm; /* Get the pointer to the application parameters for the cdc_ecm class. */ cdc_ecm_parameter = command -> ux_slave_class_command_parameter; /* Store the start and stop signals if needed by the application. */ cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = cdc_ecm_parameter -> ux_slave_class_cdc_ecm_instance_activate; cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = cdc_ecm_parameter -> ux_slave_class_cdc_ecm_instance_deactivate; /* Copy the local node ID. */ _ux_utility_memory_copy(cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id, cdc_ecm_parameter -> ux_slave_class_cdc_ecm_parameter_local_node_id, UX_DEVICE_CLASS_CDC_ECM_NODE_ID_LENGTH); /* Use case of memcpy is verified. */ /* Copy the remote node ID. */ _ux_utility_memory_copy(cdc_ecm -> ux_slave_class_cdc_ecm_remote_node_id, cdc_ecm_parameter -> ux_slave_class_cdc_ecm_parameter_remote_node_id, UX_DEVICE_CLASS_CDC_ECM_NODE_ID_LENGTH); /* Use case of memcpy is verified. */ /* Store the rest of the parameters as they are in the local instance. */ _ux_utility_memory_copy(&cdc_ecm -> ux_slave_class_cdc_ecm_parameter, cdc_ecm_parameter, sizeof (UX_SLAVE_CLASS_CDC_ECM_PARAMETER)); /* Use case of memcpy is verified. */ return(UX_SUCCESS); } _ux_device_thread_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread); } _ux_device_thread_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread); } _ux_device_thread_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread); } /* Free allocated resources. */ if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack) _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack); if (cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack) _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack); if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack) _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack); #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1 if (cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer) _ux_utility_memory_free(cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer); #endif _ux_device_mutex_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex); _ux_utility_memory_free(cdc_ecm); /* Return completion status. */ return(status); #endif }