GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hid_transfer_request_completed.c Lines: 63 63 100.0 %
Date: 2026-03-06 18:57:10 Branches: 34 34 100.0 %

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
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _ux_host_class_hid_transfer_request_completed       PORTABLE C      */
38
/*                                                           6.2.1        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Chaoqiong Xiao, Microsoft Corporation                               */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function is called by the completion thread when a transfer    */
46
/*    request has been completed either because the transfer is           */
47
/*    successful or there was an error.                                   */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    transfer_request                      Pointer to transfer request   */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    None                                                                */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    (ux_host_class_hid_report_callback_function)                        */
60
/*                                          Callback function for report  */
61
/*    _ux_host_class_hid_report_decompress  Decompress HID report         */
62
/*    _ux_host_stack_transfer_request       Process transfer request      */
63
/*    _ux_utility_memory_allocate           Allocate memory block         */
64
/*    _ux_utility_memory_free               Release memory block          */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    HID Class                                                           */
69
/*                                                                        */
70
/**************************************************************************/
71
1415
VOID  _ux_host_class_hid_transfer_request_completed(UX_TRANSFER *transfer_request)
72
{
73
74
UX_HOST_CLASS_HID                   *hid;
75
UX_HOST_CLASS_HID_CLIENT            *hid_client;
76
UX_HOST_CLASS_HID_REPORT            *hid_report;
77
UINT                                status;
78
VOID                                *report_buffer;
79
UX_HOST_CLASS_HID_REPORT_CALLBACK   callback;
80
UX_HOST_CLASS_HID_CLIENT_REPORT     client_report;
81
ULONG                               *client_buffer;
82
UX_HOST_CLASS_HID_FIELD             *hid_field;
83
ULONG                               field_report_count;
84
85
    /* Set Status to success. Optimistic view.  */
86
1415
    status = UX_SUCCESS;
87
88
    /* Get the class instance for this transfer request.  */
89
1415
    hid =  (UX_HOST_CLASS_HID *) transfer_request -> ux_transfer_request_class_instance;
90
91
    /* Check the state of the transfer.  If there is an error, we do not proceed with this report.  */
92
1415
    if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
93
    {
94
95
        /* We have an error. We do not rehook another transfer if the device instance is shutting down or
96
           if the transfer was aborted by the class.  */
97
131
        if ((hid -> ux_host_class_hid_state ==  UX_HOST_CLASS_INSTANCE_SHUTDOWN) ||
98
10
            (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_ABORT))
99
100
            /* We do not proceed.  */
101
123
            return;
102
103
        else
104
        {
105
106
            /* Reactivate the HID interrupt pipe.  */
107
8
            _ux_host_stack_transfer_request(transfer_request);
108
109
            /* We do not proceed.  */
110
8
            return;
111
        }
112
    }
113
114
    /* Get the client instance attached to the HID.  */
115
1284
    hid_client =  hid -> ux_host_class_hid_client;
116
117
    /* Get the pointer to the report buffer in the transfer request.  */
118
1284
    report_buffer =  transfer_request -> ux_transfer_request_data_pointer;
119
120
    /* We know this incoming report is for the Input report.  */
121
1284
    hid_report =  hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report;
122
123
    /* If there are multiple HID reports, report ID must be checked.  */
124
1284
    if (hid_report -> ux_host_class_hid_report_next_report != UX_NULL)
125
    {
126
127
        /* Scan the reports to find the report expected. */
128
        while(1)
129
        {
130
131
            /* Check report ID at buffer start.  */
132
40
            if (*(UCHAR*)report_buffer == hid_report -> ux_host_class_hid_report_id)
133
15
                break;
134
135
            /* If there is no more report, it's done.  */
136
25
            if (hid_report -> ux_host_class_hid_report_next_report == UX_NULL)
137
2
                break;
138
139
            /* There is more reports, next.  */
140
23
            hid_report = hid_report -> ux_host_class_hid_report_next_report;
141
        }
142
143
        /* Check if the report is what we expected.  */
144
17
        if (*(UCHAR*)report_buffer != hid_report -> ux_host_class_hid_report_id)
145
146
            /* Report not found.  */
147
2
            hid_report = UX_NULL;
148
    }
149
150
    /* For this report to be used, the HID client must have registered
151
       the report. We check the call back function.  */
152
1284
    if ((hid_report != UX_NULL) &&
153
1282
        (hid_report -> ux_host_class_hid_report_callback_function != UX_NULL))
154
    {
155
156
        /* initialize some of the callback structure which are generic to any
157
           reporting method.  */
158
1278
        callback.ux_host_class_hid_report_callback_client =  hid_client;
159
1278
        callback.ux_host_class_hid_report_callback_id =      hid_report -> ux_host_class_hid_report_id;
160
161
        /* The report is now in memory in a raw format the application may desire to handle it that way!  */
162
1278
        if (hid_report -> ux_host_class_hid_report_callback_flags & UX_HOST_CLASS_HID_REPORT_RAW)
163
        {
164
165
            /* Put the length of the report in raw form in the callers callback structure.  */
166
102
            callback.ux_host_class_hid_report_callback_actual_length =  transfer_request -> ux_transfer_request_actual_length;
167
102
            callback.ux_host_class_hid_report_callback_buffer =         report_buffer;
168
169
            /* Build the callback structure status.  */
170
102
            callback.ux_host_class_hid_report_callback_status =  status;
171
172
            /* Set the flags to indicate the type of report.  */
173
102
            callback.ux_host_class_hid_report_callback_flags =  hid_report -> ux_host_class_hid_report_callback_flags;
174
175
            /* Call the report owner.  */
176
102
            hid_report -> ux_host_class_hid_report_callback_function(&callback);
177
        }
178
        else
179
        {
180
181
            /* The report may be decompressed, buffer length is based on number of items in report.
182
               Each item is a pair of words (usage and the value itself), so the required decompress memory for each
183
               item is 4 (word size) * 2 (number of word) = 8 bytes.
184
               To accelerate we shift number of item by 3 to get the result.  */
185
1176
            if (UX_OVERFLOW_CHECK_MULC_ULONG(hid_report->ux_host_class_hid_report_number_item, 8))
186
6
                client_buffer = UX_NULL;
187
            else
188
            {
189
1170
                client_report.ux_host_class_hid_client_report_length = hid_report->ux_host_class_hid_report_number_item << 3;
190
191
                /* We need to allocate some memory to build the decompressed report.  */
192
1170
                client_buffer =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, client_report.ux_host_class_hid_client_report_length);
193
            }
194
195
            /* Check completion status.  */
196
1176
            if (client_buffer == UX_NULL)
197
            {
198
                /* We have an error of memory, do not proceed */
199
7
                status =  UX_MEMORY_INSUFFICIENT;
200
            }
201
            else
202
            {
203
204
                /* We need to build a client structure to be used by the decompression engine.  */
205
1169
                client_report.ux_host_class_hid_client_report_buffer =         client_buffer;
206
1169
                client_report.ux_host_class_hid_client_report_actual_length =  0;
207
1169
                client_report.ux_host_class_hid_client_report =                hid_report;
208
209
                /* The report buffer must be parsed and decompressed into the local buffer.  */
210
1169
                _ux_host_class_hid_report_decompress(hid, &client_report, report_buffer, transfer_request -> ux_transfer_request_actual_length);
211
212
                /* The report may be decompressed and returned as individual Usages.  */
213
1169
                if (hid_report -> ux_host_class_hid_report_callback_flags & UX_HOST_CLASS_HID_REPORT_INDIVIDUAL_USAGE)
214
                {
215
216
                    /* Now, we need to call the HID client call back function with a usage/value couple.  */
217
338
                    hid_field =  hid_report -> ux_host_class_hid_report_field;
218
219
                    /* Set the flags to indicate the type of report (usage/value couple).  */
220
338
                    callback.ux_host_class_hid_report_callback_flags =  hid_report -> ux_host_class_hid_report_callback_flags;
221
222
                    /* The length of the buffer is irrelevant here so we reset it.  */
223
338
                    callback.ux_host_class_hid_report_callback_actual_length =  0;
224
225
                    /* Scan all the fields and send each usage/value.   */
226
948
                    while(hid_field != UX_NULL)
227
                    {
228
229
                        /* Build each report item.  */
230
1492
                        for (field_report_count = 0; field_report_count < hid_field -> ux_host_class_hid_field_report_count; field_report_count++)
231
                        {
232
233
                            /* Insert the usage and the report value into the callback structure.  */
234
882
                            callback.ux_host_class_hid_report_callback_usage =  *client_report.ux_host_class_hid_client_report_buffer++;
235
882
                            callback.ux_host_class_hid_report_callback_value =  *client_report.ux_host_class_hid_client_report_buffer++;
236
237
                            /* Build the callback structure status.  */
238
882
                            callback.ux_host_class_hid_report_callback_status =  status;
239
240
                            /* Call the report owner */
241
882
                            hid_report -> ux_host_class_hid_report_callback_function(&callback);
242
                        }
243
244
                        /* Get the next field.  */
245
610
                        hid_field =  hid_field -> ux_host_class_hid_field_next_field;
246
                    }
247
                }
248
                else
249
                {
250
251
                    /* Add the length actually valid in the caller's buffer.  */
252
831
                    callback.ux_host_class_hid_report_callback_actual_length =  client_report.ux_host_class_hid_client_report_actual_length;
253
254
                    /* Add the caller's buffer address.  */
255
831
                    callback.ux_host_class_hid_report_callback_buffer =  client_report.ux_host_class_hid_client_report_buffer;
256
257
                    /* Build the callback structure status.  */
258
831
                    callback.ux_host_class_hid_report_callback_status =  status;
259
260
                    /* Set the flags to indicate the type of report.  */
261
831
                    callback.ux_host_class_hid_report_callback_flags =  hid_report -> ux_host_class_hid_report_callback_flags;
262
263
                    /* Call the report owner.  */
264
831
                    hid_report -> ux_host_class_hid_report_callback_function(&callback);
265
                }
266
267
                /* Free the memory resource we used.  */
268
1169
                _ux_utility_memory_free(client_buffer);
269
            }
270
        }
271
    }
272
273
    /* Check latest status.  */
274
1284
    if (status != UX_SUCCESS)
275
276
        /* Error trap. */
277
7
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
278
279
    /* Reactivate the HID interrupt pipe.  */
280
1284
    status =  _ux_host_stack_transfer_request(transfer_request);
281
282
    /* Check latest status.  */
283
1284
    if (status != UX_SUCCESS)
284
285
        /* Error trap. */
286
9
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
287
288
    /* Return to caller.  */
289
1284
    return;
290
}
291