summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMAY <[email protected]>2026-06-04 21:25:54 +0200
committerGitHub <[email protected]>2026-06-04 15:25:54 -0400
commit35927220c0165c06dc90e6c9aa7a8eb9b5806065 (patch)
tree445b00cc418ce9a86762f900bd95a189d8ebc324
parentc048e1ce16f90ab4c670238d0ebbc487faac9118 (diff)
Added optional device HID protocol change callback and host HID protocol get/set API (#244)
This pull request adds host-side HID API functions to get and set the HID protocol (boot vs. report mode), and introduces an optional device-sidecallback invoked when the protocol changes. New features - Added host-side APIs ux_host_class_hid_protocol_set() and ux_host_class_hid_protocol_get() with error-checking wrappers (_uxe_ variants). - Added optional device-side callback ux_device_class_hid_set_protocol_callback, invoked when the host changes the active protocol. - Added a comprehensive test to verify the new protocol callback functionality. Bug fixes (host-side protocol get/set) 1. DMA buffer safety (protocol_get): The received byte is now written into a cache-safe allocated buffer instead of the caller's USHORT* directly. Stack memory is not DMA-safe on cache-incoherent embedded targets, and writing 1 byte into a USHORT* yields incorrect results on big-endianplatforms. Follows the same pattern as ux_host_class_hid_idle_get. 2. Missing device protection semaphore (both functions): In RTOS mode, ux_device_protection_semaphore is now acquired before submitting the transfer, in addition to the HID instance semaphore. All other HID control transfer functions (idle_get, idle_set) take both semaphores; omitting it allowed concurrent callers to corrupt the shared transfer_request fields. 3. Missing standalone locking (both functions): Added proper UX_HOST_STANDALONE support using UX_DISABLE/UX_RESTORE to atomically check and setUX_HOST_CLASS_HID_FLAG_LOCK and UX_DEVICE_FLAG_LOCK, and set UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK + UX_TRANSFER_STATE_RESET on the transfer request before initiating. Follows the idle_get inline standalone pattern. Co-authored-by: Frédéric Desbiens <[email protected]> Co-authored-by: Copilot <[email protected]>
-rw-r--r--common/usbx_device_classes/inc/ux_device_class_hid.h5
-rw-r--r--common/usbx_device_classes/src/ux_device_class_hid_control_request.c16
-rw-r--r--common/usbx_device_classes/src/ux_device_class_hid_initialize.c2
-rw-r--r--common/usbx_host_classes/CMakeLists.txt2
-rw-r--r--common/usbx_host_classes/inc/ux_host_class_hid.h19
-rw-r--r--common/usbx_host_classes/src/ux_host_class_hid_protocol_get.c208
-rw-r--r--common/usbx_host_classes/src/ux_host_class_hid_protocol_set.c182
-rw-r--r--test/cmake/usbx/regression/CMakeLists.txt1
-rw-r--r--test/regression/usbx_ux_device_class_hid_set_protocol_callback_test.c465
-rw-r--r--test/regression/usbxtestcontrol.c2
10 files changed, 895 insertions, 7 deletions
diff --git a/common/usbx_device_classes/inc/ux_device_class_hid.h b/common/usbx_device_classes/inc/ux_device_class_hid.h
index add018e..f5a48f4 100644
--- a/common/usbx_device_classes/inc/ux_device_class_hid.h
+++ b/common/usbx_device_classes/inc/ux_device_class_hid.h
@@ -215,6 +215,7 @@ typedef struct UX_SLAVE_CLASS_HID_STRUCT
UINT ux_device_class_hid_state;
UINT (*ux_device_class_hid_callback)(struct UX_SLAVE_CLASS_HID_STRUCT *hid, UX_SLAVE_CLASS_HID_EVENT *);
UINT (*ux_device_class_hid_get_callback)(struct UX_SLAVE_CLASS_HID_STRUCT *hid, UX_SLAVE_CLASS_HID_EVENT *);
+ VOID (*ux_device_class_hid_set_protocol_callback)(struct UX_SLAVE_CLASS_HID_STRUCT *hid, ULONG protocol);
VOID (*ux_slave_class_hid_instance_activate)(VOID *);
VOID (*ux_slave_class_hid_instance_deactivate)(VOID *);
UCHAR *ux_device_class_hid_report_address;
@@ -331,6 +332,10 @@ typedef struct UX_SLAVE_CLASS_HID_PARAMETER_STRUCT
ULONG ux_device_class_hid_parameter_report_length;
UINT (*ux_device_class_hid_parameter_callback)(struct UX_SLAVE_CLASS_HID_STRUCT *hid, UX_SLAVE_CLASS_HID_EVENT *);
UINT (*ux_device_class_hid_parameter_get_callback)(struct UX_SLAVE_CLASS_HID_STRUCT *hid, UX_SLAVE_CLASS_HID_EVENT *);
+
+ /* Optional callback invoked when protocol changes (boot/report). */
+ VOID (*ux_device_class_hid_parameter_set_protocol_callback)(struct UX_SLAVE_CLASS_HID_STRUCT *hid, ULONG protocol);
+
#if defined(UX_DEVICE_CLASS_HID_FLEXIBLE_EVENTS_QUEUE)
ULONG ux_device_class_hid_parameter_event_max_number;
ULONG ux_device_class_hid_parameter_event_max_length;
diff --git a/common/usbx_device_classes/src/ux_device_class_hid_control_request.c b/common/usbx_device_classes/src/ux_device_class_hid_control_request.c
index 5569ba1..ccc47e8 100644
--- a/common/usbx_device_classes/src/ux_device_class_hid_control_request.c
+++ b/common/usbx_device_classes/src/ux_device_class_hid_control_request.c
@@ -178,15 +178,28 @@ UX_SLAVE_CLASS_HID *hid;
case UX_DEVICE_CLASS_HID_COMMAND_GET_PROTOCOL:
- /* Send the protocol. */
+ /* Send the protocol to host. */
*transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR)hid -> ux_device_class_hid_protocol;
_ux_device_stack_transfer_request(transfer_request, 1, request_length);
break;
case UX_DEVICE_CLASS_HID_COMMAND_SET_PROTOCOL:
+ /* Check protocol must be 0 (Boot) or 1 (Report). */
+ if ((request_value != UX_DEVICE_CLASS_HID_PROTOCOL_BOOT) &&
+ (request_value != UX_DEVICE_CLASS_HID_PROTOCOL_REPORT))
+ {
+ /* Invalid value: not handled. */
+ return(UX_ERROR);
+ }
+
/* Accept the protocol. */
hid -> ux_device_class_hid_protocol = request_value;
+
+ /* If there is a callback defined by the application, send the protocol to it. */
+ if (hid -> ux_device_class_hid_set_protocol_callback != UX_NULL)
+ hid -> ux_device_class_hid_set_protocol_callback(hid, request_value);
+
break;
default:
@@ -198,4 +211,3 @@ UX_SLAVE_CLASS_HID *hid;
/* It's handled. */
return(UX_SUCCESS);
}
-
diff --git a/common/usbx_device_classes/src/ux_device_class_hid_initialize.c b/common/usbx_device_classes/src/ux_device_class_hid_initialize.c
index 94d7f01..5b6e4f0 100644
--- a/common/usbx_device_classes/src/ux_device_class_hid_initialize.c
+++ b/common/usbx_device_classes/src/ux_device_class_hid_initialize.c
@@ -9,6 +9,7 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+
/**************************************************************************/
/**************************************************************************/
/** */
@@ -166,6 +167,7 @@ UCHAR *buffer;
/* Store the callback function. */
hid -> ux_device_class_hid_callback = hid_parameter -> ux_device_class_hid_parameter_callback;
hid -> ux_device_class_hid_get_callback = hid_parameter -> ux_device_class_hid_parameter_get_callback;
+ hid -> ux_device_class_hid_set_protocol_callback = hid_parameter -> ux_device_class_hid_parameter_set_protocol_callback;
#if defined(UX_DEVICE_CLASS_HID_FLEXIBLE_EVENTS_QUEUE)
diff --git a/common/usbx_host_classes/CMakeLists.txt b/common/usbx_host_classes/CMakeLists.txt
index 4742089..11083a2 100644
--- a/common/usbx_host_classes/CMakeLists.txt
+++ b/common/usbx_host_classes/CMakeLists.txt
@@ -93,6 +93,8 @@ target_sources(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_idle_get.c
${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_idle_set.c
${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_idle_set_run.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_protocol_set.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_protocol_get.c
${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_instance_clean.c
${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_interrupt_endpoint_search.c
${CMAKE_CURRENT_LIST_DIR}/src/ux_host_class_hid_item_data_get.c
diff --git a/common/usbx_host_classes/inc/ux_host_class_hid.h b/common/usbx_host_classes/inc/ux_host_class_hid.h
index b10f605..94cf261 100644
--- a/common/usbx_host_classes/inc/ux_host_class_hid.h
+++ b/common/usbx_host_classes/inc/ux_host_class_hid.h
@@ -15,7 +15,7 @@
/** */
/** USBX Component */
/** */
-/** HID Class */
+/** Host HID Class */
/** */
/**************************************************************************/
/**************************************************************************/
@@ -548,7 +548,7 @@ extern "C" {
#define UX_HOST_CLASS_HID_CONSUMER_ALTERNATE_AUDIO_DECREMENT 0x173
#define UX_HOST_CLASS_HID_CONSUMER_APPLICATION_LAUNCH_BUTTONS 0x174
#define UX_HOST_CLASS_HID_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION 0x180
-#define UX_HOST_CLASS_HID_CONSUMER_AL_PROGRAMMABLE_BUTTON 0x181
+#define UX_HOST_CLASS_HID_CONSUMER_AL_PROGRAMMABLE_BUTTON 0x181
#define UX_HOST_CLASS_HID_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION 0x182
#define UX_HOST_CLASS_HID_CONSUMER_AL_WORD_PROCESSOR 0x183
#define UX_HOST_CLASS_HID_CONSUMER_AL_TEXT_EDITOR 0x184
@@ -764,6 +764,10 @@ extern "C" {
#define UX_HOST_CLASS_HID_REPORT_TRANSFER_TIMEOUT 10000
#endif
+/* HID protocol values. */
+#define UX_HOST_CLASS_HID_PROTOCOL_BOOT 0x00
+#define UX_HOST_CLASS_HID_PROTOCOL_REPORT 0x01
+
/* Define HID Class descriptor. */
typedef struct UX_HID_DESCRIPTOR_STRUCT
@@ -1077,7 +1081,8 @@ VOID _ux_host_class_hid_transfer_request_completed(UX_TRANSFER *transfer_requ
UINT _ux_host_class_hid_tasks_run(UX_HOST_CLASS *hid_class);
UINT _ux_host_class_hid_idle_set_run(UX_HOST_CLASS_HID *hid, USHORT idle_time, USHORT report_id);
UINT _ux_host_class_hid_report_set_run(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report);
-
+UINT _ux_host_class_hid_protocol_set(UX_HOST_CLASS_HID *hid, USHORT protocol);
+UINT _ux_host_class_hid_protocol_get(UX_HOST_CLASS_HID *hid, USHORT *protocol);
UINT _uxe_host_class_hid_client_register(UCHAR *hid_client_name,
UINT (*hid_client_handler)(struct UX_HOST_CLASS_HID_CLIENT_COMMAND_STRUCT *));
@@ -1095,7 +1100,8 @@ UINT _uxe_host_class_hid_report_set(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID
UINT _uxe_host_class_hid_idle_set_run(UX_HOST_CLASS_HID *hid, USHORT idle_time, USHORT report_id);
UINT _uxe_host_class_hid_report_set_run(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report);
-
+UINT _uxe_host_class_hid_protocol_set(UX_HOST_CLASS_HID *hid, USHORT protocol);
+UINT _uxe_host_class_hid_protocol_get(UX_HOST_CLASS_HID *hid, USHORT *protocol);
/* Define HID Class API prototypes. */
@@ -1122,6 +1128,8 @@ UINT _uxe_host_class_hid_report_set_run(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS
#define ux_host_class_hid_report_id_get _uxe_host_class_hid_report_id_get
#define ux_host_class_hid_report_get _uxe_host_class_hid_report_get
#define ux_host_class_hid_report_set _uxe_host_class_hid_report_set
+#define ux_host_class_hid_protocol_set _uxe_host_class_hid_protocol_set
+#define ux_host_class_hid_protocol_get _uxe_host_class_hid_protocol_get
#else
@@ -1137,6 +1145,8 @@ UINT _uxe_host_class_hid_report_set_run(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS
#define ux_host_class_hid_report_id_get _ux_host_class_hid_report_id_get
#define ux_host_class_hid_report_get _ux_host_class_hid_report_get
#define ux_host_class_hid_report_set _ux_host_class_hid_report_set
+#define ux_host_class_hid_protocol_set _ux_host_class_hid_protocol_set
+#define ux_host_class_hid_protocol_get _ux_host_class_hid_protocol_get
#endif
@@ -1148,4 +1158,3 @@ UINT _uxe_host_class_hid_report_set_run(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS
#endif
#endif
-
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_protocol_get.c b/common/usbx_host_classes/src/ux_host_class_hid_protocol_get.c
new file mode 100644
index 0000000..c5369fe
--- /dev/null
+++ b/common/usbx_host_classes/src/ux_host_class_hid_protocol_get.c
@@ -0,0 +1,208 @@
+/***************************************************************************
+ * Copyright (c) 2025-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 HID Class */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+/* Include necessary system files. */
+
+#define UX_SOURCE_CODE
+
+#include "ux_api.h"
+#include "ux_host_class_hid.h"
+#include "ux_host_stack.h"
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_host_class_hid_protocol_get PORTABLE C */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function performs a GET_PROTOCOL to the HID device to read */
+/* current protocol (BOOT=0 or REPORT=1). */
+/* */
+/* INPUT */
+/* */
+/* hid Pointer to HID class */
+/* protocol Destination for protocol */
+/* */
+/* OUTPUT */
+/* */
+/* Completion Status */
+/* */
+/* CALLED BY */
+/* */
+/* Application */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/**************************************************************************/
+UINT _ux_host_class_hid_protocol_get(UX_HOST_CLASS_HID *hid, USHORT *protocol)
+{
+#if defined(UX_HOST_STANDALONE)
+UX_INTERRUPT_SAVE_AREA
+#endif
+UX_ENDPOINT *control_endpoint;
+UX_TRANSFER *transfer_request;
+UCHAR *protocol_byte;
+UINT status;
+
+ /* Ensure the instance is valid. */
+ if (_ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, (VOID *) hid) != UX_SUCCESS)
+ {
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+#if defined(UX_HOST_STANDALONE)
+ hid -> ux_host_class_hid_status = UX_HOST_CLASS_INSTANCE_UNKNOWN;
+#endif
+
+ return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
+ }
+
+ /* Initialize output to a known value. */
+ *protocol = 0;
+
+ /* Get the default control endpoint transfer request pointer. */
+ control_endpoint = &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
+ transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
+
+ /* Protect thread reentry to this instance. */
+#if defined(UX_HOST_STANDALONE)
+ UX_DISABLE
+ if (hid -> ux_host_class_hid_flags & UX_HOST_CLASS_HID_FLAG_LOCK)
+ {
+ UX_RESTORE
+ return(UX_BUSY);
+ }
+ hid -> ux_host_class_hid_flags |= UX_HOST_CLASS_HID_FLAG_LOCK;
+ UX_RESTORE
+#else
+ status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER);
+ if (status != UX_SUCCESS)
+ return(status);
+#endif
+
+ /* Need to allocate a cache-safe buffer for the DMA transfer. */
+ protocol_byte = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, 1);
+ if (protocol_byte == UX_NULL)
+ {
+
+ /* Unprotect thread reentry to this instance. */
+#if defined(UX_HOST_STANDALONE)
+ _ux_host_class_hid_unlock(hid);
+#else
+ _ux_host_semaphore_put(&hid -> ux_host_class_hid_semaphore);
+#endif
+ return(UX_MEMORY_INSUFFICIENT);
+ }
+
+ /* Protect the control endpoint. It will be unprotected in the transfer request function. */
+#if defined(UX_HOST_STANDALONE)
+ UX_DISABLE
+ if (hid -> ux_host_class_hid_device -> ux_device_flags & UX_DEVICE_FLAG_LOCK)
+ {
+ _ux_utility_memory_free(protocol_byte);
+ _ux_host_class_hid_unlock(hid);
+ UX_RESTORE
+ return(UX_BUSY);
+ }
+ hid -> ux_host_class_hid_device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK;
+ transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK;
+ UX_TRANSFER_STATE_RESET(transfer_request);
+ UX_RESTORE
+#else
+ status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
+ if (status != UX_SUCCESS)
+ {
+ _ux_utility_memory_free(protocol_byte);
+ _ux_host_semaphore_put(&hid -> ux_host_class_hid_semaphore);
+ return(status);
+ }
+#endif
+
+ /* Create a transfer request for the GET_PROTOCOL request. */
+ transfer_request -> ux_transfer_request_data_pointer = protocol_byte;
+ transfer_request -> ux_transfer_request_requested_length = 1;
+ transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_GET_PROTOCOL;
+ transfer_request -> ux_transfer_request_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
+ transfer_request -> ux_transfer_request_value = 0;
+ transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber;
+
+ /* Send request to HCD layer. */
+ status = _ux_host_stack_transfer_request(transfer_request);
+
+#if defined(UX_HOST_STANDALONE)
+ if (!(transfer_request -> ux_transfer_request_flags & UX_TRANSFER_FLAG_AUTO_WAIT))
+ {
+ hid -> ux_host_class_hid_allocated = protocol_byte;
+ return(status);
+ }
+#endif
+
+ /* Check for correct transfer and for the entire protocol byte returned. */
+ if (status == UX_SUCCESS && transfer_request -> ux_transfer_request_actual_length == 1)
+ *protocol = (USHORT) *protocol_byte;
+
+ /* Free the allocated buffer. */
+ _ux_utility_memory_free(protocol_byte);
+
+ /* Unprotect thread reentry to this instance. */
+#if defined(UX_HOST_STANDALONE)
+ _ux_host_class_hid_unlock(hid);
+#else
+ _ux_host_semaphore_put(&hid -> ux_host_class_hid_semaphore);
+#endif
+
+ return(status);
+}
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _uxe_host_class_hid_protocol_get PORTABLE C */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function checks errors in HID protocol get function call. */
+/* */
+/* INPUT */
+/* */
+/* hid Pointer to HID class */
+/* protocol Destination for protocol */
+/* */
+/* OUTPUT */
+/* */
+/* Status */
+/* */
+/**************************************************************************/
+UINT _uxe_host_class_hid_protocol_get(UX_HOST_CLASS_HID *hid, USHORT *protocol)
+{
+ /* Sanity check. */
+ if (hid == UX_NULL || protocol == UX_NULL)
+ return(UX_INVALID_PARAMETER);
+
+ /* Invoke protocol get function. */
+ return(_ux_host_class_hid_protocol_get(hid, protocol));
+}
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_protocol_set.c b/common/usbx_host_classes/src/ux_host_class_hid_protocol_set.c
new file mode 100644
index 0000000..bb46349
--- /dev/null
+++ b/common/usbx_host_classes/src/ux_host_class_hid_protocol_set.c
@@ -0,0 +1,182 @@
+/***************************************************************************
+ * Copyright (c) 2025-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 HID Class */
+/** */
+/**************************************************************************/
+/**************************************************************************/
+
+/* Include necessary system files. */
+
+#define UX_SOURCE_CODE
+
+#include "ux_api.h"
+#include "ux_host_class_hid.h"
+#include "ux_host_stack.h"
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _ux_host_class_hid_protocol_set PORTABLE C */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function performs a SET_PROTOCOL to the HID device to switch */
+/* between BOOT (0) and REPORT (1) protocols. */
+/* */
+/* INPUT */
+/* */
+/* hid Pointer to HID class */
+/* protocol Protocol (BOOT/REPORT) */
+/* */
+/* OUTPUT */
+/* */
+/* Completion Status */
+/* */
+/* CALLED BY */
+/* */
+/* Application */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/**************************************************************************/
+UINT _ux_host_class_hid_protocol_set(UX_HOST_CLASS_HID *hid, USHORT protocol)
+{
+#if defined(UX_HOST_STANDALONE)
+UX_INTERRUPT_SAVE_AREA
+#endif
+UX_ENDPOINT *control_endpoint;
+UX_TRANSFER *transfer_request;
+UINT status;
+
+ /* Ensure the instance is valid. */
+ if (_ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, (VOID *) hid) != UX_SUCCESS)
+ {
+
+ /* If trace is enabled, insert this event into the trace buffer. */
+ UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
+
+#if defined(UX_HOST_STANDALONE)
+ hid -> ux_host_class_hid_status = UX_HOST_CLASS_INSTANCE_UNKNOWN;
+#endif
+ return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
+ }
+
+ /* Get the default control endpoint transfer request pointer. */
+ control_endpoint = &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
+ transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
+
+ /* Protect thread reentry to this instance. */
+#if defined(UX_HOST_STANDALONE)
+ UX_DISABLE
+ if (hid -> ux_host_class_hid_flags & UX_HOST_CLASS_HID_FLAG_LOCK)
+ {
+ UX_RESTORE
+ return(UX_BUSY);
+ }
+ hid -> ux_host_class_hid_flags |= UX_HOST_CLASS_HID_FLAG_LOCK;
+ UX_RESTORE
+#else
+ status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER);
+ if (status != UX_SUCCESS)
+ return(status);
+
+ /* Protect the control endpoint semaphore here. It will be unprotected in the
+ transfer request function. */
+ status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
+ if (status != UX_SUCCESS)
+ {
+ _ux_host_semaphore_put(&hid -> ux_host_class_hid_semaphore);
+ return(status);
+ }
+#endif
+
+#if defined(UX_HOST_STANDALONE)
+ /* Protect the control endpoint. It will be unprotected in the transfer request function. */
+ UX_DISABLE
+ if (hid -> ux_host_class_hid_device -> ux_device_flags & UX_DEVICE_FLAG_LOCK)
+ {
+ _ux_host_class_hid_unlock(hid);
+ UX_RESTORE
+ return(UX_BUSY);
+ }
+ hid -> ux_host_class_hid_device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK;
+ transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK;
+ UX_TRANSFER_STATE_RESET(transfer_request);
+ UX_RESTORE
+#endif
+
+ /* Create a transfer request for the SET_PROTOCOL request. */
+ transfer_request -> ux_transfer_request_data_pointer = UX_NULL;
+ transfer_request -> ux_transfer_request_requested_length = 0;
+ transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_PROTOCOL;
+ transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
+ transfer_request -> ux_transfer_request_value = (UINT)protocol;
+ transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber;
+
+ /* Send request to HCD layer. */
+ status = _ux_host_stack_transfer_request(transfer_request);
+
+#if defined(UX_HOST_STANDALONE)
+ if (!(transfer_request -> ux_transfer_request_flags & UX_TRANSFER_FLAG_AUTO_WAIT))
+ return(status);
+ _ux_host_class_hid_unlock(hid);
+#else
+ /* Unprotect thread reentry to this instance. */
+ _ux_host_semaphore_put(&hid -> ux_host_class_hid_semaphore);
+#endif
+
+ /* Return the function status. */
+ return(status);
+}
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _uxe_host_class_hid_protocol_set PORTABLE C */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function checks errors in HID protocol set function call. */
+/* */
+/* INPUT */
+/* */
+/* hid Pointer to HID class */
+/* protocol Protocol (BOOT/REPORT) */
+/* */
+/* OUTPUT */
+/* */
+/* Status */
+/* */
+/**************************************************************************/
+UINT _uxe_host_class_hid_protocol_set(UX_HOST_CLASS_HID *hid, USHORT protocol)
+{
+ /* Sanity check. */
+ if (hid == UX_NULL)
+ return(UX_INVALID_PARAMETER);
+
+ /* Validate protocol value: must be BOOT(0) or REPORT(1). */
+ if (protocol != UX_HOST_CLASS_HID_PROTOCOL_BOOT &&
+ protocol != UX_HOST_CLASS_HID_PROTOCOL_REPORT)
+ return(UX_INVALID_PARAMETER);
+
+ /* Invoke protocol set function. */
+ return(_ux_host_class_hid_protocol_set(hid, protocol));
+}
diff --git a/test/cmake/usbx/regression/CMakeLists.txt b/test/cmake/usbx/regression/CMakeLists.txt
index 2992765..729559c 100644
--- a/test/cmake/usbx/regression/CMakeLists.txt
+++ b/test/cmake/usbx/regression/CMakeLists.txt
@@ -139,6 +139,7 @@ set(ux_class_hid_test_cases
${SOURCE_DIR}/usbx_ux_device_class_hid_activate_test2.c
${SOURCE_DIR}/usbx_ux_device_class_hid_activate_test3.c
${SOURCE_DIR}/usbx_ux_device_class_hid_control_request_test.c
+ ${SOURCE_DIR}/usbx_ux_device_class_hid_set_protocol_callback_test.c
${SOURCE_DIR}/usbx_ux_device_class_hid_initialize_test.c
${SOURCE_DIR}/usbx_ux_device_class_hid_interrupt_thread_test2.c
${SOURCE_DIR}/usbx_ux_device_class_hid_read_test.c
diff --git a/test/regression/usbx_ux_device_class_hid_set_protocol_callback_test.c b/test/regression/usbx_ux_device_class_hid_set_protocol_callback_test.c
new file mode 100644
index 0000000..b1c0e71
--- /dev/null
+++ b/test/regression/usbx_ux_device_class_hid_set_protocol_callback_test.c
@@ -0,0 +1,465 @@
+/* This test focuses on HID device class protocol set/get functionality and related callbacks. */
+
+#include <stdio.h>
+#include "tx_api.h"
+#include "ux_api.h"
+#include "ux_system.h"
+#include "ux_utility.h"
+#include "ux_host_class_hid.h"
+#include "ux_host_class_hid_keyboard.h"
+#include "ux_device_class_hid.h"
+#include "ux_device_stack.h"
+#include "usbx_test_common_hid.h"
+
+/* Define constants. */
+#define UX_DEMO_DEBUG_SIZE (4096*8)
+#define UX_DEMO_STACK_SIZE 1024
+
+/* Define local/extern function prototypes. */
+static void demo_thread_entry(ULONG);
+static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *, UX_SLAVE_CLASS_HID_EVENT *);
+static VOID demo_set_protocol_callback(UX_SLAVE_CLASS_HID *hid, ULONG protocol);
+static TX_THREAD tx_demo_thread_host_simulation;
+static void tx_demo_thread_host_simulation_entry(ULONG);
+
+/* Define global data structures. */
+static UX_HOST_CLASS_HID *hid;
+static UINT status;
+
+static UX_SLAVE_CLASS_HID_PARAMETER hid_parameter;
+
+static volatile UINT g_set_protocol_callback_calls = 0;
+static volatile ULONG g_set_protocol_last_value = 0xFFFFFFFFu;
+
+USHORT host_protocol;
+
+static UCHAR hid_keyboard_report[] = {
+
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x06, // USAGE (Keyboard)
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x05, 0x07, // USAGE_PAGE (Keyboard)
+ 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
+ 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x95, 0x08, // REPORT_COUNT (8)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0x09, 0x39, // USAGE (Caps Lock)
+ 0x09, 0x53, // USAGE (Num Lock)
+ 0x09, 0x47, // USAGE (Scroll Lock)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x95, 0x03, // REPORT_COUNT (3)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x05, // REPORT_SIZE (5)
+ 0x81, 0x03, // INPUT (Cnst,Var,Abs)
+ 0x95, 0x05, // REPORT_COUNT (5)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x05, 0x08, // USAGE_PAGE (LEDs)
+ 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
+ 0x29, 0x05, // USAGE_MAXIMUM (Kana)
+ 0x91, 0x02, // OUTPUT (Data,Var,Abs)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x03, // REPORT_SIZE (3)
+ 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
+ 0x95, 0x06, // REPORT_COUNT (6)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x65, // LOGICAL_MAXIMUM (101)
+ 0x05, 0x07, // USAGE_PAGE (Keyboard)
+ 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
+ 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
+ 0x81, 0x00, // INPUT (Data,Ary,Abs)
+ 0xc0 // END_COLLECTION
+};
+#define HID_KEYBOARD_REPORT_LENGTH (sizeof(hid_keyboard_report) / sizeof(hid_keyboard_report[0]))
+
+
+#define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED 52
+static UCHAR device_framework_full_speed[] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
+ 0x81, 0x0A, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x02,
+ 0x00,
+
+ /* HID descriptor */
+ 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_KEYBOARD_REPORT_LENGTH),
+ MSB(HID_KEYBOARD_REPORT_LENGTH),
+
+ /* Endpoint descriptor (Interrupt) */
+ 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
+
+ };
+
+
+#define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED 62
+static UCHAR device_framework_high_speed[] = {
+
+ /* Device descriptor */
+ 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0x0a, 0x07, 0x25, 0x40, 0x01, 0x00, 0x01, 0x02,
+ 0x03, 0x01,
+
+ /* Device qualifier descriptor */
+ 0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x00,
+
+ /* Configuration descriptor */
+ 0x09, 0x02, 0x22, 0x00, 0x01, 0x01, 0x00, 0xc0,
+ 0x32,
+
+ /* Interface descriptor */
+ 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x02,
+ 0x00,
+
+ /* HID descriptor */
+ 0x09, 0x21, 0x10, 0x01, 0x21, 0x01, 0x22, LSB(HID_KEYBOARD_REPORT_LENGTH),
+ MSB(HID_KEYBOARD_REPORT_LENGTH),
+
+ /* Endpoint descriptor (Interrupt) */
+ 0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x08
+
+ };
+
+
+ /* String Device Framework :
+ Byte 0 and 1 : Word containing the language ID : 0x0904 for US
+ Byte 2 : Byte containing the index of the descriptor
+ Byte 3 : Byte containing the length of the descriptor string
+ */
+
+#define STRING_FRAMEWORK_LENGTH 40
+static UCHAR string_framework[] = {
+
+ /* Manufacturer string descriptor : Index 1 */
+ 0x09, 0x04, 0x01, 0x0c,
+ 0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
+ 0x6f, 0x67, 0x69, 0x63,
+
+ /* Product string descriptor : Index 2 */
+ 0x09, 0x04, 0x02, 0x0c,
+ 0x55, 0x53, 0x42, 0x20, 0x4b, 0x65, 0x79, 0x62,
+ 0x6f, 0x61, 0x72, 0x64,
+
+ /* Serial Number string descriptor : Index 3 */
+ 0x09, 0x04, 0x03, 0x04,
+ 0x30, 0x30, 0x30, 0x31
+ };
+
+
+ /* Multiple languages are supported on the device, to add
+ a language besides english, the unicode language code must
+ be appended to the language_id_framework array and the length
+ adjusted accordingly. */
+#define LANGUAGE_ID_FRAMEWORK_LENGTH 2
+static UCHAR language_id_framework[] = {
+
+ /* English. */
+ 0x09, 0x04
+ };
+
+
+
+/* Define the ISR dispatch. */
+
+extern VOID (*test_isr_dispatch)(void);
+
+
+/* Prototype for test control return. */
+
+void test_control_return(UINT status);
+
+
+/* Define the ISR dispatch routine. */
+
+static void test_isr(void)
+{
+
+ /* For further expansion of interrupt-level testing. */
+}
+
+
+
+static VOID error_callback(UINT system_level, UINT system_context, UINT error_code)
+{
+
+ /* @BUG_FIX_PENDING: ux_dcd_sim_slave_function.c doesn't support transfer aborts, which happen during device unregistration of a class. */
+ if (error_code != UX_FUNCTION_NOT_SUPPORTED)
+ {
+
+ /* Failed test. */
+ printf("Error on line %d, system_level: %d, system_context: %d, error code: %d\n", __LINE__, system_level, system_context, error_code);
+ test_control_return(1);
+ }
+}
+
+/* Define what the initial system looks like. */
+
+#ifdef CTEST
+void test_application_define(void *first_unused_memory)
+#else
+void usbx_ux_device_class_hid_set_protocol_callback_test_application_define(void *first_unused_memory)
+#endif
+{
+
+UINT status;
+CHAR * stack_pointer;
+CHAR * memory_pointer;
+UINT descriptor_size = HID_KEYBOARD_REPORT_LENGTH;
+
+ /* Inform user. */
+ printf("Running HID Set/Get Protocol Callback Test......................... ");
+
+ /* Initialize the free memory pointer */
+ stack_pointer = (CHAR *) usbx_memory;
+ memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
+
+ /* Initialize USBX. Memory */
+ status = ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
+
+ /* Check for error. */
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Register the error callback. */
+ _ux_utility_error_callback_register(error_callback);
+
+ /* The code below is required for installing the host portion of USBX */
+ status = ux_host_stack_initialize(UX_NULL);
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ status = ux_host_stack_class_register(_ux_system_host_class_hid_name, ux_host_class_hid_entry);
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Register the HID client(s). */
+ status = ux_host_class_hid_client_register(_ux_system_host_class_hid_client_keyboard_name, ux_host_class_hid_keyboard_entry);
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* The code below is required for installing the device portion of USBX. No call back for
+ device status change in this example. */
+ status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
+ device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
+ string_framework, STRING_FRAMEWORK_LENGTH,
+ language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL);
+ if(status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Initialize the hid class parameters for a keyboard. */
+ hid_parameter.ux_device_class_hid_parameter_report_address = hid_keyboard_report;
+ hid_parameter.ux_device_class_hid_parameter_report_length = HID_KEYBOARD_REPORT_LENGTH;
+ hid_parameter.ux_device_class_hid_parameter_callback = demo_thread_hid_callback;
+ hid_parameter.ux_device_class_hid_parameter_set_protocol_callback = demo_set_protocol_callback;
+
+ /* Initialize the device hid class. The class is connected with interface 2 */
+ status = ux_device_stack_class_register(_ux_system_slave_class_hid_name, ux_device_class_hid_entry,
+ 1, 0, (VOID *)&hid_parameter);
+ if(status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+
+ /* Initialize the simulated device controller. */
+ status = _ux_dcd_sim_slave_initialize();
+
+ /* Check for error. */
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Register all the USB host controllers available in this system */
+ status = ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, ux_hcd_sim_host_initialize,0,0);
+
+ /* Check for error. */
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Create the main host simulation thread. */
+ status = tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", tx_demo_thread_host_simulation_entry, 0,
+ stack_pointer, UX_DEMO_STACK_SIZE,
+ 20, 20, 1, TX_AUTO_START);
+
+ /* Check for error. */
+ if (status != TX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+}
+
+
+static void tx_demo_thread_host_simulation_entry(ULONG arg)
+{
+UX_SLAVE_DEVICE *device;
+UX_SLAVE_INTERFACE *interface;
+UX_SLAVE_CLASS_HID *slave_hid;
+UINT status;
+
+ device = &_ux_system_slave -> ux_system_slave_device;
+
+ /* Ensure device is configured before accessing interfaces. */
+ while (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
+ tx_thread_sleep(10);
+
+ /* Retrieve the HID class instance from the configured interface. */
+ interface = device -> ux_slave_device_first_interface;
+ if (interface == UX_NULL || interface -> ux_slave_interface_class_instance == UX_NULL)
+ {
+ printf("Error on line %d, device interface/class not ready\n", __LINE__);
+ test_control_return(1);
+ }
+ slave_hid = interface -> ux_slave_interface_class_instance;
+
+ /* Find the HID class */
+ status = demo_class_hid_get();
+ if (status != UX_SUCCESS)
+ {
+
+ printf("Error on line %d, error code: %d\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Sanity: default protocol is report (1). */
+ if (ux_device_class_hid_protocol_get(slave_hid) != UX_DEVICE_CLASS_HID_PROTOCOL_REPORT)
+ {
+ printf("Error on line %d, protocol not default report\n", __LINE__);
+ test_control_return(1);
+ }
+
+
+ status = ux_host_class_hid_protocol_get(hid, &host_protocol);
+ if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED)
+ {
+ printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ /* Default protocol is report 1. */
+ if (status == UX_SUCCESS && host_protocol != UX_HOST_CLASS_HID_PROTOCOL_REPORT)
+ {
+ printf("Error on line %d, host get protocol not report\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Issue SET_PROTOCOL to BOOT (0). */
+ status = ux_host_class_hid_protocol_set(hid, UX_HOST_CLASS_HID_PROTOCOL_BOOT);
+ if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED)
+ {
+ printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ status = ux_host_class_hid_protocol_get(hid, &host_protocol);
+
+ if (g_set_protocol_callback_calls < 1 ||
+ g_set_protocol_last_value != 0 ||
+ host_protocol != UX_HOST_CLASS_HID_PROTOCOL_BOOT)
+ {
+ printf("Error on line %d, callback verification failed (calls=%u, val=%lu)\n",
+ __LINE__, g_set_protocol_callback_calls, g_set_protocol_last_value);
+ test_control_return(1);
+ }
+
+ if (ux_device_class_hid_protocol_get(slave_hid) != UX_DEVICE_CLASS_HID_PROTOCOL_BOOT)
+ {
+ printf("Error on line %d, protocol not set to boot\n", __LINE__);
+ test_control_return(1);
+ }
+
+ /* Issue SET_PROTOCOL to REPORT (1). */
+ status = ux_host_class_hid_protocol_set(hid, UX_HOST_CLASS_HID_PROTOCOL_REPORT);
+ if (status != UX_SUCCESS && status != UX_TRANSFER_STALLED)
+ {
+ printf("Error on line %d, error code: 0x%x\n", __LINE__, status);
+ test_control_return(1);
+ }
+
+ status = ux_host_class_hid_protocol_get(hid, &host_protocol);
+
+ if (g_set_protocol_callback_calls < 2 ||
+ g_set_protocol_last_value != 1 ||
+ host_protocol != UX_HOST_CLASS_HID_PROTOCOL_REPORT)
+ {
+ printf("Error on line %d, callback verification failed (calls=%u, val=%lu)\n",
+ __LINE__, g_set_protocol_callback_calls, g_set_protocol_last_value);
+ test_control_return(1);
+ }
+
+ if (ux_device_class_hid_protocol_get(slave_hid) != UX_DEVICE_CLASS_HID_PROTOCOL_REPORT)
+ {
+ printf("Error on line %d, protocol not set to report\n", __LINE__);
+ test_control_return(1);
+ }
+
+
+ /* Now disconnect the device. */
+ _ux_device_stack_disconnect();
+
+ /* And deinitialize the class. */
+ status = ux_device_stack_class_unregister(_ux_system_slave_class_hid_name, ux_device_class_hid_entry);
+
+ /* Deinitialize the device side of usbx. */
+ _ux_device_stack_uninitialize();
+
+ /* And finally the usbx system resources. */
+ _ux_system_uninitialize();
+
+ /* Successful test. */
+ printf("SUCCESS!\n");
+ test_control_return(0);
+}
+
+static UINT demo_thread_hid_callback(UX_SLAVE_CLASS_HID *class, UX_SLAVE_CLASS_HID_EVENT *event)
+{
+ return(UX_SUCCESS);
+}
+
+static VOID demo_set_protocol_callback(UX_SLAVE_CLASS_HID *hid, ULONG protocol)
+{
+ g_set_protocol_callback_calls++;
+ g_set_protocol_last_value = protocol;
+}
diff --git a/test/regression/usbxtestcontrol.c b/test/regression/usbxtestcontrol.c
index ab6c321..fa6bba6 100644
--- a/test/regression/usbxtestcontrol.c
+++ b/test/regression/usbxtestcontrol.c
@@ -238,6 +238,7 @@ void usbx_ux_host_class_hid_descriptor_parse_test5_application_define(void *)
void usbx_ux_host_class_hid_descriptor_parse_test6_application_define(void *);
void usbx_ux_host_class_hid_descriptor_parse_test7_application_define(void *);
void usbx_ux_host_class_hid_report_descriptor_get_test_application_define(void *);
+void usbx_ux_device_class_hid_set_protocol_callback_test_application_define(void *);
void usbx_ux_host_class_hid_remote_control_callback_test_application_define(void *);
void usbx_ux_host_class_hid_interrupt_endpoint_search_test2_application_define(void *);
void usbx_ux_host_class_hid_periodic_report_start_test2_application_define(void *);
@@ -801,6 +802,7 @@ TEST_ENTRY test_control_tests[] =
usbx_ux_device_class_hid_descriptor_send_test_application_define,
usbx_ux_device_class_hid_entry_test_application_define,
usbx_ux_device_class_hid_event_get_AND_set_test_application_define,
+ usbx_ux_device_class_hid_set_protocol_callback_test_application_define,
usbx_ux_device_class_hid_initialize_test_application_define,
usbx_ux_device_class_hid_interrupt_thread_test_application_define,
usbx_ux_device_class_hid_interrupt_thread_test2_application_define,