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