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