]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / Ehci.c
1 /** @file
2 The Ehci controller driver.
3
4 EhciDxe driver is responsible for managing the behavior of EHCI controller.
5 It implements the interfaces of monitoring the status of all ports and transferring
6 Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.
7
8 Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
9 to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or
10 OHCI controller. This way avoids the control transfer on a shared port between EHCI
11 and companion host controller when UHCI or OHCI gets attached earlier than EHCI and a
12 USB 2.0 device inserts.
13
14 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
15 SPDX-License-Identifier: BSD-2-Clause-Patent
16
17 **/
18
19 #include "Ehci.h"
20
21 //
22 // Two arrays used to translate the EHCI port state (change)
23 // to the UEFI protocol's port state (change).
24 //
25 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
26 { PORTSC_CONN, USB_PORT_STAT_CONNECTION },
27 { PORTSC_ENABLED, USB_PORT_STAT_ENABLE },
28 { PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND },
29 { PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT },
30 { PORTSC_RESET, USB_PORT_STAT_RESET },
31 { PORTSC_POWER, USB_PORT_STAT_POWER },
32 { PORTSC_OWNER, USB_PORT_STAT_OWNER }
33 };
34
35 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
36 { PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION },
37 { PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE },
38 { PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT }
39 };
40
41 EFI_DRIVER_BINDING_PROTOCOL
42 gEhciDriverBinding = {
43 EhcDriverBindingSupported,
44 EhcDriverBindingStart,
45 EhcDriverBindingStop,
46 0x30,
47 NULL,
48 NULL
49 };
50
51 /**
52 Retrieves the capability of root hub ports.
53
54 @param This This EFI_USB_HC_PROTOCOL instance.
55 @param MaxSpeed Max speed supported by the controller.
56 @param PortNumber Number of the root hub ports.
57 @param Is64BitCapable Whether the controller supports 64-bit memory
58 addressing.
59
60 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
61 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
62
63 **/
64 EFI_STATUS
65 EFIAPI
66 EhcGetCapability (
67 IN EFI_USB2_HC_PROTOCOL *This,
68 OUT UINT8 *MaxSpeed,
69 OUT UINT8 *PortNumber,
70 OUT UINT8 *Is64BitCapable
71 )
72 {
73 USB2_HC_DEV *Ehc;
74 EFI_TPL OldTpl;
75
76 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
77 return EFI_INVALID_PARAMETER;
78 }
79
80 OldTpl = gBS->RaiseTPL (EHC_TPL);
81 Ehc = EHC_FROM_THIS (This);
82
83 *MaxSpeed = EFI_USB_SPEED_HIGH;
84 *PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
85 *Is64BitCapable = (UINT8)Ehc->Support64BitDma;
86
87 DEBUG ((DEBUG_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
88
89 gBS->RestoreTPL (OldTpl);
90 return EFI_SUCCESS;
91 }
92
93 /**
94 Provides software reset for the USB host controller.
95
96 @param This This EFI_USB2_HC_PROTOCOL instance.
97 @param Attributes A bit mask of the reset operation to perform.
98
99 @retval EFI_SUCCESS The reset operation succeeded.
100 @retval EFI_INVALID_PARAMETER Attributes is not valid.
101 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
102 not currently supported by the host controller.
103 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
104
105 **/
106 EFI_STATUS
107 EFIAPI
108 EhcReset (
109 IN EFI_USB2_HC_PROTOCOL *This,
110 IN UINT16 Attributes
111 )
112 {
113 USB2_HC_DEV *Ehc;
114 EFI_TPL OldTpl;
115 EFI_STATUS Status;
116
117 Ehc = EHC_FROM_THIS (This);
118
119 if (Ehc->DevicePath != NULL) {
120 //
121 // Report Status Code to indicate reset happens
122 //
123 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
124 EFI_PROGRESS_CODE,
125 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
126 Ehc->DevicePath
127 );
128 }
129
130 OldTpl = gBS->RaiseTPL (EHC_TPL);
131
132 switch (Attributes) {
133 case EFI_USB_HC_RESET_GLOBAL:
134 //
135 // Flow through, same behavior as Host Controller Reset
136 //
137 case EFI_USB_HC_RESET_HOST_CONTROLLER:
138 //
139 // Host Controller must be Halt when Reset it
140 //
141 if (EhcIsDebugPortInUse (Ehc, NULL)) {
142 Status = EFI_SUCCESS;
143 goto ON_EXIT;
144 }
145
146 if (!EhcIsHalt (Ehc)) {
147 Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
148
149 if (EFI_ERROR (Status)) {
150 Status = EFI_DEVICE_ERROR;
151 goto ON_EXIT;
152 }
153 }
154
155 //
156 // Clean up the asynchronous transfers, currently only
157 // interrupt supports asynchronous operation.
158 //
159 EhciDelAllAsyncIntTransfers (Ehc);
160 EhcAckAllInterrupt (Ehc);
161 EhcFreeSched (Ehc);
162
163 Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
164
165 if (EFI_ERROR (Status)) {
166 goto ON_EXIT;
167 }
168
169 Status = EhcInitHC (Ehc);
170 break;
171
172 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
173 case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
174 Status = EFI_UNSUPPORTED;
175 break;
176
177 default:
178 Status = EFI_INVALID_PARAMETER;
179 }
180
181 ON_EXIT:
182 DEBUG ((DEBUG_INFO, "EhcReset: exit status %r\n", Status));
183 gBS->RestoreTPL (OldTpl);
184 return Status;
185 }
186
187 /**
188 Retrieve the current state of the USB host controller.
189
190 @param This This EFI_USB2_HC_PROTOCOL instance.
191 @param State Variable to return the current host controller
192 state.
193
194 @retval EFI_SUCCESS Host controller state was returned in State.
195 @retval EFI_INVALID_PARAMETER State is NULL.
196 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
197 retrieve the host controller's current state.
198
199 **/
200 EFI_STATUS
201 EFIAPI
202 EhcGetState (
203 IN EFI_USB2_HC_PROTOCOL *This,
204 OUT EFI_USB_HC_STATE *State
205 )
206 {
207 EFI_TPL OldTpl;
208 USB2_HC_DEV *Ehc;
209
210 if (State == NULL) {
211 return EFI_INVALID_PARAMETER;
212 }
213
214 OldTpl = gBS->RaiseTPL (EHC_TPL);
215 Ehc = EHC_FROM_THIS (This);
216
217 if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
218 *State = EfiUsbHcStateHalt;
219 } else {
220 *State = EfiUsbHcStateOperational;
221 }
222
223 gBS->RestoreTPL (OldTpl);
224
225 DEBUG ((DEBUG_INFO, "EhcGetState: current state %d\n", *State));
226 return EFI_SUCCESS;
227 }
228
229 /**
230 Sets the USB host controller to a specific state.
231
232 @param This This EFI_USB2_HC_PROTOCOL instance.
233 @param State The state of the host controller that will be set.
234
235 @retval EFI_SUCCESS The USB host controller was successfully placed
236 in the state specified by State.
237 @retval EFI_INVALID_PARAMETER State is invalid.
238 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
239
240 **/
241 EFI_STATUS
242 EFIAPI
243 EhcSetState (
244 IN EFI_USB2_HC_PROTOCOL *This,
245 IN EFI_USB_HC_STATE State
246 )
247 {
248 USB2_HC_DEV *Ehc;
249 EFI_TPL OldTpl;
250 EFI_STATUS Status;
251 EFI_USB_HC_STATE CurState;
252
253 Status = EhcGetState (This, &CurState);
254
255 if (EFI_ERROR (Status)) {
256 return EFI_DEVICE_ERROR;
257 }
258
259 if (CurState == State) {
260 return EFI_SUCCESS;
261 }
262
263 OldTpl = gBS->RaiseTPL (EHC_TPL);
264 Ehc = EHC_FROM_THIS (This);
265
266 switch (State) {
267 case EfiUsbHcStateHalt:
268 Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
269 break;
270
271 case EfiUsbHcStateOperational:
272 if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {
273 Status = EFI_DEVICE_ERROR;
274 break;
275 }
276
277 //
278 // Software must not write a one to this field unless the host controller
279 // is in the Halted state. Doing so will yield undefined results.
280 // refers to Spec[EHCI1.0-2.3.1]
281 //
282 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
283 Status = EFI_DEVICE_ERROR;
284 break;
285 }
286
287 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
288 break;
289
290 case EfiUsbHcStateSuspend:
291 Status = EFI_UNSUPPORTED;
292 break;
293
294 default:
295 Status = EFI_INVALID_PARAMETER;
296 }
297
298 DEBUG ((DEBUG_INFO, "EhcSetState: exit status %r\n", Status));
299 gBS->RestoreTPL (OldTpl);
300 return Status;
301 }
302
303 /**
304 Retrieves the current status of a USB root hub port.
305
306 @param This This EFI_USB2_HC_PROTOCOL instance.
307 @param PortNumber The root hub port to retrieve the state from.
308 This value is zero-based.
309 @param PortStatus Variable to receive the port state.
310
311 @retval EFI_SUCCESS The status of the USB root hub port specified.
312 by PortNumber was returned in PortStatus.
313 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
314 @retval EFI_DEVICE_ERROR Can't read register.
315
316 **/
317 EFI_STATUS
318 EFIAPI
319 EhcGetRootHubPortStatus (
320 IN EFI_USB2_HC_PROTOCOL *This,
321 IN UINT8 PortNumber,
322 OUT EFI_USB_PORT_STATUS *PortStatus
323 )
324 {
325 USB2_HC_DEV *Ehc;
326 EFI_TPL OldTpl;
327 UINT32 Offset;
328 UINT32 State;
329 UINT32 TotalPort;
330 UINTN Index;
331 UINTN MapSize;
332 EFI_STATUS Status;
333
334 if (PortStatus == NULL) {
335 return EFI_INVALID_PARAMETER;
336 }
337
338 OldTpl = gBS->RaiseTPL (EHC_TPL);
339
340 Ehc = EHC_FROM_THIS (This);
341 Status = EFI_SUCCESS;
342
343 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
344
345 if (PortNumber >= TotalPort) {
346 Status = EFI_INVALID_PARAMETER;
347 goto ON_EXIT;
348 }
349
350 Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber));
351 PortStatus->PortStatus = 0;
352 PortStatus->PortChangeStatus = 0;
353
354 if (EhcIsDebugPortInUse (Ehc, &PortNumber)) {
355 goto ON_EXIT;
356 }
357
358 State = EhcReadOpReg (Ehc, Offset);
359
360 //
361 // Identify device speed. If in K state, it is low speed.
362 // If the port is enabled after reset, the device is of
363 // high speed. The USB bus driver should retrieve the actual
364 // port speed after reset.
365 //
366 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
367 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
368 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
369 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
370 }
371
372 //
373 // Convert the EHCI port/port change state to UEFI status
374 //
375 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
376
377 for (Index = 0; Index < MapSize; Index++) {
378 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
379 PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
380 }
381 }
382
383 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
384
385 for (Index = 0; Index < MapSize; Index++) {
386 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
387 PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
388 }
389 }
390
391 ON_EXIT:
392 gBS->RestoreTPL (OldTpl);
393 return Status;
394 }
395
396 /**
397 Sets a feature for the specified root hub port.
398
399 @param This This EFI_USB2_HC_PROTOCOL instance.
400 @param PortNumber Root hub port to set.
401 @param PortFeature Feature to set.
402
403 @retval EFI_SUCCESS The feature specified by PortFeature was set.
404 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
405 @retval EFI_DEVICE_ERROR Can't read register.
406
407 **/
408 EFI_STATUS
409 EFIAPI
410 EhcSetRootHubPortFeature (
411 IN EFI_USB2_HC_PROTOCOL *This,
412 IN UINT8 PortNumber,
413 IN EFI_USB_PORT_FEATURE PortFeature
414 )
415 {
416 USB2_HC_DEV *Ehc;
417 EFI_TPL OldTpl;
418 UINT32 Offset;
419 UINT32 State;
420 UINT32 TotalPort;
421 EFI_STATUS Status;
422
423 OldTpl = gBS->RaiseTPL (EHC_TPL);
424 Ehc = EHC_FROM_THIS (This);
425 Status = EFI_SUCCESS;
426
427 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
428
429 if (PortNumber >= TotalPort) {
430 Status = EFI_INVALID_PARAMETER;
431 goto ON_EXIT;
432 }
433
434 Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber));
435 State = EhcReadOpReg (Ehc, Offset);
436
437 //
438 // Mask off the port status change bits, these bits are
439 // write clean bit
440 //
441 State &= ~PORTSC_CHANGE_MASK;
442
443 switch (PortFeature) {
444 case EfiUsbPortEnable:
445 //
446 // Sofeware can't set this bit, Port can only be enable by
447 // EHCI as a part of the reset and enable
448 //
449 State |= PORTSC_ENABLED;
450 EhcWriteOpReg (Ehc, Offset, State);
451 break;
452
453 case EfiUsbPortSuspend:
454 State |= PORTSC_SUSPEND;
455 EhcWriteOpReg (Ehc, Offset, State);
456 break;
457
458 case EfiUsbPortReset:
459 //
460 // Make sure Host Controller not halt before reset it
461 //
462 if (EhcIsHalt (Ehc)) {
463 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
464
465 if (EFI_ERROR (Status)) {
466 DEBUG ((DEBUG_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
467 break;
468 }
469 }
470
471 //
472 // Set one to PortReset bit must also set zero to PortEnable bit
473 //
474 State |= PORTSC_RESET;
475 State &= ~PORTSC_ENABLED;
476 EhcWriteOpReg (Ehc, Offset, State);
477 break;
478
479 case EfiUsbPortPower:
480 //
481 // Set port power bit when PPC is 1
482 //
483 if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {
484 State |= PORTSC_POWER;
485 EhcWriteOpReg (Ehc, Offset, State);
486 }
487
488 break;
489
490 case EfiUsbPortOwner:
491 State |= PORTSC_OWNER;
492 EhcWriteOpReg (Ehc, Offset, State);
493 break;
494
495 default:
496 Status = EFI_INVALID_PARAMETER;
497 }
498
499 ON_EXIT:
500 DEBUG ((DEBUG_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));
501
502 gBS->RestoreTPL (OldTpl);
503 return Status;
504 }
505
506 /**
507 Clears a feature for the specified root hub port.
508
509 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
510 @param PortNumber Specifies the root hub port whose feature is
511 requested to be cleared.
512 @param PortFeature Indicates the feature selector associated with the
513 feature clear request.
514
515 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
516 for the USB root hub port specified by PortNumber.
517 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
518 @retval EFI_DEVICE_ERROR Can't read register.
519
520 **/
521 EFI_STATUS
522 EFIAPI
523 EhcClearRootHubPortFeature (
524 IN EFI_USB2_HC_PROTOCOL *This,
525 IN UINT8 PortNumber,
526 IN EFI_USB_PORT_FEATURE PortFeature
527 )
528 {
529 USB2_HC_DEV *Ehc;
530 EFI_TPL OldTpl;
531 UINT32 Offset;
532 UINT32 State;
533 UINT32 TotalPort;
534 EFI_STATUS Status;
535
536 OldTpl = gBS->RaiseTPL (EHC_TPL);
537 Ehc = EHC_FROM_THIS (This);
538 Status = EFI_SUCCESS;
539
540 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
541
542 if (PortNumber >= TotalPort) {
543 Status = EFI_INVALID_PARAMETER;
544 goto ON_EXIT;
545 }
546
547 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
548 State = EhcReadOpReg (Ehc, Offset);
549 State &= ~PORTSC_CHANGE_MASK;
550
551 switch (PortFeature) {
552 case EfiUsbPortEnable:
553 //
554 // Clear PORT_ENABLE feature means disable port.
555 //
556 State &= ~PORTSC_ENABLED;
557 EhcWriteOpReg (Ehc, Offset, State);
558 break;
559
560 case EfiUsbPortSuspend:
561 //
562 // A write of zero to this bit is ignored by the host
563 // controller. The host controller will unconditionally
564 // set this bit to a zero when:
565 // 1. software sets the Forct Port Resume bit to a zero from a one.
566 // 2. software sets the Port Reset bit to a one frome a zero.
567 //
568 State &= ~PORSTSC_RESUME;
569 EhcWriteOpReg (Ehc, Offset, State);
570 break;
571
572 case EfiUsbPortReset:
573 //
574 // Clear PORT_RESET means clear the reset signal.
575 //
576 State &= ~PORTSC_RESET;
577 EhcWriteOpReg (Ehc, Offset, State);
578 break;
579
580 case EfiUsbPortOwner:
581 //
582 // Clear port owner means this port owned by EHC
583 //
584 State &= ~PORTSC_OWNER;
585 EhcWriteOpReg (Ehc, Offset, State);
586 break;
587
588 case EfiUsbPortConnectChange:
589 //
590 // Clear connect status change
591 //
592 State |= PORTSC_CONN_CHANGE;
593 EhcWriteOpReg (Ehc, Offset, State);
594 break;
595
596 case EfiUsbPortEnableChange:
597 //
598 // Clear enable status change
599 //
600 State |= PORTSC_ENABLE_CHANGE;
601 EhcWriteOpReg (Ehc, Offset, State);
602 break;
603
604 case EfiUsbPortOverCurrentChange:
605 //
606 // Clear PortOverCurrent change
607 //
608 State |= PORTSC_OVERCUR_CHANGE;
609 EhcWriteOpReg (Ehc, Offset, State);
610 break;
611
612 case EfiUsbPortPower:
613 //
614 // Clear port power bit when PPC is 1
615 //
616 if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {
617 State &= ~PORTSC_POWER;
618 EhcWriteOpReg (Ehc, Offset, State);
619 }
620
621 break;
622 case EfiUsbPortSuspendChange:
623 case EfiUsbPortResetChange:
624 //
625 // Not supported or not related operation
626 //
627 break;
628
629 default:
630 Status = EFI_INVALID_PARAMETER;
631 break;
632 }
633
634 ON_EXIT:
635 DEBUG ((DEBUG_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));
636 gBS->RestoreTPL (OldTpl);
637 return Status;
638 }
639
640 /**
641 Submits control transfer to a target USB device.
642
643 @param This This EFI_USB2_HC_PROTOCOL instance.
644 @param DeviceAddress The target device address.
645 @param DeviceSpeed Target device speed.
646 @param MaximumPacketLength Maximum packet size the default control transfer
647 endpoint is capable of sending or receiving.
648 @param Request USB device request to send.
649 @param TransferDirection Specifies the data direction for the data stage
650 @param Data Data buffer to be transmitted or received from USB
651 device.
652 @param DataLength The size (in bytes) of the data buffer.
653 @param TimeOut Indicates the maximum timeout, in millisecond.
654 @param Translator Transaction translator to be used by this device.
655 @param TransferResult Return the result of this control transfer.
656
657 @retval EFI_SUCCESS Transfer was completed successfully.
658 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
659 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
660 @retval EFI_TIMEOUT Transfer failed due to timeout.
661 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
662
663 **/
664 EFI_STATUS
665 EFIAPI
666 EhcControlTransfer (
667 IN EFI_USB2_HC_PROTOCOL *This,
668 IN UINT8 DeviceAddress,
669 IN UINT8 DeviceSpeed,
670 IN UINTN MaximumPacketLength,
671 IN EFI_USB_DEVICE_REQUEST *Request,
672 IN EFI_USB_DATA_DIRECTION TransferDirection,
673 IN OUT VOID *Data,
674 IN OUT UINTN *DataLength,
675 IN UINTN TimeOut,
676 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
677 OUT UINT32 *TransferResult
678 )
679 {
680 USB2_HC_DEV *Ehc;
681 URB *Urb;
682 EFI_TPL OldTpl;
683 UINT8 Endpoint;
684 EFI_STATUS Status;
685
686 //
687 // Validate parameters
688 //
689 if ((Request == NULL) || (TransferResult == NULL)) {
690 return EFI_INVALID_PARAMETER;
691 }
692
693 if ((TransferDirection != EfiUsbDataIn) &&
694 (TransferDirection != EfiUsbDataOut) &&
695 (TransferDirection != EfiUsbNoData))
696 {
697 return EFI_INVALID_PARAMETER;
698 }
699
700 if ((TransferDirection == EfiUsbNoData) &&
701 ((Data != NULL) || (*DataLength != 0)))
702 {
703 return EFI_INVALID_PARAMETER;
704 }
705
706 if ((TransferDirection != EfiUsbNoData) &&
707 ((Data == NULL) || (*DataLength == 0)))
708 {
709 return EFI_INVALID_PARAMETER;
710 }
711
712 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
713 (MaximumPacketLength != 32) && (MaximumPacketLength != 64))
714 {
715 return EFI_INVALID_PARAMETER;
716 }
717
718 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
719 return EFI_INVALID_PARAMETER;
720 }
721
722 OldTpl = gBS->RaiseTPL (EHC_TPL);
723 Ehc = EHC_FROM_THIS (This);
724
725 Status = EFI_DEVICE_ERROR;
726 *TransferResult = EFI_USB_ERR_SYSTEM;
727
728 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
729 DEBUG ((DEBUG_ERROR, "EhcControlTransfer: HC halted at entrance\n"));
730
731 EhcAckAllInterrupt (Ehc);
732 goto ON_EXIT;
733 }
734
735 EhcAckAllInterrupt (Ehc);
736
737 //
738 // Create a new URB, insert it into the asynchronous
739 // schedule list, then poll the execution status.
740 //
741 //
742 // Encode the direction in address, although default control
743 // endpoint is bidirectional. EhcCreateUrb expects this
744 // combination of Ep addr and its direction.
745 //
746 Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
747 Urb = EhcCreateUrb (
748 Ehc,
749 DeviceAddress,
750 Endpoint,
751 DeviceSpeed,
752 0,
753 MaximumPacketLength,
754 Translator,
755 EHC_CTRL_TRANSFER,
756 Request,
757 Data,
758 *DataLength,
759 NULL,
760 NULL,
761 1
762 );
763
764 if (Urb == NULL) {
765 DEBUG ((DEBUG_ERROR, "EhcControlTransfer: failed to create URB"));
766
767 Status = EFI_OUT_OF_RESOURCES;
768 goto ON_EXIT;
769 }
770
771 EhcLinkQhToAsync (Ehc, Urb->Qh);
772 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
773 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
774
775 //
776 // Get the status from URB. The result is updated in EhcCheckUrbResult
777 // which is called by EhcExecTransfer
778 //
779 *TransferResult = Urb->Result;
780 *DataLength = Urb->Completed;
781
782 if (*TransferResult == EFI_USB_NOERROR) {
783 Status = EFI_SUCCESS;
784 }
785
786 EhcAckAllInterrupt (Ehc);
787 EhcFreeUrb (Ehc, Urb);
788
789 ON_EXIT:
790 Ehc->PciIo->Flush (Ehc->PciIo);
791 gBS->RestoreTPL (OldTpl);
792
793 if (EFI_ERROR (Status)) {
794 DEBUG ((DEBUG_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
795 }
796
797 return Status;
798 }
799
800 /**
801 Submits bulk transfer to a bulk endpoint of a USB device.
802
803 @param This This EFI_USB2_HC_PROTOCOL instance.
804 @param DeviceAddress Target device address.
805 @param EndPointAddress Endpoint number and its direction in bit 7.
806 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
807 transfer.
808 @param MaximumPacketLength Maximum packet size the endpoint is capable of
809 sending or receiving.
810 @param DataBuffersNumber Number of data buffers prepared for the transfer.
811 @param Data Array of pointers to the buffers of data to transmit
812 from or receive into.
813 @param DataLength The lenght of the data buffer.
814 @param DataToggle On input, the initial data toggle for the transfer;
815 On output, it is updated to to next data toggle to
816 use of the subsequent bulk transfer.
817 @param TimeOut Indicates the maximum time, in millisecond, which
818 the transfer is allowed to complete.
819 @param Translator A pointr to the transaction translator data.
820 @param TransferResult A pointer to the detailed result information of the
821 bulk transfer.
822
823 @retval EFI_SUCCESS The transfer was completed successfully.
824 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
825 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
826 @retval EFI_TIMEOUT The transfer failed due to timeout.
827 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
828
829 **/
830 EFI_STATUS
831 EFIAPI
832 EhcBulkTransfer (
833 IN EFI_USB2_HC_PROTOCOL *This,
834 IN UINT8 DeviceAddress,
835 IN UINT8 EndPointAddress,
836 IN UINT8 DeviceSpeed,
837 IN UINTN MaximumPacketLength,
838 IN UINT8 DataBuffersNumber,
839 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
840 IN OUT UINTN *DataLength,
841 IN OUT UINT8 *DataToggle,
842 IN UINTN TimeOut,
843 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
844 OUT UINT32 *TransferResult
845 )
846 {
847 USB2_HC_DEV *Ehc;
848 URB *Urb;
849 EFI_TPL OldTpl;
850 EFI_STATUS Status;
851 UINTN DebugErrorLevel;
852
853 //
854 // Validate the parameters
855 //
856 if ((DataLength == NULL) || (*DataLength == 0) ||
857 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))
858 {
859 return EFI_INVALID_PARAMETER;
860 }
861
862 if ((*DataToggle != 0) && (*DataToggle != 1)) {
863 return EFI_INVALID_PARAMETER;
864 }
865
866 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
867 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
868 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)))
869 {
870 return EFI_INVALID_PARAMETER;
871 }
872
873 OldTpl = gBS->RaiseTPL (EHC_TPL);
874 Ehc = EHC_FROM_THIS (This);
875
876 *TransferResult = EFI_USB_ERR_SYSTEM;
877 Status = EFI_DEVICE_ERROR;
878
879 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
880 DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: HC is halted\n"));
881
882 EhcAckAllInterrupt (Ehc);
883 goto ON_EXIT;
884 }
885
886 EhcAckAllInterrupt (Ehc);
887
888 //
889 // Create a new URB, insert it into the asynchronous
890 // schedule list, then poll the execution status.
891 //
892 Urb = EhcCreateUrb (
893 Ehc,
894 DeviceAddress,
895 EndPointAddress,
896 DeviceSpeed,
897 *DataToggle,
898 MaximumPacketLength,
899 Translator,
900 EHC_BULK_TRANSFER,
901 NULL,
902 Data[0],
903 *DataLength,
904 NULL,
905 NULL,
906 1
907 );
908
909 if (Urb == NULL) {
910 DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: failed to create URB\n"));
911
912 Status = EFI_OUT_OF_RESOURCES;
913 goto ON_EXIT;
914 }
915
916 EhcLinkQhToAsync (Ehc, Urb->Qh);
917 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
918 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
919
920 *TransferResult = Urb->Result;
921 *DataLength = Urb->Completed;
922 *DataToggle = Urb->DataToggle;
923
924 if (*TransferResult == EFI_USB_NOERROR) {
925 Status = EFI_SUCCESS;
926 }
927
928 EhcAckAllInterrupt (Ehc);
929 EhcFreeUrb (Ehc, Urb);
930
931 ON_EXIT:
932 Ehc->PciIo->Flush (Ehc->PciIo);
933 gBS->RestoreTPL (OldTpl);
934
935 if (EFI_ERROR (Status)) {
936 if (Status == EFI_TIMEOUT) {
937 DebugErrorLevel = DEBUG_VERBOSE;
938 } else {
939 DebugErrorLevel = DEBUG_ERROR;
940 }
941
942 DEBUG ((DebugErrorLevel, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
943 }
944
945 return Status;
946 }
947
948 /**
949 Submits an asynchronous interrupt transfer to an
950 interrupt endpoint of a USB device.
951
952 @param This This EFI_USB2_HC_PROTOCOL instance.
953 @param DeviceAddress Target device address.
954 @param EndPointAddress Endpoint number and its direction encoded in bit 7
955 @param DeviceSpeed Indicates device speed.
956 @param MaximumPacketLength Maximum packet size the target endpoint is capable
957 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
958 transfer If FALSE, to remove the specified
959 asynchronous interrupt.
960 @param DataToggle On input, the initial data toggle to use; on output,
961 it is updated to indicate the next data toggle.
962 @param PollingInterval The he interval, in milliseconds, that the transfer
963 is polled.
964 @param DataLength The length of data to receive at the rate specified
965 by PollingInterval.
966 @param Translator Transaction translator to use.
967 @param CallBackFunction Function to call at the rate specified by
968 PollingInterval.
969 @param Context Context to CallBackFunction.
970
971 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
972 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
973 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
974 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
975
976 **/
977 EFI_STATUS
978 EFIAPI
979 EhcAsyncInterruptTransfer (
980 IN EFI_USB2_HC_PROTOCOL *This,
981 IN UINT8 DeviceAddress,
982 IN UINT8 EndPointAddress,
983 IN UINT8 DeviceSpeed,
984 IN UINTN MaximumPacketLength,
985 IN BOOLEAN IsNewTransfer,
986 IN OUT UINT8 *DataToggle,
987 IN UINTN PollingInterval,
988 IN UINTN DataLength,
989 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
990 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
991 IN VOID *Context OPTIONAL
992 )
993 {
994 USB2_HC_DEV *Ehc;
995 URB *Urb;
996 EFI_TPL OldTpl;
997 EFI_STATUS Status;
998
999 //
1000 // Validate parameters
1001 //
1002 if (!EHCI_IS_DATAIN (EndPointAddress)) {
1003 return EFI_INVALID_PARAMETER;
1004 }
1005
1006 if (IsNewTransfer) {
1007 if (DataLength == 0) {
1008 return EFI_INVALID_PARAMETER;
1009 }
1010
1011 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1012 return EFI_INVALID_PARAMETER;
1013 }
1014
1015 if ((PollingInterval > 255) || (PollingInterval < 1)) {
1016 return EFI_INVALID_PARAMETER;
1017 }
1018 }
1019
1020 OldTpl = gBS->RaiseTPL (EHC_TPL);
1021 Ehc = EHC_FROM_THIS (This);
1022
1023 //
1024 // Delete Async interrupt transfer request. DataToggle will return
1025 // the next data toggle to use.
1026 //
1027 if (!IsNewTransfer) {
1028 Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);
1029
1030 DEBUG ((DEBUG_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));
1031 goto ON_EXIT;
1032 }
1033
1034 Status = EFI_SUCCESS;
1035
1036 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1037 DEBUG ((DEBUG_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));
1038 EhcAckAllInterrupt (Ehc);
1039
1040 Status = EFI_DEVICE_ERROR;
1041 goto ON_EXIT;
1042 }
1043
1044 EhcAckAllInterrupt (Ehc);
1045
1046 Urb = EhciInsertAsyncIntTransfer (
1047 Ehc,
1048 DeviceAddress,
1049 EndPointAddress,
1050 DeviceSpeed,
1051 *DataToggle,
1052 MaximumPacketLength,
1053 Translator,
1054 DataLength,
1055 CallBackFunction,
1056 Context,
1057 PollingInterval
1058 );
1059
1060 if (Urb == NULL) {
1061 Status = EFI_OUT_OF_RESOURCES;
1062 goto ON_EXIT;
1063 }
1064
1065 ON_EXIT:
1066 Ehc->PciIo->Flush (Ehc->PciIo);
1067 gBS->RestoreTPL (OldTpl);
1068
1069 return Status;
1070 }
1071
1072 /**
1073 Submits synchronous interrupt transfer to an interrupt endpoint
1074 of a USB device.
1075
1076 @param This This EFI_USB2_HC_PROTOCOL instance.
1077 @param DeviceAddress Target device address.
1078 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1079 @param DeviceSpeed Indicates device speed.
1080 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1081 of sending or receiving.
1082 @param Data Buffer of data that will be transmitted to USB
1083 device or received from USB device.
1084 @param DataLength On input, the size, in bytes, of the data buffer; On
1085 output, the number of bytes transferred.
1086 @param DataToggle On input, the initial data toggle to use; on output,
1087 it is updated to indicate the next data toggle.
1088 @param TimeOut Maximum time, in second, to complete.
1089 @param Translator Transaction translator to use.
1090 @param TransferResult Variable to receive the transfer result.
1091
1092 @return EFI_SUCCESS The transfer was completed successfully.
1093 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1094 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1095 @return EFI_TIMEOUT The transfer failed due to timeout.
1096 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1097
1098 **/
1099 EFI_STATUS
1100 EFIAPI
1101 EhcSyncInterruptTransfer (
1102 IN EFI_USB2_HC_PROTOCOL *This,
1103 IN UINT8 DeviceAddress,
1104 IN UINT8 EndPointAddress,
1105 IN UINT8 DeviceSpeed,
1106 IN UINTN MaximumPacketLength,
1107 IN OUT VOID *Data,
1108 IN OUT UINTN *DataLength,
1109 IN OUT UINT8 *DataToggle,
1110 IN UINTN TimeOut,
1111 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1112 OUT UINT32 *TransferResult
1113 )
1114 {
1115 USB2_HC_DEV *Ehc;
1116 EFI_TPL OldTpl;
1117 URB *Urb;
1118 EFI_STATUS Status;
1119
1120 //
1121 // Validates parameters
1122 //
1123 if ((DataLength == NULL) || (*DataLength == 0) ||
1124 (Data == NULL) || (TransferResult == NULL))
1125 {
1126 return EFI_INVALID_PARAMETER;
1127 }
1128
1129 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1130 return EFI_INVALID_PARAMETER;
1131 }
1132
1133 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
1134 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1135 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))
1136 {
1137 return EFI_INVALID_PARAMETER;
1138 }
1139
1140 OldTpl = gBS->RaiseTPL (EHC_TPL);
1141 Ehc = EHC_FROM_THIS (This);
1142
1143 *TransferResult = EFI_USB_ERR_SYSTEM;
1144 Status = EFI_DEVICE_ERROR;
1145
1146 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1147 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1148
1149 EhcAckAllInterrupt (Ehc);
1150 goto ON_EXIT;
1151 }
1152
1153 EhcAckAllInterrupt (Ehc);
1154
1155 Urb = EhcCreateUrb (
1156 Ehc,
1157 DeviceAddress,
1158 EndPointAddress,
1159 DeviceSpeed,
1160 *DataToggle,
1161 MaximumPacketLength,
1162 Translator,
1163 EHC_INT_TRANSFER_SYNC,
1164 NULL,
1165 Data,
1166 *DataLength,
1167 NULL,
1168 NULL,
1169 1
1170 );
1171
1172 if (Urb == NULL) {
1173 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));
1174
1175 Status = EFI_OUT_OF_RESOURCES;
1176 goto ON_EXIT;
1177 }
1178
1179 EhcLinkQhToPeriod (Ehc, Urb->Qh);
1180 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1181 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
1182
1183 *TransferResult = Urb->Result;
1184 *DataLength = Urb->Completed;
1185 *DataToggle = Urb->DataToggle;
1186
1187 if (*TransferResult == EFI_USB_NOERROR) {
1188 Status = EFI_SUCCESS;
1189 }
1190
1191 EhcFreeUrb (Ehc, Urb);
1192 ON_EXIT:
1193 Ehc->PciIo->Flush (Ehc->PciIo);
1194 gBS->RestoreTPL (OldTpl);
1195
1196 if (EFI_ERROR (Status)) {
1197 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1198 }
1199
1200 return Status;
1201 }
1202
1203 /**
1204 Submits isochronous transfer to a target USB device.
1205
1206 @param This This EFI_USB2_HC_PROTOCOL instance.
1207 @param DeviceAddress Target device address.
1208 @param EndPointAddress End point address with its direction.
1209 @param DeviceSpeed Device speed, Low speed device doesn't support this
1210 type.
1211 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1212 sending or receiving.
1213 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1214 @param Data Array of pointers to the buffers of data that will
1215 be transmitted to USB device or received from USB
1216 device.
1217 @param DataLength The size, in bytes, of the data buffer.
1218 @param Translator Transaction translator to use.
1219 @param TransferResult Variable to receive the transfer result.
1220
1221 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1222
1223 **/
1224 EFI_STATUS
1225 EFIAPI
1226 EhcIsochronousTransfer (
1227 IN EFI_USB2_HC_PROTOCOL *This,
1228 IN UINT8 DeviceAddress,
1229 IN UINT8 EndPointAddress,
1230 IN UINT8 DeviceSpeed,
1231 IN UINTN MaximumPacketLength,
1232 IN UINT8 DataBuffersNumber,
1233 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1234 IN UINTN DataLength,
1235 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1236 OUT UINT32 *TransferResult
1237 )
1238 {
1239 return EFI_UNSUPPORTED;
1240 }
1241
1242 /**
1243 Submits Async isochronous transfer to a target USB device.
1244
1245 @param This This EFI_USB2_HC_PROTOCOL instance.
1246 @param DeviceAddress Target device address.
1247 @param EndPointAddress End point address with its direction.
1248 @param DeviceSpeed Device speed, Low speed device doesn't support this
1249 type.
1250 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1251 sending or receiving.
1252 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1253 @param Data Array of pointers to the buffers of data that will
1254 be transmitted to USB device or received from USB
1255 device.
1256 @param DataLength The size, in bytes, of the data buffer.
1257 @param Translator Transaction translator to use.
1258 @param IsochronousCallBack Function to be called when the transfer complete.
1259 @param Context Context passed to the call back function as
1260 parameter.
1261
1262 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1263
1264 **/
1265 EFI_STATUS
1266 EFIAPI
1267 EhcAsyncIsochronousTransfer (
1268 IN EFI_USB2_HC_PROTOCOL *This,
1269 IN UINT8 DeviceAddress,
1270 IN UINT8 EndPointAddress,
1271 IN UINT8 DeviceSpeed,
1272 IN UINTN MaximumPacketLength,
1273 IN UINT8 DataBuffersNumber,
1274 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1275 IN UINTN DataLength,
1276 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1277 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1278 IN VOID *Context
1279 )
1280 {
1281 return EFI_UNSUPPORTED;
1282 }
1283
1284 /**
1285 Entry point for EFI drivers.
1286
1287 @param ImageHandle EFI_HANDLE.
1288 @param SystemTable EFI_SYSTEM_TABLE.
1289
1290 @return EFI_SUCCESS Success.
1291 EFI_DEVICE_ERROR Fail.
1292
1293 **/
1294 EFI_STATUS
1295 EFIAPI
1296 EhcDriverEntryPoint (
1297 IN EFI_HANDLE ImageHandle,
1298 IN EFI_SYSTEM_TABLE *SystemTable
1299 )
1300 {
1301 return EfiLibInstallDriverBindingComponentName2 (
1302 ImageHandle,
1303 SystemTable,
1304 &gEhciDriverBinding,
1305 ImageHandle,
1306 &gEhciComponentName,
1307 &gEhciComponentName2
1308 );
1309 }
1310
1311 /**
1312 Test to see if this driver supports ControllerHandle. Any
1313 ControllerHandle that has Usb2HcProtocol installed will
1314 be supported.
1315
1316 @param This Protocol instance pointer.
1317 @param Controller Handle of device to test.
1318 @param RemainingDevicePath Not used.
1319
1320 @return EFI_SUCCESS This driver supports this device.
1321 @return EFI_UNSUPPORTED This driver does not support this device.
1322
1323 **/
1324 EFI_STATUS
1325 EFIAPI
1326 EhcDriverBindingSupported (
1327 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1328 IN EFI_HANDLE Controller,
1329 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1330 )
1331 {
1332 EFI_STATUS Status;
1333 EFI_PCI_IO_PROTOCOL *PciIo;
1334 USB_CLASSC UsbClassCReg;
1335
1336 //
1337 // Test whether there is PCI IO Protocol attached on the controller handle.
1338 //
1339 Status = gBS->OpenProtocol (
1340 Controller,
1341 &gEfiPciIoProtocolGuid,
1342 (VOID **)&PciIo,
1343 This->DriverBindingHandle,
1344 Controller,
1345 EFI_OPEN_PROTOCOL_BY_DRIVER
1346 );
1347
1348 if (EFI_ERROR (Status)) {
1349 return EFI_UNSUPPORTED;
1350 }
1351
1352 Status = PciIo->Pci.Read (
1353 PciIo,
1354 EfiPciIoWidthUint8,
1355 PCI_CLASSCODE_OFFSET,
1356 sizeof (USB_CLASSC) / sizeof (UINT8),
1357 &UsbClassCReg
1358 );
1359
1360 if (EFI_ERROR (Status)) {
1361 Status = EFI_UNSUPPORTED;
1362 goto ON_EXIT;
1363 }
1364
1365 //
1366 // Test whether the controller belongs to Ehci type
1367 //
1368 if ( (UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)
1369 || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface != PCI_IF_UHCI) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI)))
1370 {
1371 Status = EFI_UNSUPPORTED;
1372 }
1373
1374 ON_EXIT:
1375 gBS->CloseProtocol (
1376 Controller,
1377 &gEfiPciIoProtocolGuid,
1378 This->DriverBindingHandle,
1379 Controller
1380 );
1381
1382 return Status;
1383 }
1384
1385 /**
1386 Get the usb debug port related information.
1387
1388 @param Ehc The EHCI device.
1389
1390 @retval RETURN_SUCCESS Get debug port number, bar and offset successfully.
1391 @retval Others The usb host controller does not supported usb debug port capability.
1392
1393 **/
1394 EFI_STATUS
1395 EhcGetUsbDebugPortInfo (
1396 IN USB2_HC_DEV *Ehc
1397 )
1398 {
1399 EFI_PCI_IO_PROTOCOL *PciIo;
1400 UINT16 PciStatus;
1401 UINT8 CapabilityPtr;
1402 UINT8 CapabilityId;
1403 UINT16 DebugPort;
1404 EFI_STATUS Status;
1405
1406 ASSERT (Ehc->PciIo != NULL);
1407 PciIo = Ehc->PciIo;
1408
1409 //
1410 // Detect if the EHCI host controller support Capaility Pointer.
1411 //
1412 Status = PciIo->Pci.Read (
1413 PciIo,
1414 EfiPciIoWidthUint8,
1415 PCI_PRIMARY_STATUS_OFFSET,
1416 sizeof (UINT16),
1417 &PciStatus
1418 );
1419
1420 if (EFI_ERROR (Status)) {
1421 return Status;
1422 }
1423
1424 if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {
1425 //
1426 // The Pci Device Doesn't Support Capability Pointer.
1427 //
1428 return EFI_UNSUPPORTED;
1429 }
1430
1431 //
1432 // Get Pointer To Capability List
1433 //
1434 Status = PciIo->Pci.Read (
1435 PciIo,
1436 EfiPciIoWidthUint8,
1437 PCI_CAPBILITY_POINTER_OFFSET,
1438 1,
1439 &CapabilityPtr
1440 );
1441
1442 if (EFI_ERROR (Status)) {
1443 return Status;
1444 }
1445
1446 //
1447 // Find Capability ID 0xA, Which Is For Debug Port
1448 //
1449 while (CapabilityPtr != 0) {
1450 Status = PciIo->Pci.Read (
1451 PciIo,
1452 EfiPciIoWidthUint8,
1453 CapabilityPtr,
1454 1,
1455 &CapabilityId
1456 );
1457
1458 if (EFI_ERROR (Status)) {
1459 return Status;
1460 }
1461
1462 if (CapabilityId == EHC_DEBUG_PORT_CAP_ID) {
1463 break;
1464 }
1465
1466 Status = PciIo->Pci.Read (
1467 PciIo,
1468 EfiPciIoWidthUint8,
1469 CapabilityPtr + 1,
1470 1,
1471 &CapabilityPtr
1472 );
1473
1474 if (EFI_ERROR (Status)) {
1475 return Status;
1476 }
1477 }
1478
1479 //
1480 // No Debug Port Capability Found
1481 //
1482 if (CapabilityPtr == 0) {
1483 return EFI_UNSUPPORTED;
1484 }
1485
1486 //
1487 // Get The Base Address Of Debug Port Register In Debug Port Capability Register
1488 //
1489 Status = PciIo->Pci.Read (
1490 Ehc->PciIo,
1491 EfiPciIoWidthUint8,
1492 CapabilityPtr + 2,
1493 sizeof (UINT16),
1494 &DebugPort
1495 );
1496
1497 if (EFI_ERROR (Status)) {
1498 return Status;
1499 }
1500
1501 Ehc->DebugPortOffset = DebugPort & 0x1FFF;
1502 Ehc->DebugPortBarNum = (UINT8)((DebugPort >> 13) - 1);
1503 Ehc->DebugPortNum = (UINT8)((Ehc->HcStructParams & 0x00F00000) >> 20);
1504
1505 return EFI_SUCCESS;
1506 }
1507
1508 /**
1509 Create and initialize a USB2_HC_DEV.
1510
1511 @param PciIo The PciIo on this device.
1512 @param DevicePath The device path of host controller.
1513 @param OriginalPciAttributes Original PCI attributes.
1514
1515 @return The allocated and initialized USB2_HC_DEV structure if created,
1516 otherwise NULL.
1517
1518 **/
1519 USB2_HC_DEV *
1520 EhcCreateUsb2Hc (
1521 IN EFI_PCI_IO_PROTOCOL *PciIo,
1522 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1523 IN UINT64 OriginalPciAttributes
1524 )
1525 {
1526 USB2_HC_DEV *Ehc;
1527 EFI_STATUS Status;
1528
1529 Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));
1530
1531 if (Ehc == NULL) {
1532 return NULL;
1533 }
1534
1535 //
1536 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1537 //
1538 Ehc->Signature = USB2_HC_DEV_SIGNATURE;
1539
1540 Ehc->Usb2Hc.GetCapability = EhcGetCapability;
1541 Ehc->Usb2Hc.Reset = EhcReset;
1542 Ehc->Usb2Hc.GetState = EhcGetState;
1543 Ehc->Usb2Hc.SetState = EhcSetState;
1544 Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;
1545 Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;
1546 Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;
1547 Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;
1548 Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;
1549 Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;
1550 Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1551 Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1552 Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1553 Ehc->Usb2Hc.MajorRevision = 0x2;
1554 Ehc->Usb2Hc.MinorRevision = 0x0;
1555
1556 Ehc->PciIo = PciIo;
1557 Ehc->DevicePath = DevicePath;
1558 Ehc->OriginalPciAttributes = OriginalPciAttributes;
1559
1560 InitializeListHead (&Ehc->AsyncIntTransfers);
1561
1562 Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);
1563 Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);
1564 Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1565
1566 DEBUG ((DEBUG_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));
1567
1568 //
1569 // EHCI Controllers with a CapLen of 0 are ignored.
1570 //
1571 if (Ehc->CapLen == 0) {
1572 gBS->FreePool (Ehc);
1573 return NULL;
1574 }
1575
1576 EhcGetUsbDebugPortInfo (Ehc);
1577
1578 //
1579 // Create AsyncRequest Polling Timer
1580 //
1581 Status = gBS->CreateEvent (
1582 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1583 TPL_NOTIFY,
1584 EhcMonitorAsyncRequests,
1585 Ehc,
1586 &Ehc->PollTimer
1587 );
1588
1589 if (EFI_ERROR (Status)) {
1590 gBS->FreePool (Ehc);
1591 return NULL;
1592 }
1593
1594 return Ehc;
1595 }
1596
1597 /**
1598 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1599
1600 @param Event Pointer to this event
1601 @param Context Event handler private data
1602
1603 **/
1604 VOID
1605 EFIAPI
1606 EhcExitBootService (
1607 EFI_EVENT Event,
1608 VOID *Context
1609 )
1610
1611 {
1612 USB2_HC_DEV *Ehc;
1613
1614 Ehc = (USB2_HC_DEV *)Context;
1615
1616 //
1617 // Reset the Host Controller
1618 //
1619 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
1620 }
1621
1622 /**
1623 Starting the Usb EHCI Driver.
1624
1625 @param This Protocol instance pointer.
1626 @param Controller Handle of device to test.
1627 @param RemainingDevicePath Not used.
1628
1629 @return EFI_SUCCESS supports this device.
1630 @return EFI_UNSUPPORTED do not support this device.
1631 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1632 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1633
1634 **/
1635 EFI_STATUS
1636 EFIAPI
1637 EhcDriverBindingStart (
1638 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1639 IN EFI_HANDLE Controller,
1640 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1641 )
1642 {
1643 EFI_STATUS Status;
1644 USB2_HC_DEV *Ehc;
1645 EFI_PCI_IO_PROTOCOL *PciIo;
1646 EFI_PCI_IO_PROTOCOL *Instance;
1647 UINT64 Supports;
1648 UINT64 OriginalPciAttributes;
1649 BOOLEAN PciAttributesSaved;
1650 USB_CLASSC UsbClassCReg;
1651 EFI_HANDLE *HandleBuffer;
1652 UINTN NumberOfHandles;
1653 UINTN Index;
1654 UINTN CompanionSegmentNumber;
1655 UINTN CompanionBusNumber;
1656 UINTN CompanionDeviceNumber;
1657 UINTN CompanionFunctionNumber;
1658 UINTN EhciSegmentNumber;
1659 UINTN EhciBusNumber;
1660 UINTN EhciDeviceNumber;
1661 UINTN EhciFunctionNumber;
1662 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1663
1664 //
1665 // Open the PciIo Protocol, then enable the USB host controller
1666 //
1667 Status = gBS->OpenProtocol (
1668 Controller,
1669 &gEfiPciIoProtocolGuid,
1670 (VOID **)&PciIo,
1671 This->DriverBindingHandle,
1672 Controller,
1673 EFI_OPEN_PROTOCOL_BY_DRIVER
1674 );
1675
1676 if (EFI_ERROR (Status)) {
1677 return Status;
1678 }
1679
1680 //
1681 // Open Device Path Protocol for on USB host controller
1682 //
1683 HcDevicePath = NULL;
1684 Status = gBS->OpenProtocol (
1685 Controller,
1686 &gEfiDevicePathProtocolGuid,
1687 (VOID **)&HcDevicePath,
1688 This->DriverBindingHandle,
1689 Controller,
1690 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1691 );
1692
1693 PciAttributesSaved = FALSE;
1694 //
1695 // Save original PCI attributes
1696 //
1697 Status = PciIo->Attributes (
1698 PciIo,
1699 EfiPciIoAttributeOperationGet,
1700 0,
1701 &OriginalPciAttributes
1702 );
1703
1704 if (EFI_ERROR (Status)) {
1705 goto CLOSE_PCIIO;
1706 }
1707
1708 PciAttributesSaved = TRUE;
1709
1710 Status = PciIo->Attributes (
1711 PciIo,
1712 EfiPciIoAttributeOperationSupported,
1713 0,
1714 &Supports
1715 );
1716 if (!EFI_ERROR (Status)) {
1717 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1718 Status = PciIo->Attributes (
1719 PciIo,
1720 EfiPciIoAttributeOperationEnable,
1721 Supports,
1722 NULL
1723 );
1724 }
1725
1726 if (EFI_ERROR (Status)) {
1727 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));
1728 goto CLOSE_PCIIO;
1729 }
1730
1731 //
1732 // Get the Pci device class code.
1733 //
1734 Status = PciIo->Pci.Read (
1735 PciIo,
1736 EfiPciIoWidthUint8,
1737 PCI_CLASSCODE_OFFSET,
1738 sizeof (USB_CLASSC) / sizeof (UINT8),
1739 &UsbClassCReg
1740 );
1741
1742 if (EFI_ERROR (Status)) {
1743 Status = EFI_UNSUPPORTED;
1744 goto CLOSE_PCIIO;
1745 }
1746
1747 //
1748 // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the
1749 // companion usb ehci host controller and force EHCI driver get attached to it before
1750 // UHCI or OHCI driver attaches to UHCI or OHCI host controller.
1751 //
1752 if (((UsbClassCReg.ProgInterface == PCI_IF_UHCI) || (UsbClassCReg.ProgInterface == PCI_IF_OHCI)) &&
1753 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
1754 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB))
1755 {
1756 Status = PciIo->GetLocation (
1757 PciIo,
1758 &CompanionSegmentNumber,
1759 &CompanionBusNumber,
1760 &CompanionDeviceNumber,
1761 &CompanionFunctionNumber
1762 );
1763 if (EFI_ERROR (Status)) {
1764 goto CLOSE_PCIIO;
1765 }
1766
1767 Status = gBS->LocateHandleBuffer (
1768 ByProtocol,
1769 &gEfiPciIoProtocolGuid,
1770 NULL,
1771 &NumberOfHandles,
1772 &HandleBuffer
1773 );
1774 if (EFI_ERROR (Status)) {
1775 goto CLOSE_PCIIO;
1776 }
1777
1778 for (Index = 0; Index < NumberOfHandles; Index++) {
1779 //
1780 // Get the device path on this handle
1781 //
1782 Status = gBS->HandleProtocol (
1783 HandleBuffer[Index],
1784 &gEfiPciIoProtocolGuid,
1785 (VOID **)&Instance
1786 );
1787 ASSERT_EFI_ERROR (Status);
1788
1789 Status = Instance->Pci.Read (
1790 Instance,
1791 EfiPciIoWidthUint8,
1792 PCI_CLASSCODE_OFFSET,
1793 sizeof (USB_CLASSC) / sizeof (UINT8),
1794 &UsbClassCReg
1795 );
1796
1797 if (EFI_ERROR (Status)) {
1798 Status = EFI_UNSUPPORTED;
1799 goto CLOSE_PCIIO;
1800 }
1801
1802 if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) &&
1803 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
1804 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB))
1805 {
1806 Status = Instance->GetLocation (
1807 Instance,
1808 &EhciSegmentNumber,
1809 &EhciBusNumber,
1810 &EhciDeviceNumber,
1811 &EhciFunctionNumber
1812 );
1813 if (EFI_ERROR (Status)) {
1814 goto CLOSE_PCIIO;
1815 }
1816
1817 //
1818 // Currently, the judgment on the companion usb host controller is through the
1819 // same bus number, which may vary on different platform.
1820 //
1821 if (EhciBusNumber == CompanionBusNumber) {
1822 gBS->CloseProtocol (
1823 Controller,
1824 &gEfiPciIoProtocolGuid,
1825 This->DriverBindingHandle,
1826 Controller
1827 );
1828 EhcDriverBindingStart (This, HandleBuffer[Index], NULL);
1829 }
1830 }
1831 }
1832
1833 Status = EFI_NOT_FOUND;
1834 goto CLOSE_PCIIO;
1835 }
1836
1837 //
1838 // Create then install USB2_HC_PROTOCOL
1839 //
1840 Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes);
1841
1842 if (Ehc == NULL) {
1843 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1844
1845 Status = EFI_OUT_OF_RESOURCES;
1846 goto CLOSE_PCIIO;
1847 }
1848
1849 //
1850 // Enable 64-bit DMA support in the PCI layer if this controller
1851 // supports it.
1852 //
1853 if (EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT)) {
1854 Status = PciIo->Attributes (
1855 PciIo,
1856 EfiPciIoAttributeOperationEnable,
1857 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
1858 NULL
1859 );
1860 if (!EFI_ERROR (Status)) {
1861 Ehc->Support64BitDma = TRUE;
1862 } else {
1863 DEBUG ((
1864 DEBUG_WARN,
1865 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
1866 __FUNCTION__,
1867 Controller,
1868 Status
1869 ));
1870 }
1871 }
1872
1873 Status = gBS->InstallProtocolInterface (
1874 &Controller,
1875 &gEfiUsb2HcProtocolGuid,
1876 EFI_NATIVE_INTERFACE,
1877 &Ehc->Usb2Hc
1878 );
1879
1880 if (EFI_ERROR (Status)) {
1881 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1882 goto FREE_POOL;
1883 }
1884
1885 //
1886 // Robustnesss improvement such as for Duet platform
1887 // Default is not required.
1888 //
1889 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1890 EhcClearLegacySupport (Ehc);
1891 }
1892
1893 if (!EhcIsDebugPortInUse (Ehc, NULL)) {
1894 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
1895 }
1896
1897 Status = EhcInitHC (Ehc);
1898
1899 if (EFI_ERROR (Status)) {
1900 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));
1901 goto UNINSTALL_USBHC;
1902 }
1903
1904 //
1905 // Start the asynchronous interrupt monitor
1906 //
1907 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);
1908
1909 if (EFI_ERROR (Status)) {
1910 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1911
1912 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1913 goto UNINSTALL_USBHC;
1914 }
1915
1916 //
1917 // Create event to stop the HC when exit boot service.
1918 //
1919 Status = gBS->CreateEventEx (
1920 EVT_NOTIFY_SIGNAL,
1921 TPL_NOTIFY,
1922 EhcExitBootService,
1923 Ehc,
1924 &gEfiEventExitBootServicesGuid,
1925 &Ehc->ExitBootServiceEvent
1926 );
1927 if (EFI_ERROR (Status)) {
1928 goto UNINSTALL_USBHC;
1929 }
1930
1931 //
1932 // Install the component name protocol, don't fail the start
1933 // because of something for display.
1934 //
1935 AddUnicodeString2 (
1936 "eng",
1937 gEhciComponentName.SupportedLanguages,
1938 &Ehc->ControllerNameTable,
1939 L"Enhanced Host Controller (USB 2.0)",
1940 TRUE
1941 );
1942 AddUnicodeString2 (
1943 "en",
1944 gEhciComponentName2.SupportedLanguages,
1945 &Ehc->ControllerNameTable,
1946 L"Enhanced Host Controller (USB 2.0)",
1947 FALSE
1948 );
1949
1950 DEBUG ((DEBUG_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));
1951 return EFI_SUCCESS;
1952
1953 UNINSTALL_USBHC:
1954 gBS->UninstallProtocolInterface (
1955 Controller,
1956 &gEfiUsb2HcProtocolGuid,
1957 &Ehc->Usb2Hc
1958 );
1959
1960 FREE_POOL:
1961 EhcFreeSched (Ehc);
1962 gBS->CloseEvent (Ehc->PollTimer);
1963 gBS->FreePool (Ehc);
1964
1965 CLOSE_PCIIO:
1966 if (PciAttributesSaved) {
1967 //
1968 // Restore original PCI attributes
1969 //
1970 PciIo->Attributes (
1971 PciIo,
1972 EfiPciIoAttributeOperationSet,
1973 OriginalPciAttributes,
1974 NULL
1975 );
1976 }
1977
1978 gBS->CloseProtocol (
1979 Controller,
1980 &gEfiPciIoProtocolGuid,
1981 This->DriverBindingHandle,
1982 Controller
1983 );
1984
1985 return Status;
1986 }
1987
1988 /**
1989 Stop this driver on ControllerHandle. Support stopping any child handles
1990 created by this driver.
1991
1992 @param This Protocol instance pointer.
1993 @param Controller Handle of device to stop driver on.
1994 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1995 @param ChildHandleBuffer List of handles for the children we need to stop.
1996
1997 @return EFI_SUCCESS Success.
1998 @return EFI_DEVICE_ERROR Fail.
1999
2000 **/
2001 EFI_STATUS
2002 EFIAPI
2003 EhcDriverBindingStop (
2004 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2005 IN EFI_HANDLE Controller,
2006 IN UINTN NumberOfChildren,
2007 IN EFI_HANDLE *ChildHandleBuffer
2008 )
2009 {
2010 EFI_STATUS Status;
2011 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2012 EFI_PCI_IO_PROTOCOL *PciIo;
2013 USB2_HC_DEV *Ehc;
2014
2015 //
2016 // Test whether the Controller handler passed in is a valid
2017 // Usb controller handle that should be supported, if not,
2018 // return the error status directly
2019 //
2020 Status = gBS->OpenProtocol (
2021 Controller,
2022 &gEfiUsb2HcProtocolGuid,
2023 (VOID **)&Usb2Hc,
2024 This->DriverBindingHandle,
2025 Controller,
2026 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2027 );
2028
2029 if (EFI_ERROR (Status)) {
2030 return Status;
2031 }
2032
2033 Ehc = EHC_FROM_THIS (Usb2Hc);
2034 PciIo = Ehc->PciIo;
2035
2036 Status = gBS->UninstallProtocolInterface (
2037 Controller,
2038 &gEfiUsb2HcProtocolGuid,
2039 Usb2Hc
2040 );
2041
2042 if (EFI_ERROR (Status)) {
2043 return Status;
2044 }
2045
2046 //
2047 // Stop AsyncRequest Polling timer then stop the EHCI driver
2048 // and uninstall the EHCI protocl.
2049 //
2050 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);
2051 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
2052
2053 if (Ehc->PollTimer != NULL) {
2054 gBS->CloseEvent (Ehc->PollTimer);
2055 }
2056
2057 if (Ehc->ExitBootServiceEvent != NULL) {
2058 gBS->CloseEvent (Ehc->ExitBootServiceEvent);
2059 }
2060
2061 EhcFreeSched (Ehc);
2062
2063 if (Ehc->ControllerNameTable != NULL) {
2064 FreeUnicodeStringTable (Ehc->ControllerNameTable);
2065 }
2066
2067 //
2068 // Disable routing of all ports to EHCI controller, so all ports are
2069 // routed back to the UHCI or OHCI controller.
2070 //
2071 EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
2072
2073 //
2074 // Restore original PCI attributes
2075 //
2076 PciIo->Attributes (
2077 PciIo,
2078 EfiPciIoAttributeOperationSet,
2079 Ehc->OriginalPciAttributes,
2080 NULL
2081 );
2082
2083 gBS->CloseProtocol (
2084 Controller,
2085 &gEfiPciIoProtocolGuid,
2086 This->DriverBindingHandle,
2087 Controller
2088 );
2089
2090 FreePool (Ehc);
2091
2092 return EFI_SUCCESS;
2093 }