/*************************************************************************** * 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 HID Class */ /** */ /**************************************************************************/ /**************************************************************************/ #define UX_SOURCE_CODE /* Include necessary system files. */ #include "ux_api.h" #include "ux_device_class_hid.h" #include "ux_device_stack.h" /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _ux_device_class_hid_receiver_initialize PORTABLE C */ /* 6.3.0 */ /* AUTHOR */ /* */ /* Chaoqiong Xiao, Microsoft Corporation */ /* */ /* DESCRIPTION */ /* */ /* This function initializes the USB HID device receiver. */ /* This function is called by the class register function. It is only */ /* done once. */ /* */ /* INPUT */ /* */ /* hid Pointer to hid instance */ /* parameter Pointer to hid parameter */ /* receiver Pointer to fill pointer to */ /* allocated receiver instance */ /* */ /* OUTPUT */ /* */ /* Completion Status */ /* */ /* CALLS */ /* */ /* _ux_utility_memory_allocate Allocate memory */ /* _ux_utility_memory_free Free memory */ /* _ux_utility_thread_create Create thread */ /* _ux_utility_thread_delete Delete thread */ /* */ /* CALLED BY */ /* */ /* USBX Source Code */ /* */ /**************************************************************************/ UINT _ux_device_class_hid_receiver_initialize(UX_SLAVE_CLASS_HID *hid, UX_SLAVE_CLASS_HID_PARAMETER *parameter, UX_DEVICE_CLASS_HID_RECEIVER **receiver) { #if !defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) UX_PARAMETER_NOT_USED(hid); UX_PARAMETER_NOT_USED(parameter); UX_PARAMETER_NOT_USED(receiver); return(UX_FUNCTION_NOT_SUPPORTED); #else ULONG memory_size; ULONG events_size; UCHAR *memory_receiver; UCHAR *memory_events; #if !defined(UX_DEVICE_STANDALONE) UCHAR *memory_stack; #endif #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY) UX_DEVICE_CLASS_HID_RECEIVED_EVENT *events_head; UCHAR *buffer; UINT i; #endif UINT status = UX_SUCCESS; /* Validate parameters. */ UX_ASSERT(parameter -> ux_device_class_hid_parameter_receiver_event_max_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH); /* Allocate memory for receiver and receiver events. */ /* Memory of thread stack and receiver instance. */ #if !defined(UX_DEVICE_STANDALONE) UX_ASSERT(!UX_OVERFLOW_CHECK_ADD_ULONG(UX_DEVICE_CLASS_HID_RECEIVER_THREAD_STACK_SIZE, sizeof(UX_DEVICE_CLASS_HID_RECEIVER))); memory_size = UX_DEVICE_CLASS_HID_RECEIVER_THREAD_STACK_SIZE + sizeof(UX_DEVICE_CLASS_HID_RECEIVER); #else memory_size = sizeof(UX_DEVICE_CLASS_HID_RECEIVER); #endif UX_ASSERT(!UX_OVERFLOW_CHECK_ADD_ULONG(parameter -> ux_device_class_hid_parameter_receiver_event_max_length, sizeof(ULONG))); #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY) /* Events structs are in regular memory. */ UX_ASSERT(!UX_OVERFLOW_CHECK_MULV_ULONG(sizeof(UX_DEVICE_CLASS_HID_RECEIVED_EVENT), parameter -> ux_device_class_hid_parameter_receiver_event_max_number)); events_size = sizeof(UX_DEVICE_CLASS_HID_RECEIVED_EVENT) * parameter -> ux_device_class_hid_parameter_receiver_event_max_number; /* Memory of events are allocated later as cache safe memory. */ #else /* Memory of events. */ events_size = parameter -> ux_device_class_hid_parameter_receiver_event_max_length + sizeof(ULONG); UX_ASSERT(!UX_OVERFLOW_CHECK_MULV_ULONG(events_size, parameter -> ux_device_class_hid_parameter_receiver_event_max_number)); events_size *= parameter -> ux_device_class_hid_parameter_receiver_event_max_number; #endif UX_ASSERT(!UX_OVERFLOW_CHECK_ADD_ULONG(memory_size, events_size)); memory_size += events_size; /* Allocate memory. */ memory_receiver = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, memory_size); if (memory_receiver == UX_NULL) return(UX_MEMORY_INSUFFICIENT); #if !defined(UX_DEVICE_STANDALONE) memory_stack = memory_receiver + sizeof(UX_DEVICE_CLASS_HID_RECEIVER); memory_events = memory_stack + UX_DEVICE_CLASS_HID_RECEIVER_THREAD_STACK_SIZE; #else memory_events = memory_receiver + sizeof(UX_DEVICE_CLASS_HID_RECEIVER); #endif #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY) /* Allocate cache safe memory. */ /* Total buffer size calculate. */ events_size = parameter -> ux_device_class_hid_parameter_receiver_event_max_length; UX_ASSERT(!UX_OVERFLOW_CHECK_MULV_ULONG(events_size, parameter -> ux_device_class_hid_parameter_receiver_event_max_number)); events_size *= parameter -> ux_device_class_hid_parameter_receiver_event_max_number; /* Allocate buffer. */ buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, events_size); if (buffer == UX_NULL) { _ux_utility_memory_free(memory_receiver); return(UX_MEMORY_INSUFFICIENT); } /* Assign events buffers. */ events_head = (UX_DEVICE_CLASS_HID_RECEIVED_EVENT *) memory_events; for (i = 0; i < parameter -> ux_device_class_hid_parameter_receiver_event_max_number; i++) { /* Assign event buffer. */ events_head -> ux_device_class_hid_received_event_data = buffer; /* Move to next event and next buffer. */ buffer += parameter -> ux_device_class_hid_parameter_receiver_event_max_length; events_head ++; } #endif /* Store receiver instance pointer. */ (*receiver) = (UX_DEVICE_CLASS_HID_RECEIVER *)memory_receiver; #if !defined(UX_DEVICE_STANDALONE) /* This instance needs to be running in a different thread. So start a new thread. We pass a pointer to the class to the new thread. This thread does not start until we have a instance of the class. */ if (status == UX_SUCCESS) status = _ux_utility_thread_create(&(*receiver) -> ux_device_class_hid_receiver_thread, "ux_device_class_hid_receiver_thread", _ux_device_class_hid_receiver_thread, (ULONG) (ALIGN_TYPE) hid, (VOID *) memory_stack, UX_DEVICE_CLASS_HID_RECEIVER_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS, UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START); #endif /* Check the creation of this thread. */ if (status == UX_SUCCESS) { #if !defined(UX_DEVICE_STANDALONE) UX_THREAD_EXTENSION_PTR_SET(&((*receiver) -> ux_device_class_hid_receiver_thread), hid) #else hid -> ux_device_class_hid_read_state = UX_DEVICE_CLASS_HID_RECEIVER_START; (*receiver) -> ux_device_class_hid_receiver_tasks_run = _ux_device_class_hid_receiver_tasks_run; #endif /* Initialize event buffer size. */ (*receiver) -> ux_device_class_hid_receiver_event_buffer_size = parameter -> ux_device_class_hid_parameter_receiver_event_max_length; /* Initialize events. */ (*receiver) -> ux_device_class_hid_receiver_events = (UX_DEVICE_CLASS_HID_RECEIVED_EVENT *)(memory_events); (*receiver) -> ux_device_class_hid_receiver_events_end = (UX_DEVICE_CLASS_HID_RECEIVED_EVENT *)(memory_receiver + memory_size); (*receiver) -> ux_device_class_hid_receiver_event_read_pos = (*receiver) -> ux_device_class_hid_receiver_events; (*receiver) -> ux_device_class_hid_receiver_event_save_pos = (*receiver) -> ux_device_class_hid_receiver_events; /* Initialize uninitialize function. */ (*receiver) -> ux_device_class_hid_receiver_uninitialize = _ux_device_class_hid_receiver_uninitialize; /* Initialize callback function. */ (*receiver) -> ux_device_class_hid_receiver_event_callback = parameter -> ux_device_class_hid_parameter_receiver_event_callback; /* Done success. */ return(UX_SUCCESS); } else status = (UX_THREAD_ERROR); /* Free allocated memory. */ _ux_utility_memory_free(*receiver); (*receiver) = UX_NULL; /* Return completion status. */ return(status); #endif }