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 #if (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_DESCRIPTOR_LENGTH) || \
32 (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) || \
33 (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_OTG_DESCRIPTOR_LENGTH)
34 /* #error UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH too small, please check */
35 /* Build option checked runtime by UX_ASSERT */
36 #endif
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _ux_device_stack_descriptor_send PORTABLE C */
43 /* 6.3.0 */
44 /* AUTHOR */
45 /* */
46 /* Chaoqiong Xiao, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function sends back the device descriptor required by the host.*/
51 /* */
52 /* INPUT */
53 /* */
54 /* descriptor_type Descriptor type */
55 /* descriptor_index Index of descriptor */
56 /* host_length Length requested by host */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* Completion Status */
61 /* */
62 /* CALLS */
63 /* */
64 /* (ux_slave_dcd_function) DCD dispatch function */
65 /* _ux_device_stack_transfer_request Process transfer request */
66 /* _ux_utility_descriptor_parse Parse descriptor */
67 /* _ux_utility_memory_copy Memory copy */
68 /* _ux_utility_short_get Get short value */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* Application */
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 /* optimized descriptor search */
82 /* logic, verified memset and */
83 /* memcpy cases, */
84 /* resulting in version 6.1 */
85 /* 12-31-2020 Chaoqiong Xiao Modified comment(s), */
86 /* added BOS support, */
87 /* resulting in version 6.1.3 */
88 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
89 /* internal clean up, */
90 /* resulting in version 6.1.11 */
91 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
92 /* moved compile option check, */
93 /* added support for get string*/
94 /* requests with zero wIndex, */
95 /* resulting in version 6.3.0 */
96 /* */
97 /**************************************************************************/
_ux_device_stack_descriptor_send(ULONG descriptor_type,ULONG request_index,ULONG host_length)98 UINT _ux_device_stack_descriptor_send(ULONG descriptor_type, ULONG request_index, ULONG host_length)
99 {
100
101 UX_SLAVE_DCD *dcd;
102 UX_SLAVE_DEVICE *device;
103 ULONG descriptor_index;
104 ULONG parsed_descriptor_index;
105 UX_SLAVE_TRANSFER *transfer_request;
106 UX_CONFIGURATION_DESCRIPTOR configuration_descriptor;
107 #ifndef UX_BOS_SUPPORT_DISABLE
108 UX_BOS_DESCRIPTOR bos_descriptor;
109 #endif
110 UX_SLAVE_ENDPOINT *endpoint;
111 UCHAR *device_framework;
112 UCHAR *device_framework_end;
113 ULONG device_framework_length;
114 ULONG descriptor_length;
115 ULONG target_descriptor_length = 0;
116 UINT status = UX_ERROR;
117 ULONG length;
118 UCHAR *string_memory;
119 UCHAR *string_framework;
120 ULONG string_framework_length;
121 ULONG string_length;
122
123
124 /* Build option check. */
125 UX_ASSERT((UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_DEVICE_DESCRIPTOR_LENGTH) &&
126 (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) &&
127 (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_OTG_DESCRIPTOR_LENGTH));
128
129 /* If trace is enabled, insert this event into the trace buffer. */
130 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_DESCRIPTOR_SEND, descriptor_type, request_index, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
131
132 /* Get the pointer to the DCD. */
133 dcd = &_ux_system_slave -> ux_system_slave_dcd;
134
135 /* Get the pointer to the device. */
136 device = &_ux_system_slave -> ux_system_slave_device;
137
138 /* Get the control endpoint associated with the device. */
139 endpoint = &device -> ux_slave_device_control_endpoint;
140
141 /* Get the pointer to the transfer request associated with the endpoint. */
142 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
143
144 /* Set the direction to OUT. */
145 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT;
146
147 /* Isolate the descriptor index. */
148 descriptor_index = descriptor_type & 0xff;
149
150 /* Reset the parsed index. */
151 parsed_descriptor_index = 0;
152
153 /* Shift the descriptor type in the low byte field. */
154 descriptor_type = (UCHAR) ((descriptor_type >> 8) & 0xff);
155
156 /* Default descriptor length is host length. */
157 length = host_length;
158
159 /* What type of descriptor do we need to return? */
160 switch (descriptor_type)
161 {
162
163 case UX_DEVICE_DESCRIPTOR_ITEM:
164
165 /* Setup device descriptor length. */
166 if (host_length > UX_DEVICE_DESCRIPTOR_LENGTH)
167 length = UX_DEVICE_DESCRIPTOR_LENGTH;
168
169 /* Fall through. */
170 case UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM:
171
172 /* Setup qualifier descriptor length. */
173 if (descriptor_type == UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM &&
174 host_length > UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH)
175 length = UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH;
176
177 /* Fall through. */
178 case UX_OTG_DESCRIPTOR_ITEM:
179
180 /* Setup OTG descriptor length. */
181 if (descriptor_type == UX_OTG_DESCRIPTOR_ITEM &&
182 host_length > UX_OTG_DESCRIPTOR_LENGTH)
183 length = UX_OTG_DESCRIPTOR_LENGTH;
184
185 /* We may or may not have a device qualifier descriptor. */
186 device_framework = _ux_system_slave -> ux_system_slave_device_framework;
187 device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length;
188 device_framework_end = device_framework + device_framework_length;
189
190 /* Parse the device framework and locate a device qualifier descriptor. */
191 while (device_framework < device_framework_end)
192 {
193
194 /* Get descriptor length. */
195 descriptor_length = (ULONG) *device_framework;
196
197 /* Check if this is a descriptor expected. */
198 if (*(device_framework + 1) == descriptor_type)
199 {
200
201 /* Copy the device descriptor into the transfer request memory. */
202 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
203 device_framework, length); /* Use case of memcpy is verified. */
204
205 /* Perform the data transfer. */
206 status = _ux_device_stack_transfer_request(transfer_request, length, host_length);
207 break;
208 }
209
210 /* Adjust what is left of the device framework. */
211 device_framework_length -= descriptor_length;
212
213 /* Point to the next descriptor. */
214 device_framework += descriptor_length;
215 }
216 break;
217
218 #ifndef UX_BOS_SUPPORT_DISABLE
219 case UX_BOS_DESCRIPTOR_ITEM:
220 /* Fall through. */
221 #endif
222 case UX_OTHER_SPEED_DESCRIPTOR_ITEM:
223 /* Fall through. */
224 case UX_CONFIGURATION_DESCRIPTOR_ITEM:
225
226 if (descriptor_type == UX_OTHER_SPEED_DESCRIPTOR_ITEM)
227 {
228
229 /* This request is used by the host to find out the capability of this device
230 if it was running at full speed. The behavior is the same as in a GET_CONFIGURATIOn descriptor
231 but we do not use the current device framework but rather the full speed framework. */
232 device_framework = _ux_system_slave -> ux_system_slave_device_framework_full_speed;
233 device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_full_speed;
234 device_framework_end = device_framework + device_framework_length;
235 }
236 else
237 {
238
239 /* We may have multiple configurations !, the index will tell us what
240 configuration descriptor we need to return. */
241 device_framework = _ux_system_slave -> ux_system_slave_device_framework;
242 device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length;
243 device_framework_end = device_framework + device_framework_length;
244 }
245
246 /* Parse the device framework and locate a configuration descriptor. */
247 while (device_framework < device_framework_end)
248 {
249
250 /* Get descriptor length. */
251 descriptor_length = (ULONG) *device_framework;
252
253 #ifndef UX_BOS_SUPPORT_DISABLE
254
255 /* Check if we are finding BOS descriptor. */
256 if (descriptor_type == UX_BOS_DESCRIPTOR_ITEM)
257 {
258 if (*(device_framework + 1) == UX_BOS_DESCRIPTOR_ITEM)
259 {
260
261 /* Parse the BOS descriptor. */
262 _ux_utility_descriptor_parse(device_framework,
263 _ux_system_bos_descriptor_structure,
264 UX_BOS_DESCRIPTOR_ENTRIES,
265 (UCHAR *) &bos_descriptor);
266
267 /* Get the length of entire BOS descriptor. */
268 target_descriptor_length = bos_descriptor.wTotalLength;
269
270 /* Descriptor is found. */
271 status = UX_SUCCESS;
272 break;
273 }
274 }
275 else
276 #endif
277
278 {
279
280 /* Check if this is a configuration descriptor. We are cheating here. Instead of creating
281 a OTHER SPEED descriptor, we simply scan the configuration descriptor for the Full Speed
282 framework and return this configuration after we manually changed the configuration descriptor
283 item into a Other Speed Descriptor. */
284 if (*(device_framework + 1) == UX_CONFIGURATION_DESCRIPTOR_ITEM)
285 {
286
287 /* Check the index. It must be the same as the one requested. */
288 if (parsed_descriptor_index == descriptor_index)
289 {
290
291 /* Parse the configuration descriptor. */
292 _ux_utility_descriptor_parse(device_framework,
293 _ux_system_configuration_descriptor_structure,
294 UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
295 (UCHAR *) &configuration_descriptor);
296
297 /* Get the length of entire configuration descriptor. */
298 target_descriptor_length = configuration_descriptor.wTotalLength;
299
300 /* Descriptor is found. */
301 status = UX_SUCCESS;
302 break;
303 }
304 else
305 {
306
307 /* There may be more configuration descriptors in this framework. */
308 parsed_descriptor_index++;
309 }
310 }
311 }
312
313 /* Adjust what is left of the device framework. */
314 device_framework_length -= descriptor_length;
315
316 /* Point to the next descriptor. */
317 device_framework += descriptor_length;
318 }
319
320 /* Send the descriptor. */
321 if (status == UX_SUCCESS)
322 {
323
324 /* Ensure the host does not demand a length beyond our descriptor (Windows does that)
325 and do not return more than what is allowed. */
326 if (target_descriptor_length < host_length)
327 length = target_descriptor_length;
328 else
329 length = host_length;
330
331 /* Check buffer length, since total descriptors length may exceed buffer... */
332 if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
333 {
334 /* Error trap. */
335 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
336
337 /* If trace is enabled, insert this event into the trace buffer. */
338 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
339
340 /* Stall the endpoint. */
341 status = dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
342 break;
343 }
344
345 /* Copy the device descriptor into the transfer request memory. */
346 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
347 device_framework, length); /* Use case of memcpy is verified. */
348
349 /* Now we need to hack the found descriptor because this request expect a requested
350 descriptor type instead of the regular descriptor. */
351 *(transfer_request -> ux_slave_transfer_request_data_pointer + 1) = (UCHAR)descriptor_type;
352
353 /* We can return the configuration descriptor. */
354 status = _ux_device_stack_transfer_request(transfer_request, length, host_length);
355 }
356 break;
357
358 case UX_STRING_DESCRIPTOR_ITEM:
359
360 /* We need to filter for the index 0 which is the language ID string. */
361 if (descriptor_index == 0)
362 {
363
364 /* We need to check request buffer size in case it's possible exceed. */
365 if (_ux_system_slave -> ux_system_slave_language_id_framework_length + 2 > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
366 {
367
368 /* Error trap. */
369 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
370
371 /* If trace is enabled, insert this event into the trace buffer. */
372 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
373
374 /* Stall the endpoint. */
375 status = dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
376 break;
377 }
378
379 /* We have a request to send back the language ID list. Use the transfer request buffer. */
380 string_memory = transfer_request -> ux_slave_transfer_request_data_pointer;
381
382 /* Store the total length of the response. */
383 *string_memory = (UCHAR)(_ux_system_slave -> ux_system_slave_language_id_framework_length + 2);
384
385 /* Store the descriptor type. */
386 *(string_memory +1) = UX_STRING_DESCRIPTOR_ITEM;
387
388 /* Store the language ID into the buffer. */
389 _ux_utility_memory_copy(string_memory+2, _ux_system_slave -> ux_system_slave_language_id_framework,
390 _ux_system_slave -> ux_system_slave_language_id_framework_length); /* Use case of memcpy is verified. */
391
392 /* Filter the length asked/required. */
393 if (host_length > _ux_system_slave -> ux_system_slave_language_id_framework_length + 2)
394 length = _ux_system_slave -> ux_system_slave_language_id_framework_length + 2;
395 else
396 length = host_length;
397
398 /* We can return the string language ID descriptor. */
399 status = _ux_device_stack_transfer_request(transfer_request, length, host_length);
400 }
401 else
402 {
403 #ifdef UX_DEVICE_ENABLE_GET_STRING_WITH_ZERO_LANGUAGE_ID
404
405 /* Check if the language ID is zero. */
406 if (request_index == 0)
407 {
408
409 /* Get the first language ID in the language ID framework. */
410 request_index = _ux_utility_short_get(_ux_system_slave -> ux_system_slave_language_id_framework);
411 }
412 #endif
413
414 /* The host wants a specific string index returned. Get the string framework pointer
415 and length. */
416 string_framework = _ux_system_slave -> ux_system_slave_string_framework;
417 string_framework_length = _ux_system_slave -> ux_system_slave_string_framework_length;
418
419 /* We search through the string framework until we find the right index.
420 The index is in the lower byte of the descriptor type. */
421 while (string_framework_length != 0)
422 {
423
424 /* Ensure we have the correct language page. */
425 if (_ux_utility_short_get(string_framework) == request_index)
426 {
427
428 /* Check the index. */
429 if (*(string_framework + 2) == descriptor_index)
430 {
431
432 /* We need to check request buffer size in case it's possible exceed. */
433 if (((*(string_framework + 3)*2) + 2) > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
434 {
435
436 /* Error trap. */
437 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
438
439 /* If trace is enabled, insert this event into the trace buffer. */
440 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
441
442 /* Stall the endpoint. */
443 status = dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
444 break;
445 }
446
447 /* We have a request to send back a string. Use the transfer request buffer. */
448 string_memory = transfer_request -> ux_slave_transfer_request_data_pointer;
449
450 /* Store the length in the string buffer. The length
451 of the string descriptor is stored in the third byte,
452 hence the ' + 3'. The encoding must be in 16-bit
453 unicode, hence the '*2'. The length includes the size
454 of the length itself as well as the descriptor type,
455 hence the ' + 2'. */
456 *string_memory = (UCHAR)((*(string_framework + 3)*2) + 2);
457
458 /* Store the Descriptor type. */
459 *(string_memory + 1) = UX_STRING_DESCRIPTOR_ITEM;
460
461 /* Create the Unicode string. */
462 for (string_length = 0; string_length < *(string_framework + 3) ; string_length ++)
463 {
464
465 /* Insert a Unicode byte. */
466 *(string_memory + 2 + (string_length * 2)) = *(string_framework + 4 + string_length);
467
468 /* Insert a zero after the Unicode byte. */
469 *(string_memory + 2 + (string_length * 2) + 1) = 0;
470 }
471
472 /* Filter the length asked/required. */
473 if (host_length > (UINT)((*(string_framework + 3)*2) + 2))
474 length = (ULONG)((*(string_framework + 3)*2) + 2);
475 else
476 length = host_length;
477
478 /* We can return the string descriptor. */
479 status = _ux_device_stack_transfer_request(transfer_request, length, host_length);
480 break;
481 }
482 }
483
484 /* This is the wrong string descriptor, jump to the next. */
485 string_framework_length -= (ULONG) *(string_framework + 3) + 4;
486 string_framework += (ULONG) *(string_framework + 3) + 4;
487 }
488
489 /* Have we exhausted all the string descriptors? */
490 if (string_framework_length == 0)
491 {
492
493 /* Could not find the required string index. Stall the endpoint. */
494 dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
495 return(UX_ERROR);
496 }
497 }
498 break;
499
500 default:
501
502 /* Stall the endpoint. */
503 dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
504 return(UX_ERROR);
505 }
506
507 /* Return the status to the caller. */
508 return(status);
509 }
510
511