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