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