1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** USBX Component */
15 /** */
16 /** Device HID Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_hid.h"
28 #include "ux_device_stack.h"
29
30
31 #if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) && !defined(UX_DEVICE_STANDALONE)
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_device_class_hid_receiver_thread PORTABLE C */
37 /* 6.3.0 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the thread of the hid interrupt OUT endpoint */
45 /* */
46 /* INPUT */
47 /* */
48 /* hid_class Address of hid class */
49 /* container */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* None */
54 /* */
55 /* CALLS */
56 /* */
57 /* _ux_utility_event_flags_get Get event flags */
58 /* _ux_device_stack_transfer_request Request transfer */
59 /* _ux_utility_memory_copy Copy memory */
60 /* _ux_utility_thread_suspend Suspend thread */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* ThreadX */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
71 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
72 /* added receiver callback, */
73 /* resulting in version 6.1.11 */
74 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
75 /* added zero copy support, */
76 /* resulting in version 6.3.0 */
77 /* */
78 /**************************************************************************/
_ux_device_class_hid_receiver_thread(ULONG hid_instance)79 VOID _ux_device_class_hid_receiver_thread(ULONG hid_instance)
80 {
81
82 UX_SLAVE_CLASS_HID *hid;
83 UX_SLAVE_DEVICE *device;
84 UX_DEVICE_CLASS_HID_RECEIVER *receiver;
85 UX_DEVICE_CLASS_HID_RECEIVED_EVENT *pos;
86 UCHAR *next_pos;
87 UX_SLAVE_TRANSFER *transfer;
88 UINT status;
89 UCHAR *buffer;
90 ULONG temp;
91
92
93 /* Cast properly the hid instance. */
94 UX_THREAD_EXTENSION_PTR_GET(hid, UX_SLAVE_CLASS_HID, hid_instance)
95
96 /* Get the pointer to the device. */
97 device = &_ux_system_slave -> ux_system_slave_device;
98
99 /* Get receiver instance. */
100 receiver = hid -> ux_device_class_hid_receiver;
101
102 /* This thread runs forever but can be suspended or resumed. */
103 while(1)
104 {
105
106 /* Check device state. */
107 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
108 {
109
110 /* We need to suspend ourselves. We will be resumed by the device enumeration module. */
111 _ux_utility_thread_suspend(&receiver -> ux_device_class_hid_receiver_thread);
112 continue;
113 }
114
115 /* Protect read. */
116 _ux_device_mutex_on(&hid -> ux_device_class_hid_read_mutex);
117
118 /* Check if there is buffer available. */
119 pos = receiver -> ux_device_class_hid_receiver_event_save_pos;
120 if (pos -> ux_device_class_hid_received_event_length != 0)
121 {
122
123 /* Wait before check again. */
124 status = _ux_utility_event_flags_get(
125 &hid -> ux_device_class_hid_event_flags_group,
126 UX_DEVICE_CLASS_HID_RECEIVER_RESTART,
127 UX_OR_CLEAR, &temp, 100);
128 if (status != UX_SUCCESS)
129 {
130
131 /* Keep checking before a good state. */
132 _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
133 continue;
134 }
135 }
136
137 /* Event buffer available, issue request to get data. */
138 transfer = &hid -> ux_device_class_hid_read_endpoint -> ux_slave_endpoint_transfer_request;
139
140 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
141
142 /* Directly use event buffer for transfer. */
143 buffer = pos -> ux_device_class_hid_received_event_data;
144 transfer -> ux_slave_transfer_request_data_pointer = buffer;
145 #endif
146
147 /* Issue the transfer request. */
148 status = _ux_device_stack_transfer_request(transfer,
149 receiver -> ux_device_class_hid_receiver_event_buffer_size,
150 receiver -> ux_device_class_hid_receiver_event_buffer_size);
151
152 /* Check status and ignore ZLPs. */
153 if ((status != UX_SUCCESS) ||
154 (transfer -> ux_slave_transfer_request_actual_length == 0))
155 {
156 _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
157 continue;
158 }
159
160 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
161
162 /* Save received event length. */
163 temp = transfer -> ux_slave_transfer_request_actual_length;
164 #else
165 /* Save received event data and length. */
166 buffer = (UCHAR *)&pos -> ux_device_class_hid_received_event_data;
167 temp = transfer -> ux_slave_transfer_request_actual_length;
168 _ux_utility_memory_copy(buffer,
169 transfer -> ux_slave_transfer_request_data_pointer,
170 temp); /* Use case of memcpy is verified. */
171 #endif
172
173 /* Unprotect read. */
174 _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
175
176 /* Advance the save position. */
177 next_pos = (UCHAR *)pos + UX_DEVICE_CLASS_HID_RECEIVED_QUEUE_ITEM_SIZE(receiver);
178
179 if (next_pos >= (UCHAR *)receiver -> ux_device_class_hid_receiver_events_end)
180 next_pos = (UCHAR *)receiver -> ux_device_class_hid_receiver_events;
181 receiver -> ux_device_class_hid_receiver_event_save_pos = (UX_DEVICE_CLASS_HID_RECEIVED_EVENT *)next_pos;
182
183 /* Save received data length (it's valid now). */
184 pos -> ux_device_class_hid_received_event_length = temp;
185
186 /* Notify application that a event is received. */
187 if (receiver -> ux_device_class_hid_receiver_event_callback)
188 receiver -> ux_device_class_hid_receiver_event_callback(hid);
189 }
190 }
191 #endif
192