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