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: 2024-12-12 17:16:36 Branches: 24 28 85.7 %

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

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