GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_control_request_process.c Lines: 88 88 100.0 %
Date: 2026-03-06 18:57:10 Branches: 54 54 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
/**   Device Stack                                                        */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define UX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "ux_api.h"
29
#include "ux_device_stack.h"
30
31
/**************************************************************************/
32
/*                                                                        */
33
/*  FUNCTION                                               RELEASE        */
34
/*                                                                        */
35
/*    _ux_device_stack_control_request_process            PORTABLE C      */
36
/*                                                           6.3.0        */
37
/*  AUTHOR                                                                */
38
/*                                                                        */
39
/*    Chaoqiong Xiao, Microsoft Corporation                               */
40
/*                                                                        */
41
/*  DESCRIPTION                                                           */
42
/*                                                                        */
43
/*    This function is called by the DCD when the device has received a   */
44
/*    SETUP packet.                                                       */
45
/*                                                                        */
46
/*  INPUT                                                                 */
47
/*                                                                        */
48
/*    transfer_request                      Pointer to transfer request   */
49
/*                                                                        */
50
/*  OUTPUT                                                                */
51
/*                                                                        */
52
/*    Completion Status                                                   */
53
/*                                                                        */
54
/*  CALLS                                                                 */
55
/*                                                                        */
56
/*    (ux_slave_class_entry_function)       Device class entry function   */
57
/*    (ux_slave_dcd_function)               DCD dispatch function         */
58
/*    _ux_device_stack_transfer_request     Transfer request              */
59
/*    _ux_device_stack_endpoint_stall       Stall endpoint                */
60
/*    _ux_device_stack_alternate_setting_get                              */
61
/*                                          Get alternate settings        */
62
/*    _ux_device_stack_alternate_setting_set                              */
63
/*                                          Set alternate settings        */
64
/*    _ux_device_stack_clear_feature        Clear feature                 */
65
/*    _ux_device_stack_configuration_get    Get configuration             */
66
/*    _ux_device_stack_configuration_set    Set configuration             */
67
/*    _ux_device_stack_descriptor_send      Send descriptor               */
68
/*    _ux_device_stack_get_status           Get status                    */
69
/*    _ux_device_stack_set_feature          Set feature                   */
70
/*    _ux_utility_short_get                 Get short value               */
71
/*                                                                        */
72
/*  CALLED BY                                                             */
73
/*                                                                        */
74
/*    Device Stack                                                        */
75
/*                                                                        */
76
/**************************************************************************/
77
10821
UINT  _ux_device_stack_control_request_process(UX_SLAVE_TRANSFER *transfer_request)
78
{
79
80
UX_SLAVE_DCD                *dcd;
81
UX_SLAVE_DEVICE             *device;
82
UX_SLAVE_CLASS              *class_ptr;
83
UX_SLAVE_CLASS_COMMAND      class_command;
84
ULONG                       request_type;
85
ULONG                       request;
86
ULONG                       request_value;
87
ULONG                       request_index;
88
ULONG                       request_length;
89
ULONG                       class_index;
90
10821
UINT                        status =  UX_ERROR;
91
UX_SLAVE_ENDPOINT           *endpoint;
92
ULONG                       application_data_length;
93
94
    /* Get the pointer to the DCD.  */
95
10821
    dcd =  &_ux_system_slave -> ux_system_slave_dcd;
96
97
    /* Get the pointer to the device.  */
98
10821
    device =  &_ux_system_slave -> ux_system_slave_device;
99
100
    /* Ensure that the Setup request has been received correctly.  */
101
10821
    if (transfer_request -> ux_slave_transfer_request_completion_code == UX_SUCCESS)
102
    {
103
104
        /* Seems so far, the Setup request is valid. Extract all fields of
105
           the request.  */
106
10820
        request_type   =   *transfer_request -> ux_slave_transfer_request_setup;
107
10820
        request        =   *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
108
10820
        request_value  =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE);
109
10820
        request_index  =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_INDEX);
110
10820
        request_length =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
111
112
        /* Filter for GET_DESCRIPTOR/SET_DESCRIPTOR commands. If the descriptor to be returned is not a standard descriptor,
113
           treat the command as a CLASS command.  */
