summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-06-04 15:45:21 -0400
committerGitHub <[email protected]>2026-06-04 15:45:21 -0400
commit94cdd1e0e34573dac3f2c5dadb1c4f68a2857435 (patch)
tree7b665c728dba50d8dbba5328aee310ef3685ca29
parent35927220c0165c06dc90e6c9aa7a8eb9b5806065 (diff)
Fixed standalone locking bugs in HID host idle get/set (#264)
Two issues discovered while reviewing and fixing thread-safety issues in the new ux_host_class_hid_protocol_get/set functions (PR #244). 1. idle_get.c: wrong operator acquires no lock in standalone mode Line 104 used '&= ~UX_HOST_CLASS_HID_FLAG_LOCK' (the release/clear operation) instead of '|= UX_HOST_CLASS_HID_FLAG_LOCK' (acquire/set). The preceding check correctly returns UX_BUSY when the flag is set, but the follow-on line then immediately clears it instead of setting it. The net effect is that the HID instance is never actually locked in UX_HOST_STANDALONE mode, making the mutual-exclusion check a no-op. 2. idle_set.c: standalone path used a blocking spin-loop The standalone branch called _ux_host_class_hid_idle_set_run() in a do/while loop, blocking the caller until the transfer completed. This is inconsistent with every other inline HID control-transfer function (idle_get, report_get, report_set, protocol_get, protocol_set) which all use the direct UX_DISABLE/UX_RESTORE atomic flag pattern and return UX_BUSY if the instance or device endpoint is already locked. Replaced with the same inline standalone locking pattern used by the other functions: atomic HID FLAG_LOCK acquire, atomic DEVICE_FLAG_LOCK acquire with AUTO_DEVICE_UNLOCK + UX_TRANSFER_STATE_RESET, and an AUTO_WAIT check at completion consistent with idle_get behavior. Co-authored-by: Copilot <[email protected]>
-rw-r--r--common/usbx_host_classes/src/ux_host_class_hid_idle_get.c2
-rw-r--r--common/usbx_host_classes/src/ux_host_class_hid_idle_set.c49
2 files changed, 35 insertions, 16 deletions
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_idle_get.c b/common/usbx_host_classes/src/ux_host_class_hid_idle_get.c
index e120884..e39f988 100644
--- a/common/usbx_host_classes/src/ux_host_class_hid_idle_get.c
+++ b/common/usbx_host_classes/src/ux_host_class_hid_idle_get.c
@@ -101,7 +101,7 @@ UINT status;
UX_RESTORE
return(UX_BUSY);
}
- hid -> ux_host_class_hid_flags &= ~UX_HOST_CLASS_HID_FLAG_LOCK;
+ hid -> ux_host_class_hid_flags |= UX_HOST_CLASS_HID_FLAG_LOCK;
UX_RESTORE
#else
diff --git a/common/usbx_host_classes/src/ux_host_class_hid_idle_set.c b/common/usbx_host_classes/src/ux_host_class_hid_idle_set.c
index fe74deb..1611e91 100644
--- a/common/usbx_host_classes/src/ux_host_class_hid_idle_set.c
+++ b/common/usbx_host_classes/src/ux_host_class_hid_idle_set.c
@@ -69,14 +69,8 @@
UINT _ux_host_class_hid_idle_set(UX_HOST_CLASS_HID *hid, USHORT idle_time, USHORT report_id)
{
#if defined(UX_HOST_STANDALONE)
-UINT status;
- do
- {
- status = _ux_host_class_hid_idle_set_run(hid, idle_time, report_id);
- } while(status == UX_STATE_WAIT || status == UX_STATE_LOCK);
- return(hid -> ux_host_class_hid_status);
-#else
-
+UX_INTERRUPT_SAVE_AREA
+#endif
UX_ENDPOINT *control_endpoint;
UX_TRANSFER *transfer_request;
UINT status;
@@ -99,6 +93,16 @@ UINT status;
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);
@@ -106,17 +110,27 @@ UINT 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);
-
- /* Check for status. */
if (status != UX_SUCCESS)
{
-
- /* Something went wrong. */
- /* Unprotect thread reentry to this instance. */
_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_IDLE request. */
transfer_request -> ux_transfer_request_data_pointer = UX_NULL;
@@ -129,12 +143,17 @@ UINT status;
/* 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);
-#endif
}
/**************************************************************************/