GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hid_report_set.c Lines: 51 55 92.7 %
Date: 2026-03-06 18:57:10 Branches: 24 28 85.7 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** USBX Component                                                        */
17
/**                                                                       */
18
/**   HID Class                                                           */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
24
/* Include necessary system files.  */
25
26
#define UX_SOURCE_CODE
27
28
#include "ux_api.h"
29
#include "ux_host_class_hid.h"
30
#include "ux_host_stack.h"
31
32
33
#if !defined(UX_HOST_STANDALONE)
34
35
/* Inline the function to let compiler optimize.  */
36
static inline
37
#else
38
39
/* Prototype the function to remove warnings.  */
40
UINT ux_host_class_hid_report_set_buffer_allocate(
41
        UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report,
42
        UCHAR **allocated);
43
#endif
44
169
UINT ux_host_class_hid_report_set_buffer_allocate(
45
        UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report,
46
        UCHAR **allocated)
47
{
48
49
UX_HOST_CLASS_HID_REPORT    *hid_report;
50
UCHAR                       *report_buffer;
51
UCHAR                       *current_report_buffer;
52
53
    /* Get the report pointer from the caller.  */
54
169
    hid_report =  client_report -> ux_host_class_hid_client_report;
55
56
    /* Ensure this is NOT an INPUT report.  */
57
169
    if (hid_report -> ux_host_class_hid_report_type == UX_HOST_CLASS_HID_REPORT_TYPE_INPUT)
58
    {
59
60
        /* Return error code.  */
61
1
        return(UX_HOST_CLASS_HID_REPORT_ERROR);
62
    }
63
64
    /* Get some memory for sending the report.  */
65
168
    if (hid_report -> ux_host_class_hid_report_id == 0)
66
160
        report_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, hid_report -> ux_host_class_hid_report_byte_length);
67
    else
68
8
        report_buffer =  _ux_utility_memory_allocate_add_safe(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, hid_report -> ux_host_class_hid_report_byte_length, 1);
69
168
    if (report_buffer == UX_NULL)
70
    {
71
72
        /* Return error code.  */
73
3
        return(UX_MEMORY_INSUFFICIENT);
74
    }
75
76
    /* Memorize the start of the real report buffer.  */
77
165
    current_report_buffer =  report_buffer;
78
79
    /* Check if there is a report ID to be inserted in front of the buffer.  */
80
165
    if (hid_report -> ux_host_class_hid_report_id != 0)
81
8
        *current_report_buffer++ =  (UCHAR)(hid_report -> ux_host_class_hid_report_id);
82
83
    /* The report is in the client's buffer. It may be raw or or decompressed. If decompressed,
84
       we need to create the report.  */
85
165
    if (client_report -> ux_host_class_hid_client_report_flags & UX_HOST_CLASS_HID_REPORT_RAW)
86
    {
87
88
        /* Ensure the user is not trying to overflow the report buffer.  */
89
162
        if (hid_report -> ux_host_class_hid_report_byte_length >= client_report -> ux_host_class_hid_client_report_length)
90
        {
91
92
            /* We have enough memory to store the raw buffer.  */
93
161
            _ux_utility_memory_copy(current_report_buffer, client_report -> ux_host_class_hid_client_report_buffer, hid_report -> ux_host_class_hid_report_byte_length); /* Use case of memcpy is verified. */
94
        }
95
        else
96
        {
97
98
            /* Free allocated buffer.  */
99
1
            _ux_utility_memory_free(report_buffer);
100
101
            /* Return error code.  */
102
1
            return(UX_HOST_CLASS_HID_REPORT_OVERFLOW);
103
        }
104
    }
105
    else
106
    {
107
108
        /* The report buffer has to be compressed.  */
109
3
        _ux_host_class_hid_report_compress(hid, client_report, current_report_buffer, client_report -> ux_host_class_hid_client_report_length);
110
    }
111
112
    /* Buffer is allocated and report data copied.  */
113
164
    *allocated = report_buffer;
114
164
    return(UX_SUCCESS);
