]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
MdeModulePkg: Apply uncrustify changes
[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
852 //
853 // Validate the parameters
854 //
855 if ((DataLength == NULL) || (*DataLength == 0) ||
856 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))
857 {
858 return EFI_INVALID_PARAMETER;
859 }
860
861 if ((*DataToggle != 0) && (*DataToggle != 1)) {
862 return EFI_INVALID_PARAMETER;
863 }
864
865 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
866 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
867 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)))
868 {
869 return EFI_INVALID_PARAMETER;
870 }
871
872 OldTpl = gBS->RaiseTPL (EHC_TPL);
873 Ehc = EHC_FROM_THIS (This);
874
875 *TransferResult = EFI_USB_ERR_SYSTEM;
876 Status = EFI_DEVICE_ERROR;
877
878 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
879 DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: HC is halted\n"));
880
881 EhcAckAllInterrupt (Ehc);
882 goto ON_EXIT;
883 }
884
885 EhcAckAllInterrupt (Ehc);
886
887 //
888 // Create a new URB, insert it into the asynchronous
889 // schedule list, then poll the execution status.
890 //
891 Urb = EhcCreateUrb (
892 Ehc,
893 DeviceAddress,
894 EndPointAddress,
895 DeviceSpeed,
896 *DataToggle,
897 MaximumPacketLength,
898 Translator,
899 EHC_BULK_TRANSFER,
900 NULL,
901 Data[0],
902 *DataLength,
903 NULL,
904 NULL,
905 1
906 );
907
908 if (Urb == NULL) {
909 DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: failed to create URB\n"));
910
911 Status = EFI_OUT_OF_RESOURCES;
912 goto ON_EXIT;
913 }
914
915 EhcLinkQhToAsync (Ehc, Urb->Qh);
916 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
917 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
918
919 *TransferResult = Urb->Result;
920 *DataLength = Urb->Completed;
921 *DataToggle = Urb->DataToggle;
922
923 if (*TransferResult == EFI_USB_NOERROR) {
924 Status = EFI_SUCCESS;
925 }
926
927 EhcAckAllInterrupt (Ehc);
928 EhcFreeUrb (Ehc, Urb);
929
930 ON_EXIT:
931 Ehc->PciIo->Flush (Ehc->PciIo);
932 gBS->RestoreTPL (OldTpl);
933
934 if (EFI_ERROR (Status)) {
935 DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
936 }
937
938 return Status;
939 }
940
941 /**
942 Submits an asynchronous interrupt transfer to an
943 interrupt endpoint of a USB device.
944
945 @param This This EFI_USB2_HC_PROTOCOL instance.
946 @param DeviceAddress Target device address.
947 @param EndPointAddress Endpoint number and its direction encoded in bit 7
948 @param DeviceSpeed Indicates device speed.
949 @param MaximumPacketLength Maximum packet size the target endpoint is capable
950 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
951 transfer If FALSE, to remove the specified
952 asynchronous interrupt.
953 @param DataToggle On input, the initial data toggle to use; on output,
954 it is updated to indicate the next data toggle.
955 @param PollingInterval The he interval, in milliseconds, that the transfer
956 is polled.
957 @param DataLength The length of data to receive at the rate specified
958 by PollingInterval.
959 @param Translator Transaction translator to use.
960 @param CallBackFunction Function to call at the rate specified by
961 PollingInterval.
962 @param Context Context to CallBackFunction.
963
964 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
965 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
966 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
967 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
968
969 **/
970 EFI_STATUS
971 EFIAPI
972 EhcAsyncInterruptTransfer (
973 IN EFI_USB2_HC_PROTOCOL *This,
974 IN UINT8 DeviceAddress,
975 IN UINT8 EndPointAddress,
976 IN UINT8 DeviceSpeed,
977 IN UINTN MaximumPacketLength,
978 IN BOOLEAN IsNewTransfer,
979 IN OUT UINT8 *DataToggle,
980 IN UINTN PollingInterval,
981 IN UINTN DataLength,
982 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
983 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
984 IN VOID *Context OPTIONAL
985 )
986 {
987 USB2_HC_DEV *Ehc;
988 URB *Urb;
989 EFI_TPL OldTpl;
990 EFI_STATUS Status;
991
992 //
993 // Validate parameters
994 //
995 if (!EHCI_IS_DATAIN (EndPointAddress)) {
996 return EFI_INVALID_PARAMETER;
997 }
998
999 if (IsNewTransfer) {
1000 if (DataLength == 0) {
1001 return EFI_INVALID_PARAMETER;
1002 }
1003
1004 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1005 return EFI_INVALID_PARAMETER;
1006 }
1007
1008 if ((PollingInterval > 255) || (PollingInterval < 1)) {
1009 return EFI_INVALID_PARAMETER;
1010 }
1011 }
1012
1013 OldTpl = gBS->RaiseTPL (EHC_TPL);
1014 Ehc = EHC_FROM_THIS (This);
1015
1016 //
1017 // Delete Async interrupt transfer request. DataToggle will return
1018 // the next data toggle to use.
1019 //
1020 if (!IsNewTransfer) {
1021 Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);
1022
1023 DEBUG ((DEBUG_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));
1024 goto ON_EXIT;
1025 }
1026
1027 Status = EFI_SUCCESS;
1028
1029 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1030 DEBUG ((DEBUG_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));
1031 EhcAckAllInterrupt (Ehc);
1032
1033 Status = EFI_DEVICE_ERROR;
1034 goto ON_EXIT;
1035 }
1036
1037 EhcAckAllInterrupt (Ehc);
1038
1039 Urb = EhciInsertAsyncIntTransfer (
1040 Ehc,
1041 DeviceAddress,
1042 EndPointAddress,
1043 DeviceSpeed,
1044 *DataToggle,
1045 MaximumPacketLength,
1046 Translator,
1047 DataLength,
1048 CallBackFunction,
1049 Context,
1050 PollingInterval
1051 );
1052
1053 if (Urb == NULL) {
1054 Status = EFI_OUT_OF_RESOURCES;
1055 goto ON_EXIT;
1056 }
1057
1058 ON_EXIT:
1059 Ehc->PciIo->Flush (Ehc->PciIo);
1060 gBS->RestoreTPL (OldTpl);
1061
1062 return Status;
1063 }
1064
1065 /**
1066 Submits synchronous interrupt transfer to an interrupt endpoint
1067 of a USB device.
1068
1069 @param This This EFI_USB2_HC_PROTOCOL instance.
1070 @param DeviceAddress Target device address.
1071 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1072 @param DeviceSpeed Indicates device speed.
1073 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1074 of sending or receiving.
1075 @param Data Buffer of data that will be transmitted to USB
1076 device or received from USB device.
1077 @param DataLength On input, the size, in bytes, of the data buffer; On
1078 output, the number of bytes transferred.
1079 @param DataToggle On input, the initial data toggle to use; on output,
1080 it is updated to indicate the next data toggle.
1081 @param TimeOut Maximum time, in second, to complete.
1082 @param Translator Transaction translator to use.
1083 @param TransferResult Variable to receive the transfer result.
1084
1085 @return EFI_SUCCESS The transfer was completed successfully.
1086 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1087 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1088 @return EFI_TIMEOUT The transfer failed due to timeout.
1089 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1090
1091 **/
1092 EFI_STATUS
1093 EFIAPI
1094 EhcSyncInterruptTransfer (
1095 IN EFI_USB2_HC_PROTOCOL *This,
1096 IN UINT8 DeviceAddress,
1097 IN UINT8 EndPointAddress,
1098 IN UINT8 DeviceSpeed,
1099 IN UINTN MaximumPacketLength,
1100 IN OUT VOID *Data,
1101 IN OUT UINTN *DataLength,
1102 IN OUT UINT8 *DataToggle,
1103 IN UINTN TimeOut,
1104 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1105 OUT UINT32 *TransferResult
1106 )
1107 {
1108 USB2_HC_DEV *Ehc;
1109 EFI_TPL OldTpl;
1110 URB *Urb;
1111 EFI_STATUS Status;
1112
1113 //
1114 // Validates parameters
1115 //
1116 if ((DataLength == NULL) || (*DataLength == 0) ||
1117 (Data == NULL) || (TransferResult == NULL))
1118 {
1119 return EFI_INVALID_PARAMETER;
1120 }
1121
1122 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1123 return EFI_INVALID_PARAMETER;
1124 }
1125
1126 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
1127 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1128 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))
1129 {
1130 return EFI_INVALID_PARAMETER;
1131 }
1132
1133 OldTpl = gBS->RaiseTPL (EHC_TPL);
1134 Ehc = EHC_FROM_THIS (This);
1135
1136 *TransferResult = EFI_USB_ERR_SYSTEM;
1137 Status = EFI_DEVICE_ERROR;
1138
1139 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1140 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1141
1142 EhcAckAllInterrupt (Ehc);
1143 goto ON_EXIT;
1144 }
1145
1146 EhcAckAllInterrupt (Ehc);
1147
1148 Urb = EhcCreateUrb (
1149 Ehc,
1150 DeviceAddress,
1151 EndPointAddress,
1152 DeviceSpeed,
1153 *DataToggle,
1154 MaximumPacketLength,
1155 Translator,
1156 EHC_INT_TRANSFER_SYNC,
1157 NULL,
1158 Data,
1159 *DataLength,
1160 NULL,
1161 NULL,
1162 1
1163 );
1164
1165 if (Urb == NULL) {
1166 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));
1167
1168 Status = EFI_OUT_OF_RESOURCES;
1169 goto ON_EXIT;
1170 }
1171
1172 EhcLinkQhToPeriod (Ehc, Urb->Qh);
1173 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1174 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
1175
1176 *TransferResult = Urb->Result;
1177 *DataLength = Urb->Completed;
1178 *DataToggle = Urb->DataToggle;
1179
1180 if (*TransferResult == EFI_USB_NOERROR) {
1181 Status = EFI_SUCCESS;
1182 }
1183
1184 EhcFreeUrb (Ehc, Urb);
1185 ON_EXIT:
1186 Ehc->PciIo->Flush (Ehc->PciIo);
1187 gBS->RestoreTPL (OldTpl);
1188
1189 if (EFI_ERROR (Status)) {
1190 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1191 }
1192
1193 return Status;
1194 }
1195
1196 /**
1197 Submits isochronous transfer to a target USB device.
1198
1199 @param This This EFI_USB2_HC_PROTOCOL instance.
1200 @param DeviceAddress Target device address.
1201 @param EndPointAddress End point address with its direction.
1202 @param DeviceSpeed Device speed, Low speed device doesn't support this
1203 type.
1204 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1205 sending or receiving.
1206 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1207 @param Data Array of pointers to the buffers of data that will
1208 be transmitted to USB device or received from USB
1209 device.
1210 @param DataLength The size, in bytes, of the data buffer.
1211 @param Translator Transaction translator to use.
1212 @param TransferResult Variable to receive the transfer result.
1213
1214 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1215
1216 **/
1217 EFI_STATUS
1218 EFIAPI
1219 EhcIsochronousTransfer (
1220 IN EFI_USB2_HC_PROTOCOL *This,
1221 IN UINT8 DeviceAddress,
1222 IN UINT8 EndPointAddress,
1223 IN UINT8 DeviceSpeed,
1224 IN UINTN MaximumPacketLength,
1225 IN UINT8 DataBuffersNumber,
1226 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1227 IN UINTN DataLength,
1228 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1229 OUT UINT32 *TransferResult
1230 )
1231 {
1232 return EFI_UNSUPPORTED;
1233 }
1234
1235 /**
1236 Submits Async isochronous transfer to a target USB device.
1237
1238 @param This This EFI_USB2_HC_PROTOCOL instance.
1239 @param DeviceAddress Target device address.
1240 @param EndPointAddress End point address with its direction.
1241 @param DeviceSpeed Device speed, Low speed device doesn't support this
1242 type.
1243 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1244 sending or receiving.
1245 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1246 @param Data Array of pointers to the buffers of data that will
1247 be transmitted to USB device or received from USB
1248 device.
1249 @param DataLength The size, in bytes, of the data buffer.
1250 @param Translator Transaction translator to use.
1251 @param IsochronousCallBack Function to be called when the transfer complete.
1252 @param Context Context passed to the call back function as
1253 parameter.
1254
1255 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1256
1257 **/
1258 EFI_STATUS
1259 EFIAPI
1260 EhcAsyncIsochronousTransfer (
1261 IN EFI_USB2_HC_PROTOCOL *This,
1262 IN UINT8 DeviceAddress,
1263 IN UINT8 EndPointAddress,
1264 IN UINT8 DeviceSpeed,
1265 IN UINTN MaximumPacketLength,
1266 IN UINT8 DataBuffersNumber,
1267 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1268 IN UINTN DataLength,
1269 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1270 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1271 IN VOID *Context
1272 )
1273 {
1274 return EFI_UNSUPPORTED;
1275 }
1276
1277 /**
1278 Entry point for EFI drivers.
1279
1280 @param ImageHandle EFI_HANDLE.
1281 @param SystemTable EFI_SYSTEM_TABLE.
1282
1283 @return EFI_SUCCESS Success.
1284 EFI_DEVICE_ERROR Fail.
1285
1286 **/
1287 EFI_STATUS
1288 EFIAPI
1289 EhcDriverEntryPoint (
1290 IN EFI_HANDLE ImageHandle,
1291 IN EFI_SYSTEM_TABLE *SystemTable
1292 )
1293 {
1294 return EfiLibInstallDriverBindingComponentName2 (
1295 ImageHandle,
1296 SystemTable,
1297 &gEhciDriverBinding,
1298 ImageHandle,
1299 &gEhciComponentName,
1300 &gEhciComponentName2
1301 );
1302 }
1303
1304 /**
1305 Test to see if this driver supports ControllerHandle. Any
1306 ControllerHandle that has Usb2HcProtocol installed will
1307 be supported.
1308
1309 @param This Protocol instance pointer.
1310 @param Controller Handle of device to test.
1311 @param RemainingDevicePath Not used.
1312
1313 @return EFI_SUCCESS This driver supports this device.
1314 @return EFI_UNSUPPORTED This driver does not support this device.
1315
1316 **/
1317 EFI_STATUS
1318 EFIAPI
1319 EhcDriverBindingSupported (
1320 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1321 IN EFI_HANDLE Controller,
1322 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1323 )
1324 {
1325 EFI_STATUS Status;
1326 EFI_PCI_IO_PROTOCOL *PciIo;
1327 USB_CLASSC UsbClassCReg;
1328
1329 //
1330 // Test whether there is PCI IO Protocol attached on the controller handle.
1331 //
1332 Status = gBS->OpenProtocol (
1333 Controller,
1334 &gEfiPciIoProtocolGuid,
1335 (VOID **)&PciIo,
1336 This->DriverBindingHandle,
1337 Controller,
1338 EFI_OPEN_PROTOCOL_BY_DRIVER
1339 );
1340
1341 if (EFI_ERROR (Status)) {
1342 return EFI_UNSUPPORTED;
1343 }
1344
1345 Status = PciIo->Pci.Read (
1346 PciIo,
1347 EfiPciIoWidthUint8,
1348 PCI_CLASSCODE_OFFSET,
1349 sizeof (USB_CLASSC) / sizeof (UINT8),
1350 &UsbClassCReg
1351 );
1352
1353 if (EFI_ERROR (Status)) {
1354 Status = EFI_UNSUPPORTED;
1355 goto ON_EXIT;
1356 }
1357
1358 //
1359 // Test whether the controller belongs to Ehci type
1360 //
1361 if ( (UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)
1362 || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface != PCI_IF_UHCI) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI)))
1363 {
1364 Status = EFI_UNSUPPORTED;
1365 }
1366
1367 ON_EXIT:
1368 gBS->CloseProtocol (
1369 Controller,
1370 &gEfiPciIoProtocolGuid,
1371 This->DriverBindingHandle,
1372 Controller
1373 );
1374
1375 return Status;
1376 }
1377
1378 /**
1379 Get the usb debug port related information.
1380
1381 @param Ehc The EHCI device.
1382
1383 @retval RETURN_SUCCESS Get debug port number, bar and offset successfully.
1384 @retval Others The usb host controller does not supported usb debug port capability.
1385
1386 **/
1387 EFI_STATUS
1388 EhcGetUsbDebugPortInfo (
1389 IN USB2_HC_DEV *Ehc
1390 )
1391 {
1392 EFI_PCI_IO_PROTOCOL *PciIo;
1393 UINT16 PciStatus;
1394 UINT8 CapabilityPtr;
1395 UINT8 CapabilityId;
1396 UINT16 DebugPort;
1397 EFI_STATUS Status;
1398
1399 ASSERT (Ehc->PciIo != NULL);
1400 PciIo = Ehc->PciIo;
1401
1402 //
1403 // Detect if the EHCI host controller support Capaility Pointer.
1404 //
1405 Status = PciIo->Pci.Read (
1406 PciIo,
1407 EfiPciIoWidthUint8,
1408 PCI_PRIMARY_STATUS_OFFSET,
1409 sizeof (UINT16),
1410 &PciStatus
1411 );
1412
1413 if (EFI_ERROR (Status)) {
1414 return Status;
1415 }
1416
1417 if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {
1418 //
1419 // The Pci Device Doesn't Support Capability Pointer.
1420 //
1421 return EFI_UNSUPPORTED;
1422 }
1423
1424 //
1425 // Get Pointer To Capability List
1426 //
1427 Status = PciIo->Pci.Read (
1428 PciIo,
1429 EfiPciIoWidthUint8,
1430 PCI_CAPBILITY_POINTER_OFFSET,
1431 1,
1432 &CapabilityPtr
1433 );
1434
1435 if (EFI_ERROR (Status)) {
1436 return Status;
1437 }
1438
1439 //
1440 // Find Capability ID 0xA, Which Is For Debug Port
1441 //
1442 while (CapabilityPtr != 0) {
1443 Status = PciIo->Pci.Read (
1444 PciIo,
1445 EfiPciIoWidthUint8,
1446 CapabilityPtr,
1447 1,
1448 &CapabilityId
1449 );
1450
1451 if (EFI_ERROR (Status)) {
1452 return Status;
1453 }
1454
1455 if (CapabilityId == EHC_DEBUG_PORT_CAP_ID) {
1456 break;
1457 }
1458
1459 Status = PciIo->Pci.Read (
1460 PciIo,
1461 EfiPciIoWidthUint8,
1462 CapabilityPtr + 1,
1463 1,
1464 &CapabilityPtr
1465 );
1466
1467 if (EFI_ERROR (Status)) {
1468 return Status;
1469 }
1470 }
1471
1472 //
1473 // No Debug Port Capability Found
1474 //
1475 if (CapabilityPtr == 0) {
1476 return EFI_UNSUPPORTED;
1477 }
1478
1479 //
1480 // Get The Base Address Of Debug Port Register In Debug Port Capability Register
1481 //
1482 Status = PciIo->Pci.Read (
1483 Ehc->PciIo,
1484 EfiPciIoWidthUint8,
1485 CapabilityPtr + 2,
1486 sizeof (UINT16),
1487 &DebugPort
1488 );
1489
1490 if (EFI_ERROR (Status)) {
1491 return Status;
1492 }
1493
1494 Ehc->DebugPortOffset = DebugPort & 0x1FFF;
1495 Ehc->DebugPortBarNum = (UINT8)((DebugPort >> 13) - 1);
1496 Ehc->DebugPortNum = (UINT8)((Ehc->HcStructParams & 0x00F00000) >> 20);
1497
1498 return EFI_SUCCESS;
1499 }
1500
1501 /**
1502 Create and initialize a USB2_HC_DEV.
1503
1504 @param PciIo The PciIo on this device.
1505 @param DevicePath The device path of host controller.
1506 @param OriginalPciAttributes Original PCI attributes.
1507
1508 @return The allocated and initialized USB2_HC_DEV structure if created,
1509 otherwise NULL.
1510
1511 **/
1512 USB2_HC_DEV *
1513 EhcCreateUsb2Hc (
1514 IN EFI_PCI_IO_PROTOCOL *PciIo,
1515 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1516 IN UINT64 OriginalPciAttributes
1517 )
1518 {
1519 USB2_HC_DEV *Ehc;
1520 EFI_STATUS Status;
1521
1522 Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));
1523
1524 if (Ehc == NULL) {
1525 return NULL;
1526 }
1527
1528 //
1529 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1530 //
1531 Ehc->Signature = USB2_HC_DEV_SIGNATURE;
1532
1533 Ehc->Usb2Hc.GetCapability = EhcGetCapability;
1534 Ehc->Usb2Hc.Reset = EhcReset;
1535 Ehc->Usb2Hc.GetState = EhcGetState;
1536 Ehc->Usb2Hc.SetState = EhcSetState;
1537 Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;
1538 Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;
1539 Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;
1540 Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;
1541 Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;
1542 Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;
1543 Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1544 Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1545 Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1546 Ehc->Usb2Hc.MajorRevision = 0x2;
1547 Ehc->Usb2Hc.MinorRevision = 0x0;
1548
1549 Ehc->PciIo = PciIo;
1550 Ehc->DevicePath = DevicePath;
1551 Ehc->OriginalPciAttributes = OriginalPciAttributes;
1552
1553 InitializeListHead (&Ehc->AsyncIntTransfers);
1554
1555 Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);
1556 Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);
1557 Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1558
1559 DEBUG ((DEBUG_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));
1560
1561 //
1562 // EHCI Controllers with a CapLen of 0 are ignored.
1563 //
1564 if (Ehc->CapLen == 0) {
1565 gBS->FreePool (Ehc);
1566 return NULL;
1567 }
1568
1569 EhcGetUsbDebugPortInfo (Ehc);
1570
1571 //
1572 // Create AsyncRequest Polling Timer
1573 //
1574 Status = gBS->CreateEvent (
1575 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1576 TPL_NOTIFY,
1577 EhcMonitorAsyncRequests,
1578 Ehc,
1579 &Ehc->PollTimer
1580 );
1581
1582 if (EFI_ERROR (Status)) {
1583 gBS->FreePool (Ehc);
1584 return NULL;
1585 }
1586
1587 return Ehc;
1588 }
1589
1590 /**
1591 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1592
1593 @param Event Pointer to this event
1594 @param Context Event handler private data
1595
1596 **/
1597 VOID
1598 EFIAPI
1599 EhcExitBootService (
1600 EFI_EVENT Event,
1601 VOID *Context
1602 )
1603
1604 {
1605 USB2_HC_DEV *Ehc;
1606
1607 Ehc = (USB2_HC_DEV *)Context;
1608
1609 //
1610 // Reset the Host Controller
1611 //
1612 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
1613 }
1614
1615 /**
1616 Starting the Usb EHCI Driver.
1617
1618 @param This Protocol instance pointer.
1619 @param Controller Handle of device to test.
1620 @param RemainingDevicePath Not used.
1621
1622 @return EFI_SUCCESS supports this device.
1623 @return EFI_UNSUPPORTED do not support this device.
1624 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1625 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1626
1627 **/
1628 EFI_STATUS
1629 EFIAPI
1630 EhcDriverBindingStart (
1631 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1632 IN EFI_HANDLE Controller,
1633 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1634 )
1635 {
1636 EFI_STATUS Status;
1637 USB2_HC_DEV *Ehc;
1638 EFI_PCI_IO_PROTOCOL *PciIo;
1639 EFI_PCI_IO_PROTOCOL *Instance;
1640 UINT64 Supports;
1641 UINT64 OriginalPciAttributes;
1642 BOOLEAN PciAttributesSaved;
1643 USB_CLASSC UsbClassCReg;
1644 EFI_HANDLE *HandleBuffer;
1645 UINTN NumberOfHandles;
1646 UINTN Index;
1647 UINTN CompanionSegmentNumber;
1648 UINTN CompanionBusNumber;
1649 UINTN CompanionDeviceNumber;
1650 UINTN CompanionFunctionNumber;
1651 UINTN EhciSegmentNumber;
1652 UINTN EhciBusNumber;
1653 UINTN EhciDeviceNumber;
1654 UINTN EhciFunctionNumber;
1655 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1656
1657 //
1658 // Open the PciIo Protocol, then enable the USB host controller
1659 //
1660 Status = gBS->OpenProtocol (
1661 Controller,
1662 &gEfiPciIoProtocolGuid,
1663 (VOID **)&PciIo,
1664 This->DriverBindingHandle,
1665 Controller,
1666 EFI_OPEN_PROTOCOL_BY_DRIVER
1667 );
1668
1669 if (EFI_ERROR (Status)) {
1670 return Status;
1671 }
1672
1673 //
1674 // Open Device Path Protocol for on USB host controller
1675 //
1676 HcDevicePath = NULL;
1677 Status = gBS->OpenProtocol (
1678 Controller,
1679 &gEfiDevicePathProtocolGuid,
1680 (VOID **)&HcDevicePath,
1681 This->DriverBindingHandle,
1682 Controller,
1683 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1684 );
1685
1686 PciAttributesSaved = FALSE;
1687 //
1688 // Save original PCI attributes
1689 //
1690 Status = PciIo->Attributes (
1691 PciIo,
1692 EfiPciIoAttributeOperationGet,
1693 0,
1694 &OriginalPciAttributes
1695 );
1696
1697 if (EFI_ERROR (Status)) {
1698 goto CLOSE_PCIIO;
1699 }
1700
1701 PciAttributesSaved = TRUE;
1702
1703 Status = PciIo->Attributes (
1704 PciIo,
1705 EfiPciIoAttributeOperationSupported,
1706 0,
1707 &Supports
1708 );
1709 if (!EFI_ERROR (Status)) {
1710 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1711 Status = PciIo->Attributes (
1712 PciIo,
1713 EfiPciIoAttributeOperationEnable,
1714 Supports,
1715 NULL
1716 );
1717 }
1718
1719 if (EFI_ERROR (Status)) {
1720 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));
1721 goto CLOSE_PCIIO;
1722 }
1723
1724 //
1725 // Get the Pci device class code.
1726 //
1727 Status = PciIo->Pci.Read (
1728 PciIo,
1729 EfiPciIoWidthUint8,
1730 PCI_CLASSCODE_OFFSET,
1731 sizeof (USB_CLASSC) / sizeof (UINT8),
1732 &UsbClassCReg
1733 );
1734
1735 if (EFI_ERROR (Status)) {
1736 Status = EFI_UNSUPPORTED;
1737 goto CLOSE_PCIIO;
1738 }
1739
1740 //
1741 // Determine if the device is UHCI or OHCI host controller or not. If yes, then find out the
1742 // companion usb ehci host controller and force EHCI driver get attached to it before
1743 // UHCI or OHCI driver attaches to UHCI or OHCI host controller.
1744 //
1745 if (((UsbClassCReg.ProgInterface == PCI_IF_UHCI) || (UsbClassCReg.ProgInterface == PCI_IF_OHCI)) &&
1746 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
1747 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB))
1748 {
1749 Status = PciIo->GetLocation (
1750 PciIo,
1751 &CompanionSegmentNumber,
1752 &CompanionBusNumber,
1753 &CompanionDeviceNumber,
1754 &CompanionFunctionNumber
1755 );
1756 if (EFI_ERROR (Status)) {
1757 goto CLOSE_PCIIO;
1758 }
1759
1760 Status = gBS->LocateHandleBuffer (
1761 ByProtocol,
1762 &gEfiPciIoProtocolGuid,
1763 NULL,
1764 &NumberOfHandles,
1765 &HandleBuffer
1766 );
1767 if (EFI_ERROR (Status)) {
1768 goto CLOSE_PCIIO;
1769 }
1770
1771 for (Index = 0; Index < NumberOfHandles; Index++) {
1772 //
1773 // Get the device path on this handle
1774 //
1775 Status = gBS->HandleProtocol (
1776 HandleBuffer[Index],
1777 &gEfiPciIoProtocolGuid,
1778 (VOID **)&Instance
1779 );
1780 ASSERT_EFI_ERROR (Status);
1781
1782 Status = Instance->Pci.Read (
1783 Instance,
1784 EfiPciIoWidthUint8,
1785 PCI_CLASSCODE_OFFSET,
1786 sizeof (USB_CLASSC) / sizeof (UINT8),
1787 &UsbClassCReg
1788 );
1789
1790 if (EFI_ERROR (Status)) {
1791 Status = EFI_UNSUPPORTED;
1792 goto CLOSE_PCIIO;
1793 }
1794
1795 if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) &&
1796 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
1797 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB))
1798 {
1799 Status = Instance->GetLocation (
1800 Instance,
1801 &EhciSegmentNumber,
1802 &EhciBusNumber,
1803 &EhciDeviceNumber,
1804 &EhciFunctionNumber
1805 );
1806 if (EFI_ERROR (Status)) {
1807 goto CLOSE_PCIIO;
1808 }
1809
1810 //
1811 // Currently, the judgment on the companion usb host controller is through the
1812 // same bus number, which may vary on different platform.
1813 //
1814 if (EhciBusNumber == CompanionBusNumber) {
1815 gBS->CloseProtocol (
1816 Controller,
1817 &gEfiPciIoProtocolGuid,
1818 This->DriverBindingHandle,
1819 Controller
1820 );
1821 EhcDriverBindingStart (This, HandleBuffer[Index], NULL);
1822 }
1823 }
1824 }
1825
1826 Status = EFI_NOT_FOUND;
1827 goto CLOSE_PCIIO;
1828 }
1829
1830 //
1831 // Create then install USB2_HC_PROTOCOL
1832 //
1833 Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes);
1834
1835 if (Ehc == NULL) {
1836 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1837
1838 Status = EFI_OUT_OF_RESOURCES;
1839 goto CLOSE_PCIIO;
1840 }
1841
1842 //
1843 // Enable 64-bit DMA support in the PCI layer if this controller
1844 // supports it.
1845 //
1846 if (EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT)) {
1847 Status = PciIo->Attributes (
1848 PciIo,
1849 EfiPciIoAttributeOperationEnable,
1850 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
1851 NULL
1852 );
1853 if (!EFI_ERROR (Status)) {
1854 Ehc->Support64BitDma = TRUE;
1855 } else {
1856 DEBUG ((
1857 DEBUG_WARN,
1858 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
1859 __FUNCTION__,
1860 Controller,
1861 Status
1862 ));
1863 }
1864 }
1865
1866 Status = gBS->InstallProtocolInterface (
1867 &Controller,
1868 &gEfiUsb2HcProtocolGuid,
1869 EFI_NATIVE_INTERFACE,
1870 &Ehc->Usb2Hc
1871 );
1872
1873 if (EFI_ERROR (Status)) {
1874 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1875 goto FREE_POOL;
1876 }
1877
1878 //
1879 // Robustnesss improvement such as for Duet platform
1880 // Default is not required.
1881 //
1882 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1883 EhcClearLegacySupport (Ehc);
1884 }
1885
1886 if (!EhcIsDebugPortInUse (Ehc, NULL)) {
1887 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
1888 }
1889
1890 Status = EhcInitHC (Ehc);
1891
1892 if (EFI_ERROR (Status)) {
1893 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));
1894 goto UNINSTALL_USBHC;
1895 }
1896
1897 //
1898 // Start the asynchronous interrupt monitor
1899 //
1900 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);
1901
1902 if (EFI_ERROR (Status)) {
1903 DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1904
1905 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1906 goto UNINSTALL_USBHC;
1907 }
1908
1909 //
1910 // Create event to stop the HC when exit boot service.
1911 //
1912 Status = gBS->CreateEventEx (
1913 EVT_NOTIFY_SIGNAL,
1914 TPL_NOTIFY,
1915 EhcExitBootService,
1916 Ehc,
1917 &gEfiEventExitBootServicesGuid,
1918 &Ehc->ExitBootServiceEvent
1919 );
1920 if (EFI_ERROR (Status)) {
1921 goto UNINSTALL_USBHC;
1922 }
1923
1924 //
1925 // Install the component name protocol, don't fail the start
1926 // because of something for display.
1927 //
1928 AddUnicodeString2 (
1929 "eng",
1930 gEhciComponentName.SupportedLanguages,
1931 &Ehc->ControllerNameTable,
1932 L"Enhanced Host Controller (USB 2.0)",
1933 TRUE
1934 );
1935 AddUnicodeString2 (
1936 "en",
1937 gEhciComponentName2.SupportedLanguages,
1938 &Ehc->ControllerNameTable,
1939 L"Enhanced Host Controller (USB 2.0)",
1940 FALSE
1941 );
1942
1943 DEBUG ((DEBUG_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));
1944 return EFI_SUCCESS;
1945
1946 UNINSTALL_USBHC:
1947 gBS->UninstallProtocolInterface (
1948 Controller,
1949 &gEfiUsb2HcProtocolGuid,
1950 &Ehc->Usb2Hc
1951 );
1952
1953 FREE_POOL:
1954 EhcFreeSched (Ehc);
1955 gBS->CloseEvent (Ehc->PollTimer);
1956 gBS->FreePool (Ehc);
1957
1958 CLOSE_PCIIO:
1959 if (PciAttributesSaved) {
1960 //
1961 // Restore original PCI attributes
1962 //
1963 PciIo->Attributes (
1964 PciIo,
1965 EfiPciIoAttributeOperationSet,
1966 OriginalPciAttributes,
1967 NULL
1968 );
1969 }
1970
1971 gBS->CloseProtocol (
1972 Controller,
1973 &gEfiPciIoProtocolGuid,
1974 This->DriverBindingHandle,
1975 Controller
1976 );
1977
1978 return Status;
1979 }
1980
1981 /**
1982 Stop this driver on ControllerHandle. Support stopping any child handles
1983 created by this driver.
1984
1985 @param This Protocol instance pointer.
1986 @param Controller Handle of device to stop driver on.
1987 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1988 @param ChildHandleBuffer List of handles for the children we need to stop.
1989
1990 @return EFI_SUCCESS Success.
1991 @return EFI_DEVICE_ERROR Fail.
1992
1993 **/
1994 EFI_STATUS
1995 EFIAPI
1996 EhcDriverBindingStop (
1997 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1998 IN EFI_HANDLE Controller,
1999 IN UINTN NumberOfChildren,
2000 IN EFI_HANDLE *ChildHandleBuffer
2001 )
2002 {
2003 EFI_STATUS Status;
2004 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2005 EFI_PCI_IO_PROTOCOL *PciIo;
2006 USB2_HC_DEV *Ehc;
2007
2008 //
2009 // Test whether the Controller handler passed in is a valid
2010 // Usb controller handle that should be supported, if not,
2011 // return the error status directly
2012 //
2013 Status = gBS->OpenProtocol (
2014 Controller,
2015 &gEfiUsb2HcProtocolGuid,
2016 (VOID **)&Usb2Hc,
2017 This->DriverBindingHandle,
2018 Controller,
2019 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2020 );
2021
2022 if (EFI_ERROR (Status)) {
2023 return Status;
2024 }
2025
2026 Ehc = EHC_FROM_THIS (Usb2Hc);
2027 PciIo = Ehc->PciIo;
2028
2029 Status = gBS->UninstallProtocolInterface (
2030 Controller,
2031 &gEfiUsb2HcProtocolGuid,
2032 Usb2Hc
2033 );
2034
2035 if (EFI_ERROR (Status)) {
2036 return Status;
2037 }
2038
2039 //
2040 // Stop AsyncRequest Polling timer then stop the EHCI driver
2041 // and uninstall the EHCI protocl.
2042 //
2043 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);
2044 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
2045
2046 if (Ehc->PollTimer != NULL) {
2047 gBS->CloseEvent (Ehc->PollTimer);
2048 }
2049
2050 if (Ehc->ExitBootServiceEvent != NULL) {
2051 gBS->CloseEvent (Ehc->ExitBootServiceEvent);
2052 }
2053
2054 EhcFreeSched (Ehc);
2055
2056 if (Ehc->ControllerNameTable != NULL) {
2057 FreeUnicodeStringTable (Ehc->ControllerNameTable);
2058 }
2059
2060 //
2061 // Disable routing of all ports to EHCI controller, so all ports are
2062 // routed back to the UHCI or OHCI controller.
2063 //
2064 EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
2065
2066 //
2067 // Restore original PCI attributes
2068 //
2069 PciIo->Attributes (
2070 PciIo,
2071 EfiPciIoAttributeOperationSet,
2072 Ehc->OriginalPciAttributes,
2073 NULL
2074 );
2075
2076 gBS->CloseProtocol (
2077 Controller,
2078 &gEfiPciIoProtocolGuid,
2079 This->DriverBindingHandle,
2080 Controller
2081 );
2082
2083 FreePool (Ehc);
2084
2085 return EFI_SUCCESS;
2086 }