]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbHub.c
1 /** @file
2
3 Unified interface for RootHub and Hub.
4
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UsbBus.h"
11
12 //
13 // Array that maps the change bit to feature value which is
14 // used to clear these change bit. USB HUB API will clear
15 // these change bit automatically. For non-root hub, these
16 // bits determine whether hub will report the port in changed
17 // bit maps.
18 //
19 USB_CHANGE_FEATURE_MAP mHubFeatureMap[] = {
20 { USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange },
21 { USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange },
22 { USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange },
23 { USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange },
24 { USB_PORT_STAT_C_RESET, EfiUsbPortResetChange }
25 };
26
27 USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[] = {
28 { USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange },
29 { USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange },
30 { USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange },
31 { USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange },
32 { USB_PORT_STAT_C_RESET, EfiUsbPortResetChange },
33 };
34
35 //
36 // USB hub class specific requests. Although USB hub
37 // is related to an interface, these requests are sent
38 // to the control endpoint of the device.
39 //
40
41 /**
42 USB hub control transfer to set the hub depth.
43
44 @param HubDev The device of the hub.
45 @param Depth The depth to set.
46
47 @retval EFI_SUCCESS Depth of the hub is set.
48 @retval Others Failed to set the depth.
49
50 **/
51 EFI_STATUS
52 UsbHubCtrlSetHubDepth (
53 IN USB_DEVICE *HubDev,
54 IN UINT16 Depth
55 )
56 {
57 EFI_STATUS Status;
58
59 Status = UsbCtrlRequest (
60 HubDev,
61 EfiUsbNoData,
62 USB_REQ_TYPE_CLASS,
63 USB_HUB_TARGET_HUB,
64 USB_HUB_REQ_SET_DEPTH,
65 Depth,
66 0,
67 NULL,
68 0
69 );
70
71 return Status;
72 }
73
74 /**
75 USB hub control transfer to clear the hub feature.
76
77 @param HubDev The device of the hub.
78 @param Feature The feature to clear.
79
80 @retval EFI_SUCCESS Feature of the hub is cleared.
81 @retval Others Failed to clear the feature.
82
83 **/
84 EFI_STATUS
85 UsbHubCtrlClearHubFeature (
86 IN USB_DEVICE *HubDev,
87 IN UINT16 Feature
88 )
89 {
90 EFI_STATUS Status;
91
92 Status = UsbCtrlRequest (
93 HubDev,
94 EfiUsbNoData,
95 USB_REQ_TYPE_CLASS,
96 USB_HUB_TARGET_HUB,
97 USB_HUB_REQ_CLEAR_FEATURE,
98 Feature,
99 0,
100 NULL,
101 0
102 );
103
104 return Status;
105 }
106
107 /**
108 Clear the feature of the device's port.
109
110 @param HubDev The hub device.
111 @param Port The port to clear feature.
112 @param Feature The feature to clear.
113
114 @retval EFI_SUCCESS The feature of the port is cleared.
115 @retval Others Failed to clear the feature.
116
117 **/
118 EFI_STATUS
119 UsbHubCtrlClearPortFeature (
120 IN USB_DEVICE *HubDev,
121 IN UINT8 Port,
122 IN UINT16 Feature
123 )
124 {
125 EFI_STATUS Status;
126
127 //
128 // In USB bus, all the port index starts from 0. But HUB
129 // indexes its port from 1. So, port number is added one.
130 //
131 Status = UsbCtrlRequest (
132 HubDev,
133 EfiUsbNoData,
134 USB_REQ_TYPE_CLASS,
135 USB_HUB_TARGET_PORT,
136 USB_HUB_REQ_CLEAR_FEATURE,
137 Feature,
138 (UINT16)(Port + 1),
139 NULL,
140 0
141 );
142
143 return Status;
144 }
145
146 /**
147 Clear the transaction translate buffer if full/low
148 speed control/bulk transfer failed and the transfer
149 uses this hub as translator.Remember to clear the TT
150 buffer of transaction translator, not that of the
151 parent.
152
153 @param HubDev The hub device.
154 @param Port The port of the hub.
155 @param DevAddr Address of the failed transaction.
156 @param EpNum The endpoint number of the failed transaction.
157 @param EpType The type of failed transaction.
158
159 @retval EFI_SUCCESS The TT buffer is cleared.
160 @retval Others Failed to clear the TT buffer.
161
162 **/
163 EFI_STATUS
164 UsbHubCtrlClearTTBuffer (
165 IN USB_DEVICE *HubDev,
166 IN UINT8 Port,
167 IN UINT16 DevAddr,
168 IN UINT16 EpNum,
169 IN UINT16 EpType
170 )
171 {
172 EFI_STATUS Status;
173 UINT16 Value;
174
175 //
176 // Check USB2.0 spec page 424 for wValue's encoding
177 //
178 Value = (UINT16)((EpNum & 0x0F) | (DevAddr << 4) |
179 ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
180
181 Status = UsbCtrlRequest (
182 HubDev,
183 EfiUsbNoData,
184 USB_REQ_TYPE_CLASS,
185 USB_HUB_TARGET_PORT,
186 USB_HUB_REQ_CLEAR_TT,
187 Value,
188 (UINT16)(Port + 1),
189 NULL,
190 0
191 );
192
193 return Status;
194 }
195
196 /**
197 Usb hub control transfer to get the (super speed) hub descriptor.
198
199 @param HubDev The hub device.
200 @param Buf The buffer to hold the descriptor.
201 @param Len The length to retrieve.
202
203 @retval EFI_SUCCESS The hub descriptor is retrieved.
204 @retval Others Failed to retrieve the hub descriptor.
205
206 **/
207 EFI_STATUS
208 UsbHubCtrlGetHubDesc (
209 IN USB_DEVICE *HubDev,
210 OUT VOID *Buf,
211 IN UINTN Len
212 )
213 {
214 EFI_STATUS Status;
215 UINT8 DescType;
216
217 DescType = (HubDev->Speed == EFI_USB_SPEED_SUPER) ?
218 USB_DESC_TYPE_HUB_SUPER_SPEED :
219 USB_DESC_TYPE_HUB;
220
221 Status = UsbCtrlRequest (
222 HubDev,
223 EfiUsbDataIn,
224 USB_REQ_TYPE_CLASS,
225 USB_HUB_TARGET_HUB,
226 USB_HUB_REQ_GET_DESC,
227 (UINT16)(DescType << 8),
228 0,
229 Buf,
230 Len
231 );
232
233 return Status;
234 }
235
236 /**
237 Usb hub control transfer to get the hub status.
238
239 @param HubDev The hub device.
240 @param State The variable to return the status.
241
242 @retval EFI_SUCCESS The hub status is returned in State.
243 @retval Others Failed to get the hub status.
244
245 **/
246 EFI_STATUS
247 UsbHubCtrlGetHubStatus (
248 IN USB_DEVICE *HubDev,
249 OUT UINT32 *State
250 )
251 {
252 EFI_STATUS Status;
253
254 Status = UsbCtrlRequest (
255 HubDev,
256 EfiUsbDataIn,
257 USB_REQ_TYPE_CLASS,
258 USB_HUB_TARGET_HUB,
259 USB_HUB_REQ_GET_STATUS,
260 0,
261 0,
262 State,
263 4
264 );
265
266 return Status;
267 }
268
269 /**
270 Usb hub control transfer to get the port status.
271
272 @param HubDev The hub device.
273 @param Port The port of the hub.
274 @param State Variable to return the hub port state.
275
276 @retval EFI_SUCCESS The port state is returned in State.
277 @retval Others Failed to retrieve the port state.
278
279 **/
280 EFI_STATUS
281 UsbHubCtrlGetPortStatus (
282 IN USB_DEVICE *HubDev,
283 IN UINT8 Port,
284 OUT VOID *State
285 )
286 {
287 EFI_STATUS Status;
288
289 //
290 // In USB bus, all the port index starts from 0. But HUB
291 // indexes its port from 1. So, port number is added one.
292 // No need to convert the hub bit to UEFI definition, they
293 // are the same
294 //
295 Status = UsbCtrlRequest (
296 HubDev,
297 EfiUsbDataIn,
298 USB_REQ_TYPE_CLASS,
299 USB_HUB_TARGET_PORT,
300 USB_HUB_REQ_GET_STATUS,
301 0,
302 (UINT16)(Port + 1),
303 State,
304 4
305 );
306
307 return Status;
308 }
309
310 /**
311 Usb hub control transfer to set the port feature.
312
313 @param HubDev The Usb hub device.
314 @param Port The Usb port to set feature for.
315 @param Feature The feature to set.
316
317 @retval EFI_SUCCESS The feature is set for the port.
318 @retval Others Failed to set the feature.
319
320 **/
321 EFI_STATUS
322 UsbHubCtrlSetPortFeature (
323 IN USB_DEVICE *HubDev,
324 IN UINT8 Port,
325 IN UINT8 Feature
326 )
327 {
328 EFI_STATUS Status;
329
330 //
331 // In USB bus, all the port index starts from 0. But HUB
332 // indexes its port from 1. So, port number is added one.
333 //
334 Status = UsbCtrlRequest (
335 HubDev,
336 EfiUsbNoData,
337 USB_REQ_TYPE_CLASS,
338 USB_HUB_TARGET_PORT,
339 USB_HUB_REQ_SET_FEATURE,
340 Feature,
341 (UINT16)(Port + 1),
342 NULL,
343 0
344 );
345
346 return Status;
347 }
348
349 /**
350 Read the whole usb hub descriptor. It is necessary
351 to do it in two steps because hub descriptor is of
352 variable length.
353
354 @param HubDev The hub device.
355 @param HubDesc The variable to return the descriptor.
356
357 @retval EFI_SUCCESS The hub descriptor is read.
358 @retval Others Failed to read the hub descriptor.
359
360 **/
361 EFI_STATUS
362 UsbHubReadDesc (
363 IN USB_DEVICE *HubDev,
364 OUT EFI_USB_HUB_DESCRIPTOR *HubDesc
365 )
366 {
367 EFI_STATUS Status;
368
369 //
370 // First get the hub descriptor length
371 //
372 Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
373
374 if (EFI_ERROR (Status)) {
375 return Status;
376 }
377
378 //
379 // Get the whole hub descriptor
380 //
381 return UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
382 }
383
384 /**
385 Ack the hub change bits. If these bits are not ACKed, Hub will
386 always return changed bit map from its interrupt endpoint.
387
388 @param HubDev The hub device.
389
390 @retval EFI_SUCCESS The hub change status is ACKed.
391 @retval Others Failed to ACK the hub status.
392
393 **/
394 EFI_STATUS
395 UsbHubAckHubStatus (
396 IN USB_DEVICE *HubDev
397 )
398 {
399 EFI_USB_PORT_STATUS HubState;
400 EFI_STATUS Status;
401
402 Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *)&HubState);
403
404 if (EFI_ERROR (Status)) {
405 return Status;
406 }
407
408 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
409 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
410 }
411
412 if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
413 UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
414 }
415
416 return EFI_SUCCESS;
417 }
418
419 /**
420 Test whether the interface is a hub interface.
421
422 @param UsbIf The interface to test.
423
424 @retval TRUE The interface is a hub interface.
425 @retval FALSE The interface isn't a hub interface.
426
427 **/
428 BOOLEAN
429 UsbIsHubInterface (
430 IN USB_INTERFACE *UsbIf
431 )
432 {
433 EFI_USB_INTERFACE_DESCRIPTOR *Setting;
434
435 //
436 // If the hub is a high-speed hub with multiple TT,
437 // the hub will has a default setting of single TT.
438 //
439 Setting = &UsbIf->IfSetting->Desc;
440
441 if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
442 (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE))
443 {
444 return TRUE;
445 }
446
447 return FALSE;
448 }
449
450 /**
451 The callback function to the USB hub status change
452 interrupt endpoint. It is called periodically by
453 the underlying host controller.
454
455 @param Data The data read.
456 @param DataLength The length of the data read.
457 @param Context The context.
458 @param Result The result of the last interrupt transfer.
459
460 @retval EFI_SUCCESS The process is OK.
461 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
462
463 **/
464 EFI_STATUS
465 EFIAPI
466 UsbOnHubInterrupt (
467 IN VOID *Data,
468 IN UINTN DataLength,
469 IN VOID *Context,
470 IN UINT32 Result
471 )
472 {
473 USB_INTERFACE *HubIf;
474 EFI_USB_IO_PROTOCOL *UsbIo;
475 EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
476 EFI_STATUS Status;
477
478 HubIf = (USB_INTERFACE *)Context;
479 UsbIo = &(HubIf->UsbIo);
480 EpDesc = &(HubIf->HubEp->Desc);
481
482 if (Result != EFI_USB_NOERROR) {
483 //
484 // If endpoint is stalled, clear the stall. Use UsbIo to access
485 // the control transfer so internal status are maintained.
486 //
487 if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
488 UsbIoClearFeature (
489 UsbIo,
490 USB_TARGET_ENDPOINT,
491 USB_FEATURE_ENDPOINT_HALT,
492 EpDesc->EndpointAddress
493 );
494 }
495
496 //
497 // Delete and submit a new async interrupt
498 //
499 Status = UsbIo->UsbAsyncInterruptTransfer (
500 UsbIo,
501 EpDesc->EndpointAddress,
502 FALSE,
503 0,
504 0,
505 NULL,
506 NULL
507 );
508
509 if (EFI_ERROR (Status)) {
510 DEBUG ((DEBUG_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
511 return Status;
512 }
513
514 Status = UsbIo->UsbAsyncInterruptTransfer (
515 UsbIo,
516 EpDesc->EndpointAddress,
517 TRUE,
518 USB_HUB_POLL_INTERVAL,
519 HubIf->NumOfPort / 8 + 1,
520 UsbOnHubInterrupt,
521 HubIf
522 );
523
524 if (EFI_ERROR (Status)) {
525 DEBUG ((DEBUG_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
526 }
527
528 return Status;
529 }
530
531 if ((DataLength == 0) || (Data == NULL)) {
532 return EFI_SUCCESS;
533 }
534
535 //
536 // OK, actually something is changed, save the change map
537 // then signal the HUB to do enumeration. This is a good
538 // practise since UsbOnHubInterrupt is called in the context
539 // of host controller's AsyncInterrupt monitor.
540 //
541 HubIf->ChangeMap = AllocateZeroPool (DataLength);
542
543 if (HubIf->ChangeMap == NULL) {
544 return EFI_OUT_OF_RESOURCES;
545 }
546
547 CopyMem (HubIf->ChangeMap, Data, DataLength);
548 gBS->SignalEvent (HubIf->HubNotify);
549
550 return EFI_SUCCESS;
551 }
552
553 /**
554 Initialize the device for a non-root hub.
555
556 @param HubIf The USB hub interface.
557
558 @retval EFI_SUCCESS The hub is initialized.
559 @retval EFI_DEVICE_ERROR Failed to initialize the hub.
560
561 **/
562 EFI_STATUS
563 UsbHubInit (
564 IN USB_INTERFACE *HubIf
565 )
566 {
567 UINT8 HubDescBuffer[256];
568 EFI_USB_HUB_DESCRIPTOR *HubDesc;
569 USB_ENDPOINT_DESC *EpDesc;
570 USB_INTERFACE_SETTING *Setting;
571 EFI_USB_IO_PROTOCOL *UsbIo;
572 USB_DEVICE *HubDev;
573 EFI_STATUS Status;
574 UINT8 Index;
575 UINT8 NumEndpoints;
576 UINT16 Depth;
577
578 //
579 // Locate the interrupt endpoint for port change map
580 //
581 HubIf->IsHub = FALSE;
582 Setting = HubIf->IfSetting;
583 HubDev = HubIf->Device;
584 EpDesc = NULL;
585 NumEndpoints = Setting->Desc.NumEndpoints;
586
587 for (Index = 0; Index < NumEndpoints; Index++) {
588 ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
589
590 EpDesc = Setting->Endpoints[Index];
591
592 if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
593 (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT))
594 {
595 break;
596 }
597 }
598
599 if (Index == NumEndpoints) {
600 DEBUG ((DEBUG_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
601 return EFI_DEVICE_ERROR;
602 }
603
604 //
605 // The length field of descriptor is UINT8 type, so the buffer
606 // with 256 bytes is enough to hold the descriptor data.
607 //
608 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)HubDescBuffer;
609 Status = UsbHubReadDesc (HubDev, HubDesc);
610
611 if (EFI_ERROR (Status)) {
612 DEBUG ((DEBUG_ERROR, "UsbHubInit: failed to read HUB descriptor - %r\n", Status));
613 return Status;
614 }
615
616 HubIf->NumOfPort = HubDesc->NumPorts;
617
618 DEBUG ((DEBUG_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address, HubIf->NumOfPort));
619
620 //
621 // OK, set IsHub to TRUE. Now usb bus can handle this device
622 // as a working HUB. If failed earlier, bus driver will not
623 // recognize it as a hub. Other parts of the bus should be able
624 // to work.
625 //
626 HubIf->IsHub = TRUE;
627 HubIf->HubApi = &mUsbHubApi;
628 HubIf->HubEp = EpDesc;
629
630 if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
631 Depth = (UINT16)(HubIf->Device->Tier - 1);
632 DEBUG ((DEBUG_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));
633 UsbHubCtrlSetHubDepth (HubIf->Device, Depth);
634
635 for (Index = 0; Index < HubDesc->NumPorts; Index++) {
636 UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);
637 }
638 } else {
639 //
640 // Feed power to all the hub ports. It should be ok
641 // for both gang/individual powered hubs.
642 //
643 for (Index = 0; Index < HubDesc->NumPorts; Index++) {
644 UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE)USB_HUB_PORT_POWER);
645 }
646
647 //
648 // Update for the usb hub has no power on delay requirement
649 //
650 if (HubDesc->PwrOn2PwrGood > 0) {
651 gBS->Stall (HubDesc->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
652 }
653
654 UsbHubAckHubStatus (HubIf->Device);
655 }
656
657 //
658 // Create an event to enumerate the hub's port. On
659 //
660 Status = gBS->CreateEvent (
661 EVT_NOTIFY_SIGNAL,
662 TPL_CALLBACK,
663 UsbHubEnumeration,
664 HubIf,
665 &HubIf->HubNotify
666 );
667
668 if (EFI_ERROR (Status)) {
669 DEBUG ((
670 DEBUG_ERROR,
671 "UsbHubInit: failed to create signal for hub %d - %r\n",
672 HubDev->Address,
673 Status
674 ));
675
676 return Status;
677 }
678
679 //
680 // Create AsyncInterrupt to query hub port change endpoint
681 // periodically. If the hub ports are changed, hub will return
682 // changed port map from the interrupt endpoint. The port map
683 // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
684 // host change status).
685 //
686 UsbIo = &HubIf->UsbIo;
687 Status = UsbIo->UsbAsyncInterruptTransfer (
688 UsbIo,
689 EpDesc->Desc.EndpointAddress,
690 TRUE,
691 USB_HUB_POLL_INTERVAL,
692 HubIf->NumOfPort / 8 + 1,
693 UsbOnHubInterrupt,
694 HubIf
695 );
696
697 if (EFI_ERROR (Status)) {
698 DEBUG ((
699 DEBUG_ERROR,
700 "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
701 HubDev->Address,
702 Status
703 ));
704
705 gBS->CloseEvent (HubIf->HubNotify);
706 HubIf->HubNotify = NULL;
707
708 return Status;
709 }
710
711 DEBUG ((DEBUG_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
712 return Status;
713 }
714
715 /**
716 Get the port status. This function is required to
717 ACK the port change bits although it will return
718 the port changes in PortState. Bus enumeration code
719 doesn't need to ACK the port change bits.
720
721 @param HubIf The hub interface.
722 @param Port The port of the hub to get state.
723 @param PortState Variable to return the port state.
724
725 @retval EFI_SUCCESS The port status is successfully returned.
726 @retval Others Failed to return the status.
727
728 **/
729 EFI_STATUS
730 UsbHubGetPortStatus (
731 IN USB_INTERFACE *HubIf,
732 IN UINT8 Port,
733 OUT EFI_USB_PORT_STATUS *PortState
734 )
735 {
736 EFI_STATUS Status;
737
738 Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
739
740 return Status;
741 }
742
743 /**
744 Clear the port change status.
745
746 @param HubIf The hub interface.
747 @param Port The hub port.
748
749 **/
750 VOID
751 UsbHubClearPortChange (
752 IN USB_INTERFACE *HubIf,
753 IN UINT8 Port
754 )
755 {
756 EFI_USB_PORT_STATUS PortState;
757 USB_CHANGE_FEATURE_MAP *Map;
758 UINTN Index;
759 EFI_STATUS Status;
760
761 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
762
763 if (EFI_ERROR (Status)) {
764 return;
765 }
766
767 //
768 // OK, get the usb port status, now ACK the change bits.
769 // Don't return error when failed to clear the change bits.
770 // It may lead to extra port state report. USB bus should
771 // be able to handle this.
772 //
773 for (Index = 0; Index < ARRAY_SIZE (mHubFeatureMap); Index++) {
774 Map = &mHubFeatureMap[Index];
775
776 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
777 UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16)Map->Feature);
778 }
779 }
780 }
781
782 /**
783 Function to set the port feature for non-root hub.
784
785 @param HubIf The hub interface.
786 @param Port The port of the hub.
787 @param Feature The feature of the port to set.
788
789 @retval EFI_SUCCESS The hub port feature is set.
790 @retval Others Failed to set the port feature.
791
792 **/
793 EFI_STATUS
794 UsbHubSetPortFeature (
795 IN USB_INTERFACE *HubIf,
796 IN UINT8 Port,
797 IN EFI_USB_PORT_FEATURE Feature
798 )
799 {
800 EFI_STATUS Status;
801
802 Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8)Feature);
803
804 return Status;
805 }
806
807 /**
808 Interface function to clear the port feature for non-root hub.
809
810 @param HubIf The hub interface.
811 @param Port The port of the hub to clear feature for.
812 @param Feature The feature to clear.
813
814 @retval EFI_SUCCESS The port feature is cleared.
815 @retval Others Failed to clear the port feature.
816
817 **/
818 EFI_STATUS
819 UsbHubClearPortFeature (
820 IN USB_INTERFACE *HubIf,
821 IN UINT8 Port,
822 IN EFI_USB_PORT_FEATURE Feature
823 )
824 {
825 EFI_STATUS Status;
826
827 Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8)Feature);
828
829 return Status;
830 }
831
832 /**
833 Interface function to reset the port.
834
835 @param HubIf The hub interface.
836 @param Port The port to reset.
837
838 @retval EFI_SUCCESS The hub port is reset.
839 @retval EFI_TIMEOUT Failed to reset the port in time.
840 @retval Others Failed to reset the port.
841
842 **/
843 EFI_STATUS
844 UsbHubResetPort (
845 IN USB_INTERFACE *HubIf,
846 IN UINT8 Port
847 )
848 {
849 EFI_USB_PORT_STATUS PortState;
850 UINTN Index;
851 EFI_STATUS Status;
852
853 Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE)USB_HUB_PORT_RESET);
854
855 if (EFI_ERROR (Status)) {
856 return Status;
857 }
858
859 //
860 // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
861 // section 7.1.7.5 for timing requirements.
862 //
863 gBS->Stall (USB_SET_PORT_RESET_STALL);
864
865 //
866 // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
867 //
868 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
869
870 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
871 Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
872
873 if (EFI_ERROR (Status)) {
874 return Status;
875 }
876
877 if (!EFI_ERROR (Status) &&
878 USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET))
879 {
880 gBS->Stall (USB_SET_PORT_RECOVERY_STALL);
881 return EFI_SUCCESS;
882 }
883
884 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
885 }
886
887 return EFI_TIMEOUT;
888 }
889
890 /**
891 Release the hub's control of the interface.
892
893 @param HubIf The hub interface.
894
895 @retval EFI_SUCCESS The interface is release of hub control.
896
897 **/
898 EFI_STATUS
899 UsbHubRelease (
900 IN USB_INTERFACE *HubIf
901 )
902 {
903 EFI_USB_IO_PROTOCOL *UsbIo;
904 EFI_STATUS Status;
905
906 UsbIo = &HubIf->UsbIo;
907 Status = UsbIo->UsbAsyncInterruptTransfer (
908 UsbIo,
909 HubIf->HubEp->Desc.EndpointAddress,
910 FALSE,
911 USB_HUB_POLL_INTERVAL,
912 0,
913 NULL,
914 0
915 );
916
917 if (EFI_ERROR (Status)) {
918 return Status;
919 }
920
921 gBS->CloseEvent (HubIf->HubNotify);
922
923 HubIf->IsHub = FALSE;
924 HubIf->HubApi = NULL;
925 HubIf->HubEp = NULL;
926 HubIf->HubNotify = NULL;
927
928 DEBUG ((DEBUG_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
929 return EFI_SUCCESS;
930 }
931
932 /**
933 Initialize the interface for root hub.
934
935 @param HubIf The root hub interface.
936
937 @retval EFI_SUCCESS The interface is initialized for root hub.
938 @retval Others Failed to initialize the hub.
939
940 **/
941 EFI_STATUS
942 UsbRootHubInit (
943 IN USB_INTERFACE *HubIf
944 )
945 {
946 EFI_STATUS Status;
947 UINT8 MaxSpeed;
948 UINT8 NumOfPort;
949 UINT8 Support64;
950
951 Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
952
953 if (EFI_ERROR (Status)) {
954 return Status;
955 }
956
957 DEBUG ((
958 DEBUG_INFO,
959 "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",
960 HubIf,
961 MaxSpeed,
962 NumOfPort
963 ));
964
965 HubIf->IsHub = TRUE;
966 HubIf->HubApi = &mUsbRootHubApi;
967 HubIf->HubEp = NULL;
968 HubIf->MaxSpeed = MaxSpeed;
969 HubIf->NumOfPort = NumOfPort;
970 HubIf->HubNotify = NULL;
971
972 //
973 // Create a timer to poll root hub ports periodically
974 //
975 Status = gBS->CreateEvent (
976 EVT_TIMER | EVT_NOTIFY_SIGNAL,
977 TPL_CALLBACK,
978 UsbRootHubEnumeration,
979 HubIf,
980 &HubIf->HubNotify
981 );
982
983 if (EFI_ERROR (Status)) {
984 return Status;
985 }
986
987 //
988 // It should signal the event immediately here, or device detection
989 // by bus enumeration might be delayed by the timer interval.
990 //
991 gBS->SignalEvent (HubIf->HubNotify);
992
993 Status = gBS->SetTimer (
994 HubIf->HubNotify,
995 TimerPeriodic,
996 USB_ROOTHUB_POLL_INTERVAL
997 );
998
999 if (EFI_ERROR (Status)) {
1000 gBS->CloseEvent (HubIf->HubNotify);
1001 }
1002
1003 return Status;
1004 }
1005
1006 /**
1007 Get the port status. This function is required to
1008 ACK the port change bits although it will return
1009 the port changes in PortState. Bus enumeration code
1010 doesn't need to ACK the port change bits.
1011
1012 @param HubIf The root hub interface.
1013 @param Port The root hub port to get the state.
1014 @param PortState Variable to return the port state.
1015
1016 @retval EFI_SUCCESS The port state is returned.
1017 @retval Others Failed to retrieve the port state.
1018
1019 **/
1020 EFI_STATUS
1021 UsbRootHubGetPortStatus (
1022 IN USB_INTERFACE *HubIf,
1023 IN UINT8 Port,
1024 OUT EFI_USB_PORT_STATUS *PortState
1025 )
1026 {
1027 USB_BUS *Bus;
1028 EFI_STATUS Status;
1029
1030 Bus = HubIf->Device->Bus;
1031 Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
1032
1033 return Status;
1034 }
1035
1036 /**
1037 Clear the port change status.
1038
1039 @param HubIf The root hub interface.
1040 @param Port The root hub port.
1041
1042 **/
1043 VOID
1044 UsbRootHubClearPortChange (
1045 IN USB_INTERFACE *HubIf,
1046 IN UINT8 Port
1047 )
1048 {
1049 EFI_USB_PORT_STATUS PortState;
1050 USB_CHANGE_FEATURE_MAP *Map;
1051 UINTN Index;
1052 EFI_STATUS Status;
1053
1054 Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
1055
1056 if (EFI_ERROR (Status)) {
1057 return;
1058 }
1059
1060 //
1061 // OK, get the usb port status, now ACK the change bits.
1062 // Don't return error when failed to clear the change bits.
1063 // It may lead to extra port state report. USB bus should
1064 // be able to handle this.
1065 //
1066 for (Index = 0; Index < ARRAY_SIZE (mRootHubFeatureMap); Index++) {
1067 Map = &mRootHubFeatureMap[Index];
1068
1069 if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
1070 UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE)Map->Feature);
1071 }
1072 }
1073 }
1074
1075 /**
1076 Set the root hub port feature.
1077
1078 @param HubIf The Usb hub interface.
1079 @param Port The hub port.
1080 @param Feature The feature to set.
1081
1082 @retval EFI_SUCCESS The root hub port is set with the feature.
1083 @retval Others Failed to set the feature.
1084
1085 **/
1086 EFI_STATUS
1087 UsbRootHubSetPortFeature (
1088 IN USB_INTERFACE *HubIf,
1089 IN UINT8 Port,
1090 IN EFI_USB_PORT_FEATURE Feature
1091 )
1092 {
1093 EFI_STATUS Status;
1094
1095 Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1096
1097 return Status;
1098 }
1099
1100 /**
1101 Clear the root hub port feature.
1102
1103 @param HubIf The root hub interface.
1104 @param Port The root hub port.
1105 @param Feature The feature to clear.
1106
1107 @retval EFI_SUCCESS The root hub port is cleared of the feature.
1108 @retval Others Failed to clear the feature.
1109
1110 **/
1111 EFI_STATUS
1112 UsbRootHubClearPortFeature (
1113 IN USB_INTERFACE *HubIf,
1114 IN UINT8 Port,
1115 IN EFI_USB_PORT_FEATURE Feature
1116 )
1117 {
1118 EFI_STATUS Status;
1119
1120 Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1121
1122 return Status;
1123 }
1124
1125 /**
1126 Interface function to reset the root hub port.
1127
1128 @param RootIf The root hub interface.
1129 @param Port The port to reset.
1130
1131 @retval EFI_SUCCESS The hub port is reset.
1132 @retval EFI_TIMEOUT Failed to reset the port in time.
1133 @retval EFI_NOT_FOUND The low/full speed device connected to high speed.
1134 root hub is released to the companion UHCI.
1135 @retval Others Failed to reset the port.
1136
1137 **/
1138 EFI_STATUS
1139 UsbRootHubResetPort (
1140 IN USB_INTERFACE *RootIf,
1141 IN UINT8 Port
1142 )
1143 {
1144 USB_BUS *Bus;
1145 EFI_STATUS Status;
1146 EFI_USB_PORT_STATUS PortState;
1147 UINTN Index;
1148
1149 //
1150 // Notice: although EHCI requires that ENABLED bit be cleared
1151 // when reset the port, we don't need to care that here. It
1152 // should be handled in the EHCI driver.
1153 //
1154 Bus = RootIf->Device->Bus;
1155
1156 Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1157
1158 if (EFI_ERROR (Status)) {
1159 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
1160 return Status;
1161 }
1162
1163 //
1164 // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1165 // section 7.1.7.5 for timing requirements.
1166 //
1167 gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);
1168
1169 Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1170
1171 if (EFI_ERROR (Status)) {
1172 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
1173 return Status;
1174 }
1175
1176 gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);
1177
1178 //
1179 // USB host controller won't clear the RESET bit until
1180 // reset is actually finished.
1181 //
1182 ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
1183
1184 for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1185 Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
1186
1187 if (EFI_ERROR (Status)) {
1188 return Status;
1189 }
1190
1191 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
1192 break;
1193 }
1194
1195 gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
1196 }
1197
1198 if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1199 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
1200 return EFI_TIMEOUT;
1201 }
1202
1203 if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
1204 //
1205 // OK, the port is reset. If root hub is of high speed and
1206 // the device is of low/full speed, release the ownership to
1207 // companion UHCI. If root hub is of full speed, it won't
1208 // automatically enable the port, we need to enable it manually.
1209 //
1210 if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
1211 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
1212
1213 UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
1214 return EFI_NOT_FOUND;
1215 } else {
1216 Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
1217
1218 if (EFI_ERROR (Status)) {
1219 DEBUG ((DEBUG_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
1220 return Status;
1221 }
1222
1223 gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);
1224 }
1225 }
1226
1227 return EFI_SUCCESS;
1228 }
1229
1230 /**
1231 Release the root hub's control of the interface.
1232
1233 @param HubIf The root hub interface.
1234
1235 @retval EFI_SUCCESS The root hub's control of the interface is
1236 released.
1237
1238 **/
1239 EFI_STATUS
1240 UsbRootHubRelease (
1241 IN USB_INTERFACE *HubIf
1242 )
1243 {
1244 DEBUG ((DEBUG_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));
1245
1246 gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
1247 gBS->CloseEvent (HubIf->HubNotify);
1248
1249 return EFI_SUCCESS;
1250 }
1251
1252 USB_HUB_API mUsbHubApi = {
1253 UsbHubInit,
1254 UsbHubGetPortStatus,
1255 UsbHubClearPortChange,
1256 UsbHubSetPortFeature,
1257 UsbHubClearPortFeature,
1258 UsbHubResetPort,
1259 UsbHubRelease
1260 };
1261
1262 USB_HUB_API mUsbRootHubApi = {
1263 UsbRootHubInit,
1264 UsbRootHubGetPortStatus,
1265 UsbRootHubClearPortChange,
1266 UsbRootHubSetPortFeature,
1267 UsbRootHubClearPortFeature,
1268 UsbRootHubResetPort,
1269 UsbRootHubRelease
1270 };