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