GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_control_request_process.c Lines: 88 88 100.0 %
Date: 2024-12-12 17:16:36 Branches: 54 54 100.0 %

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
/**   Device Stack                                                        */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define UX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "ux_api.h"
28
#include "ux_device_stack.h"
29
30
/**************************************************************************/
31
/*                                                                        */
32
/*  FUNCTION                                               RELEASE        */
33
/*                                                                        */
34
/*    _ux_device_stack_control_request_process            PORTABLE C      */
35
/*                                                           6.3.0        */
36
/*  AUTHOR                                                                */
37
/*                                                                        */
38
/*    Chaoqiong Xiao, Microsoft Corporation                               */
39
/*                                                                        */
40
/*  DESCRIPTION                                                           */
41
/*                                                                        */
42
/*    This function is called by the DCD when the device has received a   */
43
/*    SETUP packet.                                                       */
44
/*                                                                        */
45
/*  INPUT                                                                 */
46
/*                                                                        */
47
/*    transfer_request                      Pointer to transfer request   */
48
/*                                                                        */
49
/*  OUTPUT                                                                */
50
/*                                                                        */
51
/*    Completion Status                                                   */
52
/*                                                                        */
53
/*  CALLS                                                                 */
54
/*                                                                        */
55
/*    (ux_slave_class_entry_function)       Device class entry function   */
56
/*    (ux_slave_dcd_function)               DCD dispatch function         */
57
/*    _ux_device_stack_transfer_request     Transfer request              */
58
/*    _ux_device_stack_endpoint_stall       Stall endpoint                */
59
/*    _ux_device_stack_alternate_setting_get                              */
60
/*                                          Get alternate settings        */
61
/*    _ux_device_stack_alternate_setting_set                              */
62
/*                                          Set alternate settings        */
63
/*    _ux_device_stack_clear_feature        Clear feature                 */
64
/*    _ux_device_stack_configuration_get    Get configuration             */
65
/*    _ux_device_stack_configuration_set    Set configuration             */
66
/*    _ux_device_stack_descriptor_send      Send descriptor               */
67
/*    _ux_device_stack_get_status           Get status                    */
68
/*    _ux_device_stack_set_feature          Set feature                   */
69
/*    _ux_utility_short_get                 Get short value               */
70
/*                                                                        */
71
/*  CALLED BY                                                             */
72
/*                                                                        */
73
/*    Device Stack                                                        */
74
/*                                                                        */
75
/*  RELEASE HISTORY                                                       */
76
/*                                                                        */
77
/*    DATE              NAME                      DESCRIPTION             */
78
/*                                                                        */
79
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
80
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
81
/*                                            resulting in version 6.1    */
82
/*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
83
/*                                            fixed possible buffer issue */
84
/*                                            for control vendor request, */
85
/*                                            resulting in version 6.1.9  */
86
/*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
87
/*                                            added printer support,      */
88
/*                                            resulting in version 6.1.10 */
89
/*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
90
/*                                            fixed parameter/variable    */
91
/*                                            names conflict C++ keyword, */
92
/*                                            resulting in version 6.1.12 */
93
/*  03-08-2023     Chaoqiong Xiao           Modified comment(s),          */
94
/*                                            fixed vendor request issue, */
95
/*                                            resulting in version 6.2.1  */
96
/*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
97
/*                                            improved interface request  */
98
/*                                            process with print class,   */
99
/*                                            resulting in version 6.3.0  */
100
/*                                                                        */
101
/**************************************************************************/
102
10812
UINT  _ux_device_stack_control_request_process(UX_SLAVE_TRANSFER *transfer_request)
103
{
104
105
UX_SLAVE_DCD                *dcd;
106
UX_SLAVE_DEVICE             *device;
107
UX_SLAVE_CLASS              *class_ptr;
108
UX_SLAVE_CLASS_COMMAND      class_command;
109
ULONG                       request_type;
110
ULONG                       request;
111
ULONG                       request_value;
112
ULONG                       request_index;
113
ULONG                       request_length;
114
ULONG                       class_index;
115
10812
UINT                        status =  UX_ERROR;
116
UX_SLAVE_ENDPOINT           *endpoint;
117
ULONG                       application_data_length;
118
119
    /* Get the pointer to the DCD.  */
120
10812
    dcd =  &_ux_system_slave -> ux_system_slave_dcd;
121
122
    /* Get the pointer to the device.  */
123
10812
    device =  &_ux_system_slave -> ux_system_slave_device;
124
125
    /* Ensure that the Setup request has been received correctly.  */
126
10812
    if (transfer_request -> ux_slave_transfer_request_completion_code == UX_SUCCESS)
127
    {
128
129
        /* Seems so far, the Setup request is valid. Extract all fields of
130
           the request.  */
131
10811
        request_type   =   *transfer_request -> ux_slave_transfer_request_setup;
132
10811
        request        =   *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
133
10811
        request_value  =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE);
134
10811
        request_index  =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_INDEX);
135
10811
        request_length =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
136
137
        /* Filter for GET_DESCRIPTOR/SET_DESCRIPTOR commands. If the descriptor to be returned is not a standard descriptor,
138
           treat the command as a CLASS command.  */
139

10811
        if ((request == UX_GET_DESCRIPTOR || request == UX_SET_DESCRIPTOR) && (((request_value >> 8) & UX_REQUEST_TYPE) != UX_REQUEST_TYPE_STANDARD))
140
        {
141
142
            /* This request is to be handled by the class layer.  */
143
545
            request_type &=  (UINT)~UX_REQUEST_TYPE;
144
545
            request_type |= UX_REQUEST_TYPE_CLASS;
145
        }
146
147
        /* Check if there is a vendor registered function at the application layer.  If the request
148
           is VENDOR and the request match, pass the request to the application.  */
149
10811
        if ((request_type & UX_REQUEST_TYPE) == UX_REQUEST_TYPE_VENDOR)
150
        {
151
152
            /* Check the request demanded and compare it to the application registered one.  */
153
7
            if (_ux_system_slave -> ux_system_slave_device_vendor_request_function != UX_NULL &&
154
6
                request == _ux_system_slave -> ux_system_slave_device_vendor_request)
155
            {
156
157
                /* This is a Microsoft extended function. It happens before the device is configured.
158
                   The request is passed to the application directly.  */
159
4
                application_data_length = UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH;
160
4
                status = _ux_system_slave -> ux_system_slave_device_vendor_request_function(request, request_value,
161
                                                                                            request_index, request_length,
162
                                                                                            transfer_request -> ux_slave_transfer_request_data_pointer,
163
                                                                                            &application_data_length);
164
165
                /* Check the status from the application.  */
166
4
                if (status == UX_SUCCESS)
167
                {
168
169
                    /* Get the control endpoint associated with the device.  */
170
2
                    endpoint =  &device -> ux_slave_device_control_endpoint;
171
172
                    /* Get the pointer to the transfer request associated with the control endpoint.  */
173
2
                    transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
174
175
                    /* Set the direction to OUT.  */
176
2
                    transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
177
178
                    /* Perform the data transfer.  */
179
2
                    _ux_device_stack_transfer_request(transfer_request, application_data_length, request_length);
180
181
                    /* We are done here.  */
182
2
                    return(UX_SUCCESS);
183
                }
184
                else
185
                {
186
187
                    /* The application did not like the vendor command format, stall the control endpoint.  */
188
2
                    _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
189
190
                    /* We are done here.  */
191
2
                    return(UX_SUCCESS);
192
                }
193
            }
194
        }
195
196
        /* Check the destination of the request. If the request is of type CLASS or VENDOR_SPECIFIC,
197
           the function has to be passed to the class layer.  */
198
10807
        if (((request_type & UX_REQUEST_TYPE) == UX_REQUEST_TYPE_CLASS) ||
199
8727
            ((request_type & UX_REQUEST_TYPE) == UX_REQUEST_TYPE_VENDOR))
200
        {
201
202
            /* Build all the fields of the Class Command.  */
203
2083
            class_command.ux_slave_class_command_request =  UX_SLAVE_CLASS_COMMAND_REQUEST;
204
205
            /* We need to find which class this request is for.  */
206
4143
            for (class_index = 0; class_index < UX_MAX_SLAVE_INTERFACES; class_index ++)
207
            {
208
209
                /* Get the class for the interface.  */
210
4077
                class_ptr =  _ux_system_slave -> ux_system_slave_interface_class_array[class_index];
211
212
                /* If class is not ready, try next.  */
213
4077
                if (class_ptr == UX_NULL)
214
1686
                    continue;
215
216
                /* Is the request target to an interface?  */
217
2391
                if ((request_type & UX_REQUEST_TARGET) == UX_REQUEST_TARGET_INTERFACE)
218
                {
219
220
                    /* Yes, so the request index contains the index of the interface
221
                       the request is for. So if the current index does not match
222
                       the request index, we should go to the next one.  */
223
                    /* For printer class (0x07) GET_DEVICE_ID (0x00) the high byte of
224
                       wIndex is interface index (for recommended index sequence the interface
225
                       number is same as interface index inside configuration).
226
                     */
227

2094
                    if ((request_type == 0xA1) && (request == 0x00) &&
228
34
                        (class_ptr -> ux_slave_class_interface -> ux_slave_interface_descriptor.bInterfaceClass == 0x07))
229
                    {
230
231
                        /* Check wIndex high byte.  */
232
16
                        if(*(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_INDEX + 1) != class_index)
233
5
                            continue;
234
                    }
235
                    else
236
                    {
237
238
                        /* Check wIndex low.  */
239
2078
                        if ((request_index & 0xFF) != class_index)
240
339
                            continue;
241
                    }
242
                }
243
244
                /* Memorize the class in the command.  */
245
2047
                class_command.ux_slave_class_command_class_ptr = class_ptr;
246
247
                /* We have found a potential candidate. Call this registered class entry function.  */
248
2047
                status = class_ptr -> ux_slave_class_entry_function(&class_command);
249
250
                /* The status simply tells us if the registered class handled the
251
                   command - if there was an issue processing the command, it would've
252
                   stalled the control endpoint, notifying the host (and not us).  */
253
2047
                if (status == UX_SUCCESS)
254
255
                    /* We are done, break the loop!  */
256
2017
                    break;
257
258
                /* Not handled, try next.  */
259
            }
260
261
            /* If no class handled the command, then we have an error here.  */
262
2083
            if (status != UX_SUCCESS)
263
264
                /* We stall the command (request not supported).  */
265
66
                _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
266
267
            /* We are done for class/vendor request.  */
268
2083
            return(status);
269
        }
270
271
        /* At this point, the request must be a standard request that the device stack should handle.  */
272



8724
        switch (request)
273
        {
274
275
221
        case UX_GET_STATUS:
276
277
221
            status =  _ux_device_stack_get_status(request_type, request_index, request_length);
278
221
            break;
279
280
1426
        case UX_CLEAR_FEATURE:
281
282
1426
            status =  _ux_device_stack_clear_feature(request_type, request_value, request_index);
283
1426
            break;
284
285
9
        case UX_SET_FEATURE:
286
287
9
            status =  _ux_device_stack_set_feature(request_type, request_value, request_index);
288
9
            break;
289
290
1069
        case UX_SET_ADDRESS:
291
292
            /* Memorize the address. Some controllers memorize the address here. Some don't.  */
293
1069
            dcd -> ux_slave_dcd_device_address =  request_value;
294
295
            /* Force the new address.  */
296
1069
            status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_SET_DEVICE_ADDRESS, (VOID *) (ALIGN_TYPE) request_value);
297
1069
            break;
298
299
4903
        case UX_GET_DESCRIPTOR:
300
301
4903
            status =  _ux_device_stack_descriptor_send(request_value, request_index, request_length);
302
4903
            break;
303
304
1
        case UX_SET_DESCRIPTOR:
305
306
1
            status = UX_FUNCTION_NOT_SUPPORTED;
307
1
            break;
308
309
1
        case UX_GET_CONFIGURATION:
310
311
1
            status =  _ux_device_stack_configuration_get();
312
1
            break;
313
314
926
        case UX_SET_CONFIGURATION:
315
316
926
            status =  _ux_device_stack_configuration_set(request_value);
317
926
            break;
318
319
4
        case UX_GET_INTERFACE:
320
321
4
            status =  _ux_device_stack_alternate_setting_get(request_index);
322
4
            break;
323
324
162
        case UX_SET_INTERFACE:
325
326
162
            status =  _ux_device_stack_alternate_setting_set(request_index,request_value);
327
162
            break;
328
329
330
1
        case UX_SYNCH_FRAME:
331
332
1
            status = UX_SUCCESS;
333
1
            break;
334
335
1
        default :
336
337
1
            status = UX_FUNCTION_NOT_SUPPORTED;
338
1
            break;
339
        }
340
341
8724
        if (status != UX_SUCCESS)
342
343
            /* Stall the control endpoint to issue protocol error. */
344
30
            _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
345
    }
346
347
    /* Return the function status.  */
348
8725
    return(status);
349
}
350