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 add018e5..f5a48f4a 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 5569ba1b..ccc47e87 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 94d7f016..5b6e4f02 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 47420899..11083a22 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 b10f6055..94cf2611 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 00000000..54c1d6ff --- /dev/null +++ b/common/usbx_host_classes/src/ux_host_class_hid_protocol_get.c @@ -0,0 +1,142 @@ +/*************************************************************************** + * 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) +{ + +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); + } + + _ux_utility_memory_set(protocol, 0, sizeof(USHORT)); + + /* 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; + +#if !defined(UX_HOST_STANDALONE) + + /* Protect thread reentry to this instance. */ + status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); + if (status != UX_SUCCESS) + return(status); + +#endif + + /* Create a transfer request for the GET_PROTOCOL request. */ + transfer_request -> ux_transfer_request_data_pointer = (UCHAR *) protocol; + 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) + /* Unprotect thread reentry to this instance. */ + _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 00000000..1a4a4c48 --- /dev/null +++ b/common/usbx_host_classes/src/ux_host_class_hid_protocol_set.c @@ -0,0 +1,145 @@ +/*************************************************************************** + * 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) +{ + +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; + +#if !defined(UX_HOST_STANDALONE) + + /* Protect thread reentry to this instance. */ + status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_semaphore, UX_WAIT_FOREVER); + if (status != UX_SUCCESS) + return(status); + +#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) + /* 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 29927655..729559c4 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 00000000..b1c0e710 --- /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 +#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 ab6c3213..fa6bba6f 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,