115
}
116
117
/**************************************************************************/
118
/*                                                                        */
119
/*  FUNCTION                                               RELEASE        */
120
/*                                                                        */
121
/*    _ux_host_class_hid_report_set                       PORTABLE C      */
122
/*                                                           6.1.10       */
123
/*  AUTHOR                                                                */
124
/*                                                                        */
125
/*    Chaoqiong Xiao, Microsoft Corporation                               */
126
/*                                                                        */
127
/*  DESCRIPTION                                                           */
128
/*                                                                        */
129
/*    This function sets a report (input/output/feature) to the device.   */
130
/*    The report can be either decompressed by the stack or raw.          */
131
/*                                                                        */
132
/*  INPUT                                                                 */
133
/*                                                                        */
134
/*    hid                                   Pointer to HID class          */
135
/*    client_report                         Pointer to client report      */
136
/*                                                                        */
137
/*  OUTPUT                                                                */
138
/*                                                                        */
139
/*    Completion Status                                                   */
140
/*                                                                        */
141
/*  CALLS                                                                 */
142
/*                                                                        */
143
/*    _ux_host_class_hid_report_compress    Compress HID report           */
144
/*    _ux_host_stack_class_instance_verify  Verify the instance is valid  */
145
/*    _ux_host_stack_transfer_request       Process transfer request      */
146
/*    _ux_utility_memory_allocate           Allocate memory block         */
147
/*    _ux_utility_memory_copy               Copy memory block             */
148
/*    _ux_utility_memory_free               Release memory block          */
149
/*    _ux_host_semaphore_get                Get protection semaphore      */
150
/*    _ux_host_semaphore_put                Release protection semaphore  */
151
/*                                                                        */
152
/*  CALLED BY                                                             */
153
/*                                                                        */
154
/*    Application                                                         */
155
/*    HID Class                                                           */
156
/*                                                                        */
157
/**************************************************************************/
158
172
UINT  _ux_host_class_hid_report_set(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report)
159
{
160
#if defined(UX_HOST_STANDALONE)
161
UINT                    status;
162
    do
163
    {
164
        status = _ux_host_class_hid_report_set_run(hid, client_report);
165
    } while(status == UX_STATE_WAIT || status == UX_STATE_LOCK);
166
    return(hid -> ux_host_class_hid_status);
167
#else
168
169
UX_ENDPOINT                 *control_endpoint;
170
UX_TRANSFER                 *transfer_request;
171
UCHAR                       *report_buffer;
172
UX_HOST_CLASS_HID_REPORT    *hid_report;
173
UINT                        status;
174
175
    /* If trace is enabled, insert this event into the trace buffer.  */
176
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HID_REPORT_SET, hid, client_report, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
177
178
    /* Ensure the instance is valid.  */
179
172
    if (_ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, (VOID *) hid) != UX_SUCCESS)
180
    {
181
182
        /* Error trap. */
183
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
184
185
        /* If trace is enabled, insert this event into the trace buffer.  */
186
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
187
188
1
        return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
189
    }
190
191
    /* Protect thread reentry to this instance.  */
192
171
    _ux_host_class_hid_lock_fail_return(hid);
193
194
    /* Get the report pointer from the caller.  */
195
170
    hid_report =  client_report -> ux_host_class_hid_client_report;
196
#if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
197
198
    /* Check if there is an interrupt OUT endpoint.  */
199
    if (hid -> ux_host_class_hid_interrupt_out_endpoint != UX_NULL)
200
    {
201
202
        /* Transfer the report by using the interrupt OUT endpoint.  */
203
        transfer_request = &hid -> ux_host_class_hid_interrupt_out_endpoint -> ux_endpoint_transfer_request;
204
    }
205
    else
206
    {
207
#endif
208
        /* We need to get the default control endpoint transfer request pointer.  */
209
170
        control_endpoint =  &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
210
170
        transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
211
212
        /* Protect the control endpoint semaphore here.  It will be unprotected in the
213
           transfer request function.  */
214
170
        status =  _ux_host_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
215
216
        /* Check for status.  */
217
170
        if (status != UX_SUCCESS)
218
        {
219
220
            /* Something went wrong. */
221
            /* Unprotect thread reentry to this instance.  */
222
1
            _ux_host_class_hid_unlock(hid);
223
1
            return(status);
224
        }
225
#if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
226
    }
227
#endif
228
    /* Build the report buffer for SET_REPORT request.  */
229
169
    status = ux_host_class_hid_report_set_buffer_allocate(hid, client_report, &report_buffer);
230
169
    if (status != UX_SUCCESS)
231
    {
232
233
        /* Unlock device control endpoint.  */
234
5
        _ux_host_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore);
235
236
        /* Unprotect thread reentry to this instance.  */
237
5
        _ux_host_class_hid_unlock(hid);
238
239
        /* Error trap. */
240
5
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
241
242
        /* If trace is enabled, insert this event into the trace buffer.  */
243
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, status, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
244
245
5
        return(status);
246
    }
247
248
    /* Create a transfer request for the SET_REPORT request.  */
249
164
    transfer_request -> ux_transfer_request_data_pointer =      report_buffer;
250
164
    transfer_request -> ux_transfer_request_requested_length =  hid_report -> ux_host_class_hid_report_byte_length;
251
164
    transfer_request -> ux_transfer_request_function =          UX_HOST_CLASS_HID_SET_REPORT;
252
164
    transfer_request -> ux_transfer_request_type =              UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
253
164
    transfer_request -> ux_transfer_request_value =             (UINT)((USHORT) hid_report -> ux_host_class_hid_report_id | (USHORT) hid_report -> ux_host_class_hid_report_type << 8);
254
164
    transfer_request -> ux_transfer_request_index =             hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber;
255
256
    /* Send request to HCD layer.  */
257
164
    status =  _ux_host_stack_transfer_request(transfer_request);
258
#if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
259
260
    /* Check if interrupt OUT endpoint is used.  */
261
    if ((hid -> ux_host_class_hid_interrupt_out_endpoint != UX_NULL) && (status == UX_SUCCESS))
262
    {
263
264
        /* We need to wait for the completion of the transfer request.  */
265
        status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_HID_REPORT_TRANSFER_TIMEOUT));
266
    }
267
#endif
268
269
    /* Check for correct transfer and the actual transfer length.  */
270

164
    if ((status != UX_SUCCESS) || (transfer_request -> ux_transfer_request_actual_length != hid_report -> ux_host_class_hid_report_byte_length))
271
    {
272
#if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
273
274
        /* Check if interrupt OUT endpoint is used.  */
275
        if ((hid -> ux_host_class_hid_interrupt_out_endpoint != UX_NULL) && (status != UX_SUCCESS))
276
        {
277
278
            /* We need to abort the transfer request.  */
279
            _ux_host_stack_transfer_request_abort(transfer_request);
280
        }
281
#endif
282
283
        /* Error trap. */
284
4
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_HID_REPORT_ERROR);
285
286
        /* If trace is enabled, insert this event into the trace buffer.  */
287
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
288
289
4
        status =  UX_HOST_CLASS_HID_REPORT_ERROR;
290
    }
291
292
    /* Free all resources.  */
293
164
    _ux_utility_memory_free(report_buffer);
294
295
    /* Unprotect thread reentry to this instance.  */
296
164
    _ux_host_class_hid_unlock(hid);
297
298
    /* Return the function status */
299
164
    return(status);
300
#endif
301
}
302
303
/**************************************************************************/
304
/*                                                                        */
305
/*  FUNCTION                                               RELEASE        */
306
/*                                                                        */
307
/*    _uxe_host_class_hid_report_set                      PORTABLE C      */
308
/*                                                           6.3.0        */
309
/*  AUTHOR                                                                */
310
/*                                                                        */
311
/*    Chaoqiong Xiao, Microsoft Corporation                               */
312
/*                                                                        */
313
/*  DESCRIPTION                                                           */
314
/*                                                                        */
315
/*    This function checks errors in HID report set function call.        */
316
/*                                                                        */
317
/*  INPUT                                                                 */
318
/*                                                                        */
319
/*    hid                                   Pointer to HID class          */
320
/*    client_report                         Pointer to client report      */
321
/*                                                                        */
322
/*  OUTPUT                                                                */
323
/*                                                                        */
324
/*    Status                                                              */
325
/*                                                                        */
326
/*  CALLS                                                                 */
327
/*                                                                        */
328
/*    _ux_host_class_hid_report_set         Set a report                  */
329
/*                                                                        */
330
/*  CALLED BY                                                             */
331
/*                                                                        */
332
/*    Application                                                         */
333
/*                                                                        */
334
/**************************************************************************/
335
UINT  _uxe_host_class_hid_report_set(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report)
336
{
337
338
    /* Sanity checks.  */
339
    if ((hid == UX_NULL) || (client_report == UX_NULL))
340
        return(UX_INVALID_PARAMETER);
341
342
    /* Invoke report set function.  */
343
    return(_ux_host_class_hid_report_set(hid, client_report));
344
}