114

10820
        if ((request == UX_GET_DESCRIPTOR || request == UX_SET_DESCRIPTOR) && (((request_value >> 8) & UX_REQUEST_TYPE) != UX_REQUEST_TYPE_STANDARD))
115
        {
116
117
            /* This request is to be handled by the class layer.  */
118
545
            request_type &=  (UINT)~UX_REQUEST_TYPE;
119
545
            request_type |= UX_REQUEST_TYPE_CLASS;
120
        }
121
122
        /* Check if there is a vendor registered function at the application layer.  If the request
123
           is VENDOR and the request match, pass the request to the application.  */
124
10820
        if ((request_type & UX_REQUEST_TYPE) == UX_REQUEST_TYPE_VENDOR)
125
        {
126
127
            /* Check the request demanded and compare it to the application registered one.  */
128
7
            if (_ux_system_slave -> ux_system_slave_device_vendor_request_function != UX_NULL &&
129
6
                request == _ux_system_slave -> ux_system_slave_device_vendor_request)
130
            {
131
132
                /* This is a Microsoft extended function. It happens before the device is configured.
133
                   The request is passed to the application directly.  */
134
4
                application_data_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH;
135
4
                status = _ux_system_slave -> ux_system_slave_device_vendor_request_function(request, request_value,
136
                                                                                            request_index, request_length,
137
                                                                                            transfer_request -> ux_slave_transfer_request_data_pointer,
138
                                                                                            &application_data_length);
139
140
                /* Check the status from the application.  */
141
4
                if (status == UX_SUCCESS)
142
                {
143
144
                    /* Get the control endpoint associated with the device.  */
145
2
                    endpoint =  &device -> ux_slave_device_control_endpoint;
146
147
                    /* Get the pointer to the transfer request associated with the control endpoint.  */
148
2
                    transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
149
150
                    /* Set the direction to OUT.  */
151
2
                    transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
152
153
                    /* Perform the data transfer.  */
154
2
                    _ux_device_stack_transfer_request(transfer_request, application_data_length, request_length);
155
156
                    /* We are done here.  */
157
2
                    return(UX_SUCCESS);
158
                }
159
                else
160
                {
161
162
                    /* The application did not like the vendor command format, stall the control endpoint.  */
163
2
                    _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
164
165
                    /* We are done here.  */
166
2
                    return(UX_SUCCESS);
167
                }
168
            }
169
        }
170
171
        /* Check the destination of the request. If the request is of type CLASS or VENDOR_SPECIFIC,
172
           the function has to be passed to the class layer.  */
173
10816
        if (((request_type & UX_REQUEST_TYPE) == UX_REQUEST_TYPE_CLASS) ||
174
8733
            ((request_type & UX_REQUEST_TYPE) == UX_REQUEST_TYPE_VENDOR))
175
        {
176
177
            /* Build all the fields of the Class Command.  */
178
2086
            class_command.ux_slave_class_command_request =  UX_SLAVE_CLASS_COMMAND_REQUEST;
179
180
            /* We need to find which class this request is for.  */
181
4130
            for (class_index = 0; class_index < UX_MAX_SLAVE_INTERFACES; class_index ++)
182
            {
183
184
                /* Get the class for the interface.  */
185
4065
                class_ptr =  _ux_system_slave -> ux_system_slave_interface_class_array[class_index];
186
187
                /* If class is not ready, try next.  */
188
4065
                if (class_ptr == UX_NULL)
189
1672
                    continue;
190
191
                /* Is the request target to an interface?  */
192
2393
                if ((request_type & UX_REQUEST_TARGET) == UX_REQUEST_TARGET_INTERFACE)
193
                {
194
195
                    /* Yes, so the request index contains the index of the interface
196
                       the request is for. So if the current index does not match
197
                       the request index, we should go to the next one.  */
198
                    /* For printer class (0x07) GET_DEVICE_ID (0x00) the high byte of
199
                       wIndex is interface index (for recommended index sequence the interface
200
                       number is same as interface index inside configuration).
201
                     */
202

2096
                    if ((request_type == 0xA1) && (request == 0x00) &&
203
34
                        (class_ptr -> ux_slave_class_interface -> ux_slave_interface_descriptor.bInterfaceClass == 0x07))
204
                    {
205
206
                        /* Check wIndex high byte.  */
207
16
                        if(*(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_INDEX + 1) != class_index)
208
5
                            continue;
209
                    }
210
                    else
211
                    {
212
213
                        /* Check wIndex low.  */
214
2080
                        if ((request_index & 0xFF) != class_index)
215
338
                            continue;
216
                    }
217
                }
218
219
                /* Memorize the class in the command.  */
220
2050
                class_command.ux_slave_class_command_class_ptr = class_ptr;
221
222
                /* We have found a potential candidate. Call this registered class entry function.  */
223
2050
                status = class_ptr -> ux_slave_class_entry_function(&class_command);
224
225
                /* The status simply tells us if the registered class handled the
226
                   command - if there was an issue processing the command, it would've
227
                   stalled the control endpoint, notifying the host (and not us).  */
228
2050
                if (status == UX_SUCCESS)
229
230
                    /* We are done, break the loop!  */
231
2021
                    break;
232
233
                /* Not handled, try next.  */
234
            }
235
236
            /* If no class handled the command, then we have an error here.  */
237
2086
            if (status != UX_SUCCESS)
238
239
                /* We stall the command (request not supported).  */
240
65
                _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
241
242
            /* We are done for class/vendor request.  */
243
2086
            return(status);
244
        }
245
246
        /* At this point, the request must be a standard request that the device stack should handle.  */
247



8730
        switch (request)
248
        {
249
250
221
        case UX_GET_STATUS:
251
252
221
            status =  _ux_device_stack_get_status(request_type, request_index, request_length);
253
221
            break;
254
255
1426
        case UX_CLEAR_FEATURE:
256
257
1426
            status =  _ux_device_stack_clear_feature(request_type, request_value, request_index);
258
1426
            break;
259
260
9
        case UX_SET_FEATURE:
261
262
9
            status =  _ux_device_stack_set_feature(request_type, request_value, request_index);
263
9
            break;
264
265
1070
        case UX_SET_ADDRESS:
266
267
            /* Memorize the address. Some controllers memorize the address here. Some don't.  */
268
1070
            dcd -> ux_slave_dcd_device_address =  request_value;
269
270
            /* Force the new address.  */
271
1070
            status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_SET_DEVICE_ADDRESS, (VOID *) (ALIGN_TYPE) request_value);
272
1070
            break;
273
274
4907
        case UX_GET_DESCRIPTOR:
275
276
4907
            status =  _ux_device_stack_descriptor_send(request_value, request_index, request_length);
277
4907
            break;
278
279
1
        case UX_SET_DESCRIPTOR:
280
281
1
            status = UX_FUNCTION_NOT_SUPPORTED;
282
1
            break;
283
284
1
        case UX_GET_CONFIGURATION:
285
286
1
            status =  _ux_device_stack_configuration_get();
287
1
            break;
288
289
927
        case UX_SET_CONFIGURATION:
290
291
927
            status =  _ux_device_stack_configuration_set(request_value);
292
927
            break;
293
294
4
        case UX_GET_INTERFACE:
295
296
4
            status =  _ux_device_stack_alternate_setting_get(request_index);
297
4
            break;
298
299
162
        case UX_SET_INTERFACE:
300
301
162
            status =  _ux_device_stack_alternate_setting_set(request_index,request_value);
302
162
            break;
303
304
305
1
        case UX_SYNCH_FRAME:
306
307
1
            status = UX_SUCCESS;
308
1
            break;
309
310
1
        default :
311
312
1
            status = UX_FUNCTION_NOT_SUPPORTED;
313
1
            break;
314
        }
315
316
8730
        if (status != UX_SUCCESS)
317
318
            /* Stall the control endpoint to issue protocol error. */
319
30
            _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
320
    }
321
322
    /* Return the function status.  */
323
8731
    return(status);
324
}
325