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