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 /** USBX Component */
15 /** */
16 /** Device Stack */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_host_stack.h"
27
28 #if defined(UX_HOST_STANDALONE)
29
30
31 #define UX_HOST_STACK_ENUM_TRANS_ERROR(t) ( \
32 (t)->ux_transfer_request_completion_code != UX_SUCCESS || \
33 (t)->ux_transfer_request_actual_length != \
34 (t)->ux_transfer_request_requested_length)
35
36 static inline VOID _ux_host_stack_port_check_run(VOID);
37 static inline VOID _ux_host_stack_enum_run(VOID);
38 static inline VOID _ux_host_stack_pending_transfers_run(VOID);
39
40
41 /**************************************************************************/
42 /* */
43 /* FUNCTION RELEASE */
44 /* */
45 /* _ux_host_stack_tasks_run PORTABLE C */
46 /* 6.3.0 */
47 /* AUTHOR */
48 /* */
49 /* Chaoqiong Xiao, Microsoft Corporation */
50 /* */
51 /* DESCRIPTION */
52 /* */
53 /* This function runs host stack and registered classes tasks. */
54 /* */
55 /* It's valid only in standalone mode. */
56 /* It's non-blocking. */
57 /* */
58 /* INPUT */
59 /* */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* Completion State Status */
64 /* */
65 /* CALLS */
66 /* */
67 /* (ux_hcd_entry_function) HCD function */
68 /* (ux_host_class_task_function) Host class task function */
69 /* (ux_system_host_change_function) Host change callback function */
70 /* (ux_system_host_enum_hub_function) Host hub enumeration function */
71 /* _ux_host_stack_rh_change_process Host Root Hub process */
72 /* _ux_host_stack_device_address_set Start process to set address */
73 /* _ux_host_stack_configuration_set Start process to set config */
74 /* _ux_host_stack_device_descriptor_read Start process to read device */
75 /* descriptor */
76 /* _ux_host_stack_new_configuration_create */
77 /* Link a new configuration to */
78 /* a device */
79 /* _ux_host_stack_configuration_instance_create */
80 /* Create configuration instance */
81 /* _ux_host_stack_transfer_run Runs transfer state machine */
82 /* _ux_host_stack_class_device_scan Query device class driver */
83 /* _ux_host_stack_class_interface_scan Query interface class driver */
84 /* _ux_host_stack_interfaces_scan Parse interfaces in a */
85 /* configuration */
86 /* _ux_host_stack_device_remove Remove a device */
87 /* _ux_utility_descriptor_parse Parse a descriptor */
88 /* _ux_utility_memory_allocate Allocate memory */
89 /* _ux_utility_memory_free Free memory */
90 /* _ux_utility_time_get Get current time tick */
91 /* _ux_system_error_handler Error trap */
92 /* */
93 /* CALLED BY */
94 /* */
95 /* Application */
96 /* */
97 /* RELEASE HISTORY */
98 /* */
99 /* DATE NAME DESCRIPTION */
100 /* */
101 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
102 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
103 /* added standalone hub, */
104 /* used shared descriptor in */
105 /* device instance for enum, */
106 /* resulting in version 6.1.12 */
107 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
108 /* improved internal logic, */
109 /* fixed activation issue on */
110 /* no class linked interfaces, */
111 /* resulting in version 6.2.0 */
112 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
113 /* improved enum transfer, */
114 /* resulting in version 6.3.0 */
115 /* */
116 /**************************************************************************/
_ux_host_stack_tasks_run(VOID)117 UINT _ux_host_stack_tasks_run(VOID)
118 {
119
120 UX_HCD *hcd_inst;
121 ULONG hcd_index;
122 UX_HOST_CLASS *class_inst;
123 ULONG class_index;
124
125 /* =========== Run all HCD tasks. */
126 for (hcd_index = 0; hcd_index < UX_SYSTEM_HOST_MAX_HCD_GET(); hcd_index++)
127 {
128 hcd_inst = &_ux_system_host->ux_system_host_hcd_array[hcd_index];
129 if (hcd_inst -> ux_hcd_status != UX_HCD_STATUS_OPERATIONAL ||
130 hcd_inst -> ux_hcd_entry_function == UX_NULL)
131 continue;
132 hcd_inst -> ux_hcd_entry_function(hcd_inst, UX_HCD_TASKS_RUN, UX_NULL);
133 }
134
135 /* =========== Run port check process. */
136 _ux_host_stack_port_check_run();
137
138 /* =========== Run enumeration process. */
139 _ux_host_stack_enum_run();
140
141 /* =========== Run classes tasks. */
142 for (class_index = 0; class_index < UX_SYSTEM_HOST_MAX_CLASS_GET(); class_index++)
143 {
144 class_inst = &_ux_system_host->ux_system_host_class_array[class_index];
145 if ((class_inst -> ux_host_class_status == UX_UNUSED) ||
146 (class_inst -> ux_host_class_task_function == UX_NULL))
147 continue;
148 class_inst -> ux_host_class_task_function(class_inst);
149 }
150
151 /* =========== Run pending transfer tasks. */
152 _ux_host_stack_pending_transfers_run();
153
154 /* =========== Run background tasks. */
155 if (_ux_system_host -> ux_system_host_change_function)
156 {
157 _ux_system_host -> ux_system_host_change_function(
158 UX_STANDALONE_WAIT_BACKGROUND_TASK, UX_NULL, UX_NULL);
159 }
160
161 /* No idle report support now. */
162 return (UX_STATE_WAIT);
163 }
164
_ux_host_stack_port_check_run(VOID)165 static inline VOID _ux_host_stack_port_check_run(VOID)
166 {
167 #if UX_MAX_DEVICES > 1
168
169 /* We try the hub first. For this we look into the USBX project
170 structure to see if there is at least one hub. */
171 if (_ux_system_host->ux_system_host_enum_hub_function != UX_NULL)
172 {
173
174 /* Yes, there is a HUB function, call it! */
175 _ux_system_host->ux_system_host_enum_hub_function();
176 }
177 #endif
178
179 /* Check root hub changes. */
180 _ux_host_stack_rh_change_process();
181 }
182
_ux_host_stack_rh_port_enable(UX_DEVICE * device)183 static inline UINT _ux_host_stack_rh_port_enable(UX_DEVICE *device)
184 {
185 UX_HCD *hcd = UX_DEVICE_HCD_GET(device);
186 ALIGN_TYPE port_index = (ALIGN_TYPE)UX_DEVICE_PORT_LOCATION_GET(device);
187 return hcd -> ux_hcd_entry_function(hcd, UX_HCD_ENABLE_PORT, (VOID *)port_index);
188 }
_ux_host_stack_rh_port_reset(UX_DEVICE * device)189 static inline UINT _ux_host_stack_rh_port_reset(UX_DEVICE *device)
190 {
191 UX_HCD *hcd = UX_DEVICE_HCD_GET(device);
192 ALIGN_TYPE port_index = (ALIGN_TYPE)UX_DEVICE_PORT_LOCATION_GET(device);
193 return hcd -> ux_hcd_entry_function(hcd, UX_HCD_RESET_PORT, (VOID *)port_index);
194 }
_ux_host_stack_rh_port_status_get(UX_DEVICE * device)195 static inline UINT _ux_host_stack_rh_port_status_get(UX_DEVICE *device)
196 {
197 UX_HCD *hcd = UX_DEVICE_HCD_GET(device);
198 ALIGN_TYPE port_index = (ALIGN_TYPE)UX_DEVICE_PORT_LOCATION_GET(device);
199 return hcd -> ux_hcd_entry_function(hcd, UX_HCD_GET_PORT_STATUS, (VOID *)port_index);
200 }
_ux_host_stack_enum_address_sent(UX_DEVICE * device)201 static inline VOID _ux_host_stack_enum_address_sent(UX_DEVICE *device)
202 {
203
204 /* Address (request wValue) applied to device. */
205 device -> ux_device_address = device -> ux_device_control_endpoint.
206 ux_endpoint_transfer_request.ux_transfer_request_value & 0x7F;
207 device -> ux_device_state = UX_DEVICE_ADDRESSED;
208
209 /* Unlock enumeration. */
210 _ux_system_host -> ux_system_host_enum_lock = UX_NULL;
211 }
_ux_host_stack_enum_device_descriptor_parse0(UX_DEVICE * device,UCHAR * descriptor)212 static inline VOID _ux_host_stack_enum_device_descriptor_parse0(
213 UX_DEVICE *device, UCHAR *descriptor)
214 {
215
216 /* Endpoint descriptor updated. */
217 device -> ux_device_descriptor.bMaxPacketSize0 = descriptor[7];
218
219 /* Update EP0 wMaxPacketSize. */
220 device -> ux_device_control_endpoint.
221 ux_endpoint_descriptor.wMaxPacketSize = descriptor[7];
222 }
_ux_host_stack_enum_configuration_descriptor_parse0(UX_DEVICE * device,UX_CONFIGURATION * configuration,UCHAR * descriptor)223 static inline VOID _ux_host_stack_enum_configuration_descriptor_parse0(
224 UX_DEVICE *device, UX_CONFIGURATION *configuration, UCHAR *descriptor)
225 {
226 /* This configuration must be linked to the device. */
227 _ux_host_stack_new_configuration_create(device, configuration);
228
229 /* The descriptor is in a packed format, parse it locally. */
230 _ux_utility_descriptor_parse(descriptor,
231 _ux_system_configuration_descriptor_structure,
232 UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
233 (UCHAR *) &configuration -> ux_configuration_descriptor);
234 }
_ux_host_stack_enum_configuration_read(UX_DEVICE * device)235 static inline UINT _ux_host_stack_enum_configuration_read(UX_DEVICE *device)
236 {
237
238 UX_CONFIGURATION *configuration;
239 UCHAR *descriptor;
240 UX_ENDPOINT *control_endpoint;
241 UX_TRANSFER *transfer_request;
242
243 /* Allocate configuration containter for the descriptor. */
244 configuration = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
245 sizeof(UX_CONFIGURATION));
246 if (configuration == UX_NULL)
247 return(UX_MEMORY_INSUFFICIENT);
248
249 /* Need to allocate memory for the configuration descriptor the first time we read
250 only the configuration descriptor when we have the configuration descriptor, we have
251 the length of the entire configuration\interface\endpoint descriptors. */
252 descriptor = _ux_utility_memory_allocate(UX_SAFE_ALIGN,
253 UX_CACHE_SAFE_MEMORY, UX_CONFIGURATION_DESCRIPTOR_LENGTH);
254 if (descriptor == UX_NULL)
255 {
256 _ux_utility_memory_free(configuration);
257 return(UX_MEMORY_INSUFFICIENT);
258 }
259
260 /* Save allocated configuration container. */
261 device -> ux_device_enum_inst.configuration = configuration;
262
263 /* Retrieve the pointer to the control endpoint and its transfer_request. */
264 control_endpoint = &device -> ux_device_control_endpoint;
265 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
266
267 /* Create a transfer_request for the GET_DESCRIPTOR request. */
268 transfer_request -> ux_transfer_request_data_pointer = descriptor;
269 transfer_request -> ux_transfer_request_requested_length = UX_CONFIGURATION_DESCRIPTOR_LENGTH;
270 transfer_request -> ux_transfer_request_function = UX_GET_DESCRIPTOR;
271 transfer_request -> ux_transfer_request_type = UX_REQUEST_IN |
272 UX_REQUEST_TYPE_STANDARD |
273 UX_REQUEST_TARGET_DEVICE;
274 transfer_request -> ux_transfer_request_value = (UINT)device -> ux_device_enum_index |
275 (UINT)(UX_CONFIGURATION_DESCRIPTOR_ITEM << 8);
276 transfer_request -> ux_transfer_request_index = 0;
277
278 /* Transfer for wait. */
279 UX_TRANSFER_STATE_RESET(transfer_request);
280 device -> ux_device_enum_trans = transfer_request;
281
282 return(UX_SUCCESS);
283 }
_ux_host_stack_configuration_parsed(UX_DEVICE * device)284 static inline VOID _ux_host_stack_configuration_parsed(UX_DEVICE *device)
285 {
286 UINT status;
287
288 /* By default (error) configuration not activated. */
289 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
290
291 /* Query device class driver. */
292 status = _ux_host_stack_class_device_scan(device);
293 if (status == UX_SUCCESS)
294 {
295
296 /* Prepare device activation. */
297 device -> ux_device_enum_index = 0xFF;
298 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_ACTIVATE;
299 device -> ux_device_enum_inst.device = device;
300 }
301 else if (status == UX_NO_CLASS_MATCH)
302 {
303
304 /* Query interface class driver. */
305 status = _ux_host_stack_class_interface_scan(device);
306 if (status == UX_SUCCESS)
307 {
308
309 /* Prepare interfaces activation. */
310 device -> ux_device_enum_index = 0;
311 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_CONFIG_SET;
312 device -> ux_device_enum_inst.configuration =
313 device -> ux_device_first_configuration;
314 }
315 }
316 }
317
_ux_host_stack_device_enumerated(UX_DEVICE * device)318 static inline VOID _ux_host_stack_device_enumerated(UX_DEVICE *device)
319 {
320
321 /* If trace is enabled, register this object. */
322 UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_DEVICE,
323 UX_DEVICE_HCD_GET(device), UX_DEVICE_PARENT_GET(device),
324 UX_DEVICE_PORT_LOCATION_GET(device), 0);
325
326 /* Check if there is unnecessary resource to free. */
327 if (device -> ux_device_packed_configuration &&
328 device -> ux_device_packed_configuration_keep_count == 0)
329 {
330 _ux_utility_memory_free(device -> ux_device_packed_configuration);
331 device -> ux_device_packed_configuration = UX_NULL;
332 }
333
334 /* Reset enumeration state. */
335 device -> ux_device_enum_state = UX_STATE_IDLE;
336
337 /* Unlock device EP0. */
338 device -> ux_device_control_endpoint.ux_endpoint_transfer_request.
339 ux_transfer_request_flags &= ~UX_TRANSFER_FLAG_LOCK;
340
341 /* Disconnect from enumeration list. */
342
343 /* Clear enumeration flag to stop enumeration sequence. */
344 device -> ux_device_flags &= ~UX_DEVICE_FLAG_ENUM;
345
346 /* If HCD is dead or device disconnected, free device. */
347 if (UX_DEVICE_HCD_GET(device) -> ux_hcd_status != UX_HCD_STATUS_OPERATIONAL ||
348 (device -> ux_device_enum_port_status & UX_PS_CCS) == 0)
349 {
350 _ux_host_stack_device_remove(UX_DEVICE_HCD_GET(device),
351 UX_DEVICE_PARENT_GET(device),
352 UX_DEVICE_PORT_LOCATION_GET(device));
353
354 /* Done without notification. */
355 return;
356 }
357
358 /* Device connected and enumerated success/fail. */
359
360 /* For root hub, set root hub connection status. */
361 if (UX_DEVICE_PARENT_IS_ROOTHUB(device))
362 {
363 UX_DEVICE_HCD_GET(device) -> ux_hcd_rh_device_connection |=
364 (ULONG)(1 << UX_DEVICE_PORT_LOCATION_GET(device));
365 }
366
367 /* If change function available, notify device connection. */
368 if (_ux_system_host -> ux_system_host_change_function)
369 {
370 _ux_system_host -> ux_system_host_change_function(
371 UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
372 }
373 }
374
_ux_host_stack_interface_activate_wait(UX_DEVICE * device,UX_HOST_CLASS_COMMAND * command)375 static inline UINT _ux_host_stack_interface_activate_wait(UX_DEVICE *device,
376 UX_HOST_CLASS_COMMAND *command)
377 {
378 UINT status;
379 UX_INTERFACE *interface_inst;
380
381 command -> ux_host_class_command_container = device -> ux_device_enum_inst.ptr;
382 command -> ux_host_class_command_class_ptr = (device -> ux_device_enum_index == 0xFF) ?
383 device -> ux_device_class :
384 device -> ux_device_enum_inst.interface -> ux_interface_class;
385 command -> ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT;
386
387 /* If there is no class linked, just next state. */
388 if (command -> ux_host_class_command_class_ptr != UX_NULL)
389 status = command -> ux_host_class_command_class_ptr -> ux_host_class_entry_function(command);
390 else
391 status = UX_STATE_NEXT;
392
393 /* No wait command or ready for next state. */
394 if (status == UX_FUNCTION_NOT_SUPPORTED ||
395 status == UX_STATE_NEXT)
396 {
397
398 /* Activate for device class driver. */
399 if (device -> ux_device_enum_index == 0xFF)
400 {
401
402 /* Enumeration done (class driver controls device configuration). */
403 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_DONE;
404 return(UX_STATE_NEXT);
405 }
406 else
407 {
408
409 /* Activate next interface (default setting). */
410 interface_inst = device -> ux_device_enum_inst.interface -> ux_interface_next_interface;
411 while(interface_inst != UX_NULL &&
412 interface_inst -> ux_interface_descriptor.bAlternateSetting != 0)
413 {
414 interface_inst = interface_inst -> ux_interface_next_interface;
415 }
416 if (interface_inst != UX_NULL)
417 {
418 device -> ux_device_enum_inst.interface = interface_inst;
419 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_ACTIVATE;
420 return(UX_STATE_NEXT);
421 }
422
423 /* Enumeration is done. */
424 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_DONE;
425 return(UX_STATE_NEXT);
426 }
427 }
428
429 /* Error cases. */
430 if (status < UX_STATE_NEXT)
431 {
432 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
433 return(UX_STATE_NEXT);
434 }
435
436 /* Keep waiting. */
437 return(UX_STATE_WAIT);
438 }
439
440
_ux_host_stack_device_enum_run(UX_DEVICE * device)441 static inline VOID _ux_host_stack_device_enum_run(UX_DEVICE *device)
442 {
443 UX_INTERRUPT_SAVE_AREA
444 UINT status;
445 ULONG current_ms, elapsed_ms;
446 UX_TRANSFER *trans;
447 UX_CONFIGURATION *configuration;
448 UX_HOST_CLASS_COMMAND class_command;
449 UCHAR *buffer;
450 INT immediate_state = UX_TRUE;
451
452 /* Check if the device enumeration should be processed. */
453 if ((device -> ux_device_flags & UX_DEVICE_FLAG_ENUM) == 0)
454 return;
455
456 /* Enumeration lock check, devices not addressed should wait. */
457 UX_DISABLE
458 if (_ux_system_host -> ux_system_host_enum_lock &&
459 device -> ux_device_address == 0)
460 {
461
462 /* Check if the device is the one locks, others should wait. */
463 if (device != _ux_system_host -> ux_system_host_enum_lock)
464 {
465
466 /* Wait, return. */
467 UX_RESTORE
468 return;
469 }
470 }
471 UX_RESTORE
472
473 while (immediate_state)
474 {
475 switch (device -> ux_device_enum_state)
476 {
477 case UX_STATE_RESET:
478
479 /* Reset retry counts. */
480 device -> ux_device_enum_retry = UX_RH_ENUMERATION_RETRY;
481
482 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_PORT_ENABLE;
483 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_PORT_ENABLE;
484 device -> ux_device_enum_port_status = UX_PS_CCS;
485
486 /* Fall through. */
487 case UX_HOST_STACK_ENUM_PORT_ENABLE:
488
489 /* Lock enumeration any way. */
490 _ux_system_host -> ux_system_host_enum_lock = device;
491
492 #if UX_MAX_DEVICES > 1
493 if (UX_DEVICE_PARENT_IS_HUB(device))
494 {
495
496 /* Issue a port reset on hub side. */
497 device -> ux_device_flags |= UX_DEVICE_FLAG_RESET;
498 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_HUB_OPERATION_WAIT;
499 return;
500 }
501 #endif
502
503 /* For device connected to roohub, we may need port enable (OHCI). */
504 status = _ux_host_stack_rh_port_enable(device);
505 if (status == UX_PORT_INDEX_UNKNOWN)
506 {
507
508 /* No retry, enumeration fail. */
509 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
510 continue;
511 }
512
513 /* Wait a while after port connection. */
514 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_PORT_RESET;
515 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_WAIT;
516 device -> ux_device_enum_wait_start = _ux_utility_time_get();
517 device -> ux_device_enum_wait_ms =
518 UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY);
519 continue;
520
521 #if UX_MAX_DEVICES > 1
522 case UX_HOST_STACK_ENUM_HUB_OPERATION_WAIT:
523
524 /* Keep waiting, state is changed in hub tasks. */
525 return;
526 #endif
527
528 case UX_HOST_STACK_ENUM_PORT_RESET:
529
530 /* Reset may blocking, wait the reset done. */
531 /* Fall through. */
532 case UX_HOST_STACK_ENUM_PORT_RESET_WAIT:
533
534 /* Run states for reset. */
535 status = _ux_host_stack_rh_port_reset(device);
536
537 /* Check fatal error (exit enumeration). */
538 if (status < UX_STATE_ERROR)
539 {
540
541 /* Fail no retry. */
542 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
543 continue;
544 }
545
546 /* Check error. */
547 if (status == UX_STATE_ERROR)
548 {
549
550 /* Fail retry. */
551 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
552 continue;
553 }
554
555 /* Ready for next state. */
556 if (status == UX_STATE_NEXT)
557 {
558
559 /* Return device address to 0. */
560 #if UX_MAX_DEVICES > 1
561 if (device -> ux_device_address)
562 {
563
564 /* Free the address. */
565 UX_DEVICE_HCD_GET(device) ->
566 ux_hcd_address[(device -> ux_device_address-1) >> 3] &=
567 (UCHAR)(1u << ((device -> ux_device_address-1) & 7u));
568 }
569 #endif
570
571 /* Get port status. */
572 status = _ux_host_stack_rh_port_status_get(device);
573 if (status == UX_PORT_INDEX_UNKNOWN)
574 {
575
576 /* Fail no retry: No connection. */
577 device -> ux_device_enum_port_status = 0;
578 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
579 continue;
580 }
581
582 /* Save port status, next : SetAddress. */
583 device -> ux_device_enum_port_status = (UCHAR)status;
584 device -> ux_device_enum_trans = &device ->
585 ux_device_control_endpoint.ux_endpoint_transfer_request;
586 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_LOCK_WAIT;
587 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_DEVICE_ADDR_SET;
588 continue;
589 }
590
591 /* Keep waiting. */
592 return;
593
594 case UX_HOST_STACK_ENUM_DEVICE_ADDR_SET:
595
596 /* Check port connection status. */
597 if ((device -> ux_device_enum_port_status & UX_PS_CCS) == 0)
598 {
599
600 /* Port disconnected, no retry, just fail. */
601 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
602 continue;
603 }
604
605 /* Set device speed. */
606 device -> ux_device_speed = device -> ux_device_enum_port_status >> UX_PS_DS;
607
608 /* Reset bMaxPacketSize0. */
609 device -> ux_device_descriptor.bMaxPacketSize0 = 0;
610
611 /* Start SetAddress(). */
612 status = _ux_host_stack_device_address_set(device);
613 if (status != UX_SUCCESS)
614 {
615
616 /* Request fail, retry. */
617 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
618 continue;
619 }
620
621 /* Wait request progress done. */
622 UX_TRANSFER_STATE_RESET(device -> ux_device_enum_trans);
623 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_WAIT;
624 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_DEVICE_ADDR_SENT;
625 continue;
626
627 case UX_HOST_STACK_ENUM_DEVICE_ADDR_SENT:
628
629 /* Transfer error check. */
630 trans = &device -> ux_device_control_endpoint.ux_endpoint_transfer_request;
631 if (trans -> ux_transfer_request_completion_code != UX_SUCCESS)
632 {
633 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
634 continue;
635 }
636
637 /* Address is already sent to device. */
638 _ux_host_stack_enum_address_sent(device);
639
640 /* Wait at least 2ms after address is sent. */
641 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_DEVICE_DESCR_READ;
642 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_WAIT;
643 device -> ux_device_enum_wait_start = _ux_utility_time_get();
644 device -> ux_device_enum_wait_ms = UX_MS_TO_TICK_NON_ZERO(2);
645 continue;
646
647 case UX_HOST_STACK_ENUM_DEVICE_DESCR_READ:
648
649 /* Start GetDescriptor(Device). */
650 status = _ux_host_stack_device_descriptor_read(device);
651 if (status != UX_SUCCESS)
652 {
653 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
654 continue;
655 }
656 UX_TRANSFER_STATE_RESET(device -> ux_device_enum_trans);
657 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_WAIT;
658 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_DEVICE_DESCR_PARSE;
659 continue;
660
661 case UX_HOST_STACK_ENUM_DEVICE_DESCR_PARSE:
662
663 /* Transfer error check. */
664 trans = &device -> ux_device_control_endpoint.ux_endpoint_transfer_request;
665 buffer = trans -> ux_transfer_request_data_pointer;
666 if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
667 {
668 _ux_utility_memory_free(buffer);
669 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
670 continue;
671 }
672
673 /* Device bMaxPacketSize0 not available, update it. */
674 if(device -> ux_device_descriptor.bMaxPacketSize0 == 0)
675 {
676 /* Validate the bMaxPacketSize0. */
677 if (buffer[7] != 8 && buffer[7] != 16 && buffer[7] != 32 && buffer[7] != 64)
678 {
679
680 _ux_utility_memory_free(buffer);
681 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
682 continue;
683 }
684
685 /* Validate the USB-IF bDeviceClass class code. */
686 #if defined(UX_HOST_DEVICE_CLASS_CODE_VALIDATION_ENABLE)
687 switch(buffer[4])
688 {
689 case 0x00: /* Fall through. */
690 case 0x02: /* Fall through. */
691 case 0x09: /* Fall through. */
692 case 0x11: /* Fall through. */
693 case 0xDC: /* Fall through. */
694 case 0xEF: /* Fall through. */
695 case 0xFF:
696 break;
697 default:
698
699 /* Invalid device class code. */
700 _ux_utility_memory_free(buffer);
701 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
702 continue;
703 }
704 #endif
705
706 _ux_host_stack_enum_device_descriptor_parse0(device, buffer);
707
708 /* Update SETUP wLength. */
709 trans -> ux_transfer_request_requested_length = UX_DEVICE_DESCRIPTOR_LENGTH;
710
711 /* Issue GetDescriptor(Device) again and parse it. */
712 device -> ux_device_enum_trans = trans;
713 UX_TRANSFER_STATE_RESET(trans);
714 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_WAIT;
715 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_DEVICE_DESCR_PARSE;
716 continue;
717 }
718
719 /* Parse the device descriptor. */
720 _ux_utility_descriptor_parse(buffer,
721 _ux_system_device_descriptor_structure, UX_DEVICE_DESCRIPTOR_ENTRIES,
722 (UCHAR *) &device -> ux_device_descriptor);
723 _ux_utility_memory_free(buffer);
724 trans -> ux_transfer_request_data_pointer = UX_NULL;
725
726 /* Start configuration enumeration, from index 0. */
727 device -> ux_device_enum_index = 0;
728
729 /* Fall through. */
730 case UX_HOST_STACK_ENUM_CONFIG_DESCR_READ:
731
732 /* Start GetDescriptor(Configuration, 9). */
733 status = _ux_host_stack_enum_configuration_read(device);
734 if (status != UX_SUCCESS)
735 {
736 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
737 continue;
738 }
739 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_WAIT;
740 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE;
741
742 /* In this case, there are two memory blocks allocated floating:
743 - UX_CONFIGURATION
744 - configuration descriptor RX buffer. */
745 continue;
746
747 case UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE:
748
749 /* Transfer error check. */
750 trans = &device -> ux_device_control_endpoint.ux_endpoint_transfer_request;
751 buffer = trans -> ux_transfer_request_data_pointer;
752 if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
753 {
754 _ux_utility_memory_free(buffer);
755 _ux_utility_memory_free(device -> ux_device_enum_inst.ptr);
756 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
757 continue;
758 }
759
760 /* Load current parsing configuration. */
761 configuration = device -> ux_device_enum_inst.configuration;
762
763 /* Get configuration descriptor only. */
764 if (trans -> ux_transfer_request_actual_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH)
765 {
766
767 /* Parse the configuration descriptor and free descriptor buffer. */
768 _ux_host_stack_enum_configuration_descriptor_parse0(device, configuration, buffer);
769
770 /* Release descriptor buffer. */
771 _ux_utility_memory_free(buffer);
772 trans -> ux_transfer_request_data_pointer = UX_NULL;
773
774 /* If there is no interface for the configuration, check next. */
775 if (configuration -> ux_configuration_descriptor.wTotalLength ==
776 UX_CONFIGURATION_DESCRIPTOR_LENGTH)
777 {
778 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_CONFIG_DESCR_NEXT;
779 continue;
780 }
781
782 /* Allocate new buffer for total configuration. */
783 buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN,
784 UX_CACHE_SAFE_MEMORY,
785 configuration -> ux_configuration_descriptor.wTotalLength);
786 if (buffer == UX_NULL)
787 {
788 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
789 continue;
790 }
791 trans -> ux_transfer_request_data_pointer = buffer;
792
793 /* Modify transfer length for total configuration */
794 trans -> ux_transfer_request_requested_length =
795 configuration -> ux_configuration_descriptor.wTotalLength;
796
797 /* Start transfer again. */
798 device -> ux_device_enum_trans = trans;
799 UX_TRANSFER_STATE_RESET(device -> ux_device_enum_trans);
800 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_WAIT;
801 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE;
802
803 /* In this case, there is one memory blocks allocated floating:
804 - configuration descriptor RX buffer. */
805 continue;
806 }
807
808 /* Parse configuration and it's interfaces. */
809 status = _ux_host_stack_interfaces_scan(configuration, buffer);
810
811 /* Release descriptor memory. */
812 _ux_utility_memory_free(buffer);
813 trans -> ux_transfer_request_data_pointer = UX_NULL;
814
815 /* Check operation status. */
816 if (status != UX_SUCCESS)
817 {
818 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
819 continue;
820 }
821
822 /* Enumerate next configuration. */
823 /* Fall through. */
824 case UX_HOST_STACK_ENUM_CONFIG_DESCR_NEXT:
825 device -> ux_device_enum_index ++;
826 if (device -> ux_device_enum_index <
827 device -> ux_device_descriptor.bNumConfigurations)
828 {
829 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_CONFIG_DESCR_READ;
830 continue;
831 }
832
833 /* All configurations are enumerated. */
834 _ux_host_stack_configuration_parsed(device);
835
836 /* Roll back to next state. */
837 continue;
838
839 case UX_HOST_STACK_ENUM_CONFIG_SET:
840
841 /* The device is now in the unconfigured state. We need to deal
842 with the amount of power the device is consuming before allowing
843 it to be configured. Otherwise we may run the risk of an over
844 current fault. */
845 configuration = device -> ux_device_enum_inst.configuration;
846 if (((configuration -> ux_configuration_descriptor.bmAttributes &
847 UX_CONFIGURATION_DEVICE_SELF_POWERED) == 0) &&
848 (configuration -> ux_configuration_descriptor.MaxPower >
849 UX_DEVICE_MAX_POWER_GET(device)))
850 {
851
852 /* Error trap. */
853 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_OVER_CURRENT_CONDITION);
854
855 /* If trace is enabled, insert this event into the trace buffer. */
856 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_OVER_CURRENT_CONDITION, configuration, 0, 0, UX_TRACE_ERRORS, 0, 0)
857
858 /* Enumeration fail without retry. */
859 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
860 continue;
861 }
862
863 /* Prepare transfer request SetConfiguration(). */
864 _ux_host_stack_configuration_set(configuration);
865
866 /* Roll back to start transfer wait. */
867 UX_TRANSFER_STATE_RESET(device -> ux_device_enum_trans);
868 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_CONFIG_ACTIVATE;
869 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_TRANS_WAIT;
870 continue;
871
872 case UX_HOST_STACK_ENUM_CONFIG_ACTIVATE:
873 trans = &device -> ux_device_control_endpoint.ux_endpoint_transfer_request;
874 if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
875 {
876 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
877 continue;
878 }
879
880 /* Set device state to configured. */
881 configuration = device -> ux_device_enum_inst.configuration;
882 device -> ux_device_state = UX_DEVICE_CONFIGURED;
883 device -> ux_device_current_configuration = configuration;
884
885 /* Create the configuration instance. */
886 status = _ux_host_stack_configuration_instance_create(configuration);
887 if (status != UX_SUCCESS)
888 {
889 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
890 continue;
891 }
892
893 if (configuration -> ux_configuration_first_interface)
894 {
895
896 /* Activate classes. */
897 device -> ux_device_enum_index = 0;
898 device -> ux_device_enum_inst.interface =
899 configuration -> ux_configuration_first_interface;
900 }
901 else
902 {
903
904 /* No activation, done */
905 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_DONE;
906 continue;
907 }
908
909 /* Fall through. */
910 case UX_HOST_STACK_ENUM_ACTIVATE:
911
912 /* Class activate. */
913 class_command.ux_host_class_command_request = UX_HOST_CLASS_COMMAND_ACTIVATE_START;
914 if (device -> ux_device_enum_index == 0xFF)
915 {
916
917 /* Device class driver. */
918 class_command.ux_host_class_command_container = device;
919 class_command.ux_host_class_command_class_ptr = device -> ux_device_class;
920 }
921 else
922 {
923
924 /* Interface class driver. */
925 class_command.ux_host_class_command_container = device -> ux_device_enum_inst.ptr;
926 class_command.ux_host_class_command_class_ptr =
927 device -> ux_device_enum_inst.interface -> ux_interface_class;
928 }
929
930 /* If there class linked, start activation. */
931 if (class_command.ux_host_class_command_class_ptr != UX_NULL)
932 {
933 status = class_command.ux_host_class_command_class_ptr ->
934 ux_host_class_entry_function(&class_command);
935 if (status != UX_SUCCESS)
936 {
937 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
938 continue;
939 }
940 }
941
942 /* Class activate execute wait. */
943 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_ACTIVATE_WAIT;
944
945 /* Fall through. */
946 case UX_HOST_STACK_ENUM_ACTIVATE_WAIT:
947
948 /* Class activate execution wait. */
949 status = _ux_host_stack_interface_activate_wait(device, &class_command);
950
951 /* Next state. */
952 if (status != UX_STATE_WAIT)
953 continue;
954
955 /* Keep waiting. */
956 return;
957
958 case UX_HOST_STACK_ENUM_TRANS_WAIT:
959
960 /* Poll transfer task. */
961 trans = device -> ux_device_enum_trans;
962 status = _ux_host_stack_transfer_run(trans);
963
964 /* Transfer done - next state. */
965 if (status == UX_STATE_NEXT || status == UX_STATE_IDLE)
966 {
967 device -> ux_device_enum_trans = UX_NULL;
968 device -> ux_device_enum_state = device -> ux_device_enum_next_state;
969 continue;
970 }
971
972 /* Check error. */
973 if (status < UX_STATE_ERROR)
974 {
975
976 /* No retry, fail. */
977 if (trans -> ux_transfer_request_data_pointer)
978 {
979 _ux_utility_memory_free(trans -> ux_transfer_request_data_pointer);
980 trans -> ux_transfer_request_data_pointer = UX_NULL;
981 }
982 if (device -> ux_device_enum_next_state == UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE)
983 {
984 _ux_utility_memory_free(device -> ux_device_enum_inst.ptr);
985 device -> ux_device_enum_inst.ptr = UX_NULL;
986 }
987 device -> ux_device_enum_trans = UX_NULL;
988 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_FAIL;
989 continue;
990 }
991 if (status < UX_STATE_NEXT)
992 {
993
994 /* Error, retry. */
995 if (trans -> ux_transfer_request_data_pointer)
996 {
997 _ux_utility_memory_free(trans -> ux_transfer_request_data_pointer);
998 trans -> ux_transfer_request_data_pointer = UX_NULL;
999 }
1000 if (device -> ux_device_enum_next_state == UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE)
1001 {
1002 _ux_utility_memory_free(device -> ux_device_enum_inst.ptr);
1003 device -> ux_device_enum_inst.ptr = UX_NULL;
1004 }
1005 device -> ux_device_enum_trans = UX_NULL;
1006 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_RETRY;
1007 continue;
1008 }
1009
1010 /* Transfer in progress, wait. */
1011 return;
1012
1013 case UX_HOST_STACK_ENUM_TRANS_LOCK_WAIT:
1014 trans = device -> ux_device_enum_trans;
1015 UX_DISABLE
1016 if (trans -> ux_transfer_request_flags & UX_TRANSFER_FLAG_LOCK)
1017 {
1018
1019 /* Keep waiting. */
1020 UX_RESTORE;
1021 return;
1022 }
1023
1024 /* Lock it. */
1025 trans -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_LOCK;
1026 UX_RESTORE
1027
1028 /* Apply next expected state. */
1029 device -> ux_device_enum_state = device -> ux_device_enum_next_state;
1030 continue;
1031
1032 case UX_HOST_STACK_ENUM_WAIT:
1033 current_ms = _ux_utility_time_get();
1034 elapsed_ms = _ux_utility_time_elapsed(current_ms,
1035 device -> ux_device_enum_wait_start);
1036 if (elapsed_ms < device -> ux_device_enum_wait_ms)
1037
1038 /* Keep waiting. */
1039 return;
1040
1041 /* Next pre-defined state. */
1042 device -> ux_device_enum_state = device -> ux_device_enum_next_state;
1043 continue;
1044
1045 case UX_HOST_STACK_ENUM_RETRY:
1046
1047 /* Check remaining retry count. */
1048 if (device -> ux_device_enum_retry > 0)
1049 {
1050 device -> ux_device_enum_retry --;
1051
1052 /* Check if there is unnecessary resource to free. */
1053 if (device -> ux_device_packed_configuration &&
1054 device -> ux_device_packed_configuration_keep_count == 0)
1055 {
1056 _ux_utility_memory_free(device -> ux_device_packed_configuration);
1057 device -> ux_device_packed_configuration = UX_NULL;
1058 }
1059
1060 /* Start from port enable delay. */
1061 device -> ux_device_enum_next_state = UX_HOST_STACK_ENUM_PORT_RESET;
1062 device -> ux_device_enum_state = UX_HOST_STACK_ENUM_WAIT;
1063 device -> ux_device_enum_wait_start = _ux_utility_time_get();
1064 device -> ux_device_enum_wait_ms =
1065 UX_MS_TO_TICK_NON_ZERO(UX_RH_ENUMERATION_RETRY_DELAY);
1066 continue;
1067 }
1068
1069 /* Tried several times, fail case. */
1070 /* Fall through. */
1071 case UX_HOST_STACK_ENUM_FAIL:
1072
1073 /* Clear lock anyway. */
1074 if (device == _ux_system_host -> ux_system_host_enum_lock)
1075 _ux_system_host -> ux_system_host_enum_lock = UX_NULL;
1076
1077 /* Error trap. */
1078 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD,
1079 UX_DEVICE_PARENT_IS_HUB(device) ? UX_SYSTEM_CONTEXT_HUB :
1080 UX_SYSTEM_CONTEXT_ROOT_HUB,
1081 UX_DEVICE_ENUMERATION_FAILURE);
1082
1083 /* If trace is enabled, insert this event into the trace buffer. */
1084 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_ENUMERATION_FAILURE,
1085 UX_DEVICE_PORT_LOCATION_GET(device), 0, 0, UX_TRACE_ERRORS, 0, 0);
1086
1087 /* Fall through. */
1088 case UX_HOST_STACK_ENUM_DONE:
1089 _ux_host_stack_device_enumerated(device);
1090
1091 /* We are done now. */
1092 /* Fall through. */
1093 case UX_HOST_STACK_ENUM_IDLE:
1094
1095 /* Nothing to run. */
1096 return;
1097
1098 default:
1099
1100 /* Invalid state, reset. */
1101 device -> ux_device_enum_state = UX_STATE_RESET;
1102 }
1103
1104 /* Invalid unhandled state. */
1105 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HOST_STACK, UX_INVALID_STATE);
1106
1107 /* Break the immediate state loop. */
1108 immediate_state = UX_FALSE;
1109 }
1110 }
1111
_ux_host_stack_enum_run(VOID)1112 static inline VOID _ux_host_stack_enum_run(VOID)
1113 {
1114
1115 UX_DEVICE *enum_device;
1116
1117 /* Check if there is device pending enumeration. */
1118 enum_device = _ux_system_host -> ux_system_host_enum_device;
1119
1120 /* Run enumeration task for each device. */
1121 while(enum_device != UX_NULL)
1122 {
1123
1124 /* Run enumeration task on the device. */
1125 if ((enum_device -> ux_device_flags & UX_DEVICE_FLAG_PROTECT) == 0)
1126 {
1127 enum_device -> ux_device_flags |= UX_DEVICE_FLAG_PROTECT;
1128 _ux_host_stack_device_enum_run(enum_device);
1129 enum_device -> ux_device_flags &= ~UX_DEVICE_FLAG_PROTECT;
1130 }
1131
1132 /* Check device lock. */
1133 if (enum_device -> ux_device_flags & UX_DEVICE_FLAG_LOCK)
1134 {
1135 break;
1136 }
1137
1138 /* Check next enumerating device. */
1139 enum_device = enum_device -> ux_device_enum_next;
1140 }
1141 }
1142
_ux_host_stack_pending_transfers_run(VOID)1143 static inline VOID _ux_host_stack_pending_transfers_run(VOID)
1144 {
1145 UX_TRANSFER *transfer, *next;
1146 transfer = _ux_system_host -> ux_system_host_pending_transfers;
1147 while(transfer)
1148 {
1149 next = transfer -> ux_transfer_request_next_pending;
1150 _ux_host_stack_transfer_run(transfer);
1151 if (transfer == next || _ux_system_host -> ux_system_host_pending_transfers == next)
1152 break;
1153 transfer = next;
1154 }
1155 }
1156 #endif
1157