For the data region which will be touched by Pci Bus Master, we should allocate memor...
[edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / Uhci.c
blob1ed79023a36aff85a9ad904739bdda372fd9f134
1 /** @file
3 The UHCI driver model and HC protocol routines.
5 Copyright (c) 2004 - 2009, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 **/
16 #include "Uhci.h"
19 EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
20 UhciDriverBindingSupported,
21 UhciDriverBindingStart,
22 UhciDriverBindingStop,
23 0x20,
24 NULL,
25 NULL
28 /**
29 Provides software reset for the USB host controller according to UEFI 2.0 spec.
31 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
32 @param Attributes A bit mask of the reset operation to perform. See
33 below for a list of the supported bit mask values.
35 @return EFI_SUCCESS The reset operation succeeded.
36 @return EFI_INVALID_PARAMETER Attributes is not valid.
37 @return EFI_UNSUPPORTED This type of reset is not currently supported.
38 @return EFI_DEVICE_ERROR Other errors.
40 **/
41 EFI_STATUS
42 EFIAPI
43 Uhci2Reset (
44 IN EFI_USB2_HC_PROTOCOL *This,
45 IN UINT16 Attributes
48 USB_HC_DEV *Uhc;
49 EFI_TPL OldTpl;
51 if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||
52 (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {
53 return EFI_UNSUPPORTED;
56 Uhc = UHC_FROM_USB2_HC_PROTO (This);
58 OldTpl = gBS->RaiseTPL (UHCI_TPL);
60 switch (Attributes) {
61 case EFI_USB_HC_RESET_GLOBAL:
63 // Stop schedule and set the Global Reset bit in the command register
65 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
66 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
68 gBS->Stall (UHC_ROOT_PORT_RESET_STALL);
71 // Clear the Global Reset bit to zero.
73 UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
75 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
76 break;
78 case EFI_USB_HC_RESET_HOST_CONTROLLER:
80 // Stop schedule and set Host Controller Reset bit to 1
82 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
83 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
85 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
86 break;
88 default:
89 goto ON_INVAILD_PARAMETER;
93 // Delete all old transactions on the USB bus, then
94 // reinitialize the frame list
96 UhciFreeAllAsyncReq (Uhc);
97 UhciDestoryFrameList (Uhc);
98 UhciInitFrameList (Uhc);
100 gBS->RestoreTPL (OldTpl);
102 return EFI_SUCCESS;
104 ON_INVAILD_PARAMETER:
106 gBS->RestoreTPL (OldTpl);
108 return EFI_INVALID_PARAMETER;
113 Retrieves current state of the USB host controller according to UEFI 2.0 spec.
115 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
116 @param State Variable to receive current device state.
118 @return EFI_SUCCESS The state is returned.
119 @return EFI_INVALID_PARAMETER State is not valid.
120 @return EFI_DEVICE_ERROR Other errors.
123 EFI_STATUS
124 EFIAPI
125 Uhci2GetState (
126 IN CONST EFI_USB2_HC_PROTOCOL *This,
127 OUT EFI_USB_HC_STATE *State
130 USB_HC_DEV *Uhc;
131 UINT16 UsbSts;
132 UINT16 UsbCmd;
134 if (State == NULL) {
135 return EFI_INVALID_PARAMETER;
138 Uhc = UHC_FROM_USB2_HC_PROTO (This);
140 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
141 UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
143 if ((UsbCmd & USBCMD_EGSM) !=0 ) {
144 *State = EfiUsbHcStateSuspend;
146 } else if ((UsbSts & USBSTS_HCH) != 0) {
147 *State = EfiUsbHcStateHalt;
149 } else {
150 *State = EfiUsbHcStateOperational;
153 return EFI_SUCCESS;
158 Sets the USB host controller to a specific state according to UEFI 2.0 spec.
160 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
161 @param State Indicates the state of the host controller that will
162 be set.
164 @return EFI_SUCCESS Host controller was successfully placed in the state.
165 @return EFI_INVALID_PARAMETER State is invalid.
166 @return EFI_DEVICE_ERROR Failed to set the state.
169 EFI_STATUS
170 EFIAPI
171 Uhci2SetState (
172 IN EFI_USB2_HC_PROTOCOL *This,
173 IN EFI_USB_HC_STATE State
176 EFI_USB_HC_STATE CurState;
177 USB_HC_DEV *Uhc;
178 EFI_TPL OldTpl;
179 EFI_STATUS Status;
180 UINT16 UsbCmd;
182 Uhc = UHC_FROM_USB2_HC_PROTO (This);
183 Status = Uhci2GetState (This, &CurState);
185 if (EFI_ERROR (Status)) {
186 return EFI_DEVICE_ERROR;
189 if (CurState == State) {
190 return EFI_SUCCESS;
193 Status = EFI_SUCCESS;
194 OldTpl = gBS->RaiseTPL (UHCI_TPL);
196 switch (State) {
197 case EfiUsbHcStateHalt:
198 Status = UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
199 break;
201 case EfiUsbHcStateOperational:
202 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
204 if (CurState == EfiUsbHcStateHalt) {
206 // Set Run/Stop bit to 1, also set the bandwidht reclamation
207 // point to 64 bytes
209 UsbCmd |= USBCMD_RS | USBCMD_MAXP;
210 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
212 } else if (CurState == EfiUsbHcStateSuspend) {
214 // If FGR(Force Global Resume) bit is 0, set it
216 if ((UsbCmd & USBCMD_FGR) == 0) {
217 UsbCmd |= USBCMD_FGR;
218 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
222 // wait 20ms to let resume complete (20ms is specified by UHCI spec)
224 gBS->Stall (UHC_FORCE_GLOBAL_RESUME_STALL);
227 // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
229 UsbCmd &= ~USBCMD_FGR;
230 UsbCmd &= ~USBCMD_EGSM;
231 UsbCmd |= USBCMD_RS;
232 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
235 break;
237 case EfiUsbHcStateSuspend:
238 Status = Uhci2SetState (This, EfiUsbHcStateHalt);
240 if (EFI_ERROR (Status)) {
241 Status = EFI_DEVICE_ERROR;
242 goto ON_EXIT;
246 // Set Enter Global Suspend Mode bit to 1.
248 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
249 UsbCmd |= USBCMD_EGSM;
250 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
251 break;
253 default:
254 Status = EFI_INVALID_PARAMETER;
255 break;
258 ON_EXIT:
259 gBS->RestoreTPL (OldTpl);
260 return Status;
264 Retrieves capabilities of USB host controller according to UEFI 2.0 spec.
266 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
267 @param MaxSpeed A pointer to the max speed USB host controller
268 supports.
269 @param PortNumber A pointer to the number of root hub ports.
270 @param Is64BitCapable A pointer to an integer to show whether USB host
271 controller supports 64-bit memory addressing.
273 @return EFI_SUCCESS capabilities were retrieved successfully.
274 @return EFI_INVALID_PARAMETER MaxSpeed or PortNumber or Is64BitCapable is NULL.
275 @return EFI_DEVICE_ERROR An error was encountered.
278 EFI_STATUS
279 EFIAPI
280 Uhci2GetCapability (
281 IN EFI_USB2_HC_PROTOCOL *This,
282 OUT UINT8 *MaxSpeed,
283 OUT UINT8 *PortNumber,
284 OUT UINT8 *Is64BitCapable
287 USB_HC_DEV *Uhc;
288 UINT32 Offset;
289 UINT16 PortSC;
290 UINT32 Index;
292 Uhc = UHC_FROM_USB2_HC_PROTO (This);
294 if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {
295 return EFI_INVALID_PARAMETER;
298 *MaxSpeed = EFI_USB_SPEED_FULL;
299 *Is64BitCapable = (UINT8) FALSE;
301 *PortNumber = 0;
303 for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {
304 Offset = USBPORTSC_OFFSET + Index * 2;
305 PortSC = UhciReadReg (Uhc->PciIo, Offset);
308 // Port status's bit 7 is reserved and always returns 1 if
309 // the port number is valid. Intel's UHCI (in EHCI controller)
310 // returns 0 in this bit if port number is invalid. Also, if
311 // PciIo IoRead returns error, 0xFFFF is returned to caller.
313 if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) {
314 break;
316 (*PortNumber)++;
319 Uhc->RootPorts = *PortNumber;
321 DEBUG ((EFI_D_INFO, "Uhci2GetCapability: %d ports\n", (UINT32)Uhc->RootPorts));
322 return EFI_SUCCESS;
327 Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.
329 @param This A pointer to the EFI_USB2_HC_PROTOCOL.
330 @param PortNumber The port to get status.
331 @param PortStatus A pointer to the current port status bits and port
332 status change bits.
334 @return EFI_SUCCESS status of the USB root hub port was returned in PortStatus.
335 @return EFI_INVALID_PARAMETER PortNumber is invalid.
336 @return EFI_DEVICE_ERROR Can't read register.
339 EFI_STATUS
340 EFIAPI
341 Uhci2GetRootHubPortStatus (
342 IN CONST EFI_USB2_HC_PROTOCOL *This,
343 IN CONST UINT8 PortNumber,
344 OUT EFI_USB_PORT_STATUS *PortStatus
347 USB_HC_DEV *Uhc;
348 UINT32 Offset;
349 UINT16 PortSC;
351 Uhc = UHC_FROM_USB2_HC_PROTO (This);
353 if (PortStatus == NULL) {
354 return EFI_INVALID_PARAMETER;
357 if (PortNumber >= Uhc->RootPorts) {
358 return EFI_INVALID_PARAMETER;
361 Offset = USBPORTSC_OFFSET + PortNumber * 2;
362 PortStatus->PortStatus = 0;
363 PortStatus->PortChangeStatus = 0;
365 PortSC = UhciReadReg (Uhc->PciIo, Offset);
367 if ((PortSC & USBPORTSC_CCS) != 0) {
368 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
371 if ((PortSC & USBPORTSC_PED) != 0) {
372 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
375 if ((PortSC & USBPORTSC_SUSP) != 0) {
376 DEBUG ((EFI_D_INFO, "Uhci2GetRootHubPortStatus: port %d is suspended\n", PortNumber));
377 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
380 if ((PortSC & USBPORTSC_PR) != 0) {
381 PortStatus->PortStatus |= USB_PORT_STAT_RESET;
384 if ((PortSC & USBPORTSC_LSDA) != 0) {
385 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
389 // CHC will always return one in port owner bit
391 PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
393 if ((PortSC & USBPORTSC_CSC) != 0) {
394 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
397 if ((PortSC & USBPORTSC_PEDC) != 0) {
398 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
401 return EFI_SUCCESS;
406 Sets a feature for the specified root hub port according to UEFI 2.0 spec.
408 @param This A pointer to the EFI_USB2_HC_PROTOCOL.
409 @param PortNumber Specifies the root hub port whose feature is
410 requested to be set.
411 @param PortFeature Indicates the feature selector associated with the
412 feature set request.
414 @return EFI_SUCCESS PortFeature was set for the root port.
415 @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
416 @return EFI_DEVICE_ERROR Can't read register.
419 EFI_STATUS
420 EFIAPI
421 Uhci2SetRootHubPortFeature (
422 IN EFI_USB2_HC_PROTOCOL *This,
423 IN UINT8 PortNumber,
424 IN EFI_USB_PORT_FEATURE PortFeature
427 USB_HC_DEV *Uhc;
428 EFI_TPL OldTpl;
429 UINT32 Offset;
430 UINT16 PortSC;
431 UINT16 Command;
433 Uhc = UHC_FROM_USB2_HC_PROTO (This);
435 if (PortNumber >= Uhc->RootPorts) {
436 return EFI_INVALID_PARAMETER;
439 Offset = USBPORTSC_OFFSET + PortNumber * 2;
441 OldTpl = gBS->RaiseTPL (UHCI_TPL);
442 PortSC = UhciReadReg (Uhc->PciIo, Offset);
444 switch (PortFeature) {
445 case EfiUsbPortSuspend:
446 Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
447 if ((Command & USBCMD_EGSM) == 0) {
449 // if global suspend is not active, can set port suspend
451 PortSC &= 0xfff5;
452 PortSC |= USBPORTSC_SUSP;
454 break;
456 case EfiUsbPortReset:
457 PortSC &= 0xfff5;
458 PortSC |= USBPORTSC_PR;
459 break;
461 case EfiUsbPortPower:
463 // No action
465 break;
467 case EfiUsbPortEnable:
468 PortSC &= 0xfff5;
469 PortSC |= USBPORTSC_PED;
470 break;
472 default:
473 gBS->RestoreTPL (OldTpl);
474 return EFI_INVALID_PARAMETER;
477 UhciWriteReg (Uhc->PciIo, Offset, PortSC);
478 gBS->RestoreTPL (OldTpl);
480 return EFI_SUCCESS;
485 Clears a feature for the specified root hub port according to Uefi 2.0 spec.
487 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
488 @param PortNumber Specifies the root hub port whose feature is
489 requested to be cleared.
490 @param PortFeature Indicates the feature selector associated with the
491 feature clear request.
493 @return EFI_SUCCESS PortFeature was cleared for the USB root hub port.
494 @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
495 @return EFI_DEVICE_ERROR Can't read register.
498 EFI_STATUS
499 EFIAPI
500 Uhci2ClearRootHubPortFeature (
501 IN EFI_USB2_HC_PROTOCOL *This,
502 IN UINT8 PortNumber,
503 IN EFI_USB_PORT_FEATURE PortFeature
506 USB_HC_DEV *Uhc;
507 EFI_TPL OldTpl;
508 UINT32 Offset;
509 UINT16 PortSC;
511 Uhc = UHC_FROM_USB2_HC_PROTO (This);
513 if (PortNumber >= Uhc->RootPorts) {
514 return EFI_INVALID_PARAMETER;
517 Offset = USBPORTSC_OFFSET + PortNumber * 2;
519 OldTpl = gBS->RaiseTPL (UHCI_TPL);
520 PortSC = UhciReadReg (Uhc->PciIo, Offset);
522 switch (PortFeature) {
523 case EfiUsbPortEnable:
524 PortSC &= 0xfff5;
525 PortSC &= ~USBPORTSC_PED;
526 break;
528 case EfiUsbPortSuspend:
530 // Cause a resume on the specified port if in suspend mode.
532 PortSC &= 0xfff5;
533 PortSC &= ~USBPORTSC_SUSP;
534 break;
536 case EfiUsbPortPower:
538 // No action
540 break;
542 case EfiUsbPortReset:
543 PortSC &= 0xfff5;
544 PortSC &= ~USBPORTSC_PR;
545 break;
547 case EfiUsbPortConnectChange:
548 PortSC &= 0xfff5;
549 PortSC |= USBPORTSC_CSC;
550 break;
552 case EfiUsbPortEnableChange:
553 PortSC &= 0xfff5;
554 PortSC |= USBPORTSC_PEDC;
555 break;
557 case EfiUsbPortSuspendChange:
559 // Root hub does not support this
561 break;
563 case EfiUsbPortOverCurrentChange:
565 // Root hub does not support this
567 break;
569 case EfiUsbPortResetChange:
571 // Root hub does not support this
573 break;
575 default:
576 gBS->RestoreTPL (OldTpl);
577 return EFI_INVALID_PARAMETER;
580 UhciWriteReg (Uhc->PciIo, Offset, PortSC);
581 gBS->RestoreTPL (OldTpl);
583 return EFI_SUCCESS;
588 Submits control transfer to a target USB device accroding to UEFI 2.0 spec.
590 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
591 @param DeviceAddress Target device address.
592 @param DeviceSpeed Device speed.
593 @param MaximumPacketLength Maximum packet size of the target endpoint.
594 @param Request USB device request to send.
595 @param TransferDirection Data direction of the Data stage in control transfer.
596 @param Data Data to transmit/receive in data stage.
597 @param DataLength Length of the data.
598 @param TimeOut Maximum time, in microseconds, for transfer to complete.
599 @param Translator Transaction translator to be used by this device.
600 @param TransferResult Variable to receive the transfer result.
602 @return EFI_SUCCESS The control transfer was completed successfully.
603 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
604 @return EFI_INVALID_PARAMETER Some parameters are invalid.
605 @return EFI_TIMEOUT Failed due to timeout.
606 @return EFI_DEVICE_ERROR Failed due to host controller or device error.
609 EFI_STATUS
610 EFIAPI
611 Uhci2ControlTransfer (
612 IN EFI_USB2_HC_PROTOCOL *This,
613 IN UINT8 DeviceAddress,
614 IN UINT8 DeviceSpeed,
615 IN UINTN MaximumPacketLength,
616 IN EFI_USB_DEVICE_REQUEST *Request,
617 IN EFI_USB_DATA_DIRECTION TransferDirection,
618 IN OUT VOID *Data,
619 IN OUT UINTN *DataLength,
620 IN UINTN TimeOut,
621 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
622 OUT UINT32 *TransferResult
625 USB_HC_DEV *Uhc;
626 UHCI_TD_SW *TDs;
627 EFI_TPL OldTpl;
628 EFI_STATUS Status;
629 UHCI_QH_RESULT QhResult;
630 UINT8 PktId;
631 UINT8 *RequestPhy;
632 VOID *RequestMap;
633 UINT8 *DataPhy;
634 VOID *DataMap;
635 BOOLEAN IsSlowDevice;
636 UINTN TransferDataLength;
638 Uhc = UHC_FROM_USB2_HC_PROTO (This);
639 TDs = NULL;
640 DataPhy = NULL;
641 DataMap = NULL;
642 RequestPhy = NULL;
643 RequestMap = NULL;
645 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
648 // Parameters Checking
650 if (Request == NULL || TransferResult == NULL) {
651 return EFI_INVALID_PARAMETER;
654 if (IsSlowDevice && (MaximumPacketLength != 8)) {
655 return EFI_INVALID_PARAMETER;
658 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
659 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
661 return EFI_INVALID_PARAMETER;
664 if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) {
665 return EFI_INVALID_PARAMETER;
668 if (TransferDirection == EfiUsbNoData) {
669 TransferDataLength = 0;
670 } else {
671 TransferDataLength = *DataLength;
674 *TransferResult = EFI_USB_ERR_SYSTEM;
675 Status = EFI_DEVICE_ERROR;
678 // If errors exist that cause host controller halt,
679 // clear status then return EFI_DEVICE_ERROR.
681 UhciAckAllInterrupt (Uhc);
683 if (!UhciIsHcWorking (Uhc->PciIo)) {
684 return EFI_DEVICE_ERROR;
687 OldTpl = gBS->RaiseTPL (UHCI_TPL);
690 // Map the Request and data for bus master access,
691 // then create a list of TD for this transfer
693 Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);
695 if (EFI_ERROR (Status)) {
696 goto ON_EXIT;
699 Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);
701 if (EFI_ERROR (Status)) {
702 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
703 goto ON_EXIT;
706 TDs = UhciCreateCtrlTds (
707 Uhc,
708 DeviceAddress,
709 PktId,
710 (UINT8*)Request,
711 RequestPhy,
712 (UINT8*)Data,
713 DataPhy,
714 TransferDataLength,
715 (UINT8) MaximumPacketLength,
716 IsSlowDevice
719 if (TDs == NULL) {
720 Status = EFI_OUT_OF_RESOURCES;
721 goto UNMAP_DATA;
725 // According to the speed of the end point, link
726 // the TD to corrosponding queue head, then check
727 // the execution result
729 UhciLinkTdToQh (Uhc, Uhc->CtrlQh, TDs);
730 Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);
731 UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);
733 Uhc->PciIo->Flush (Uhc->PciIo);
735 *TransferResult = QhResult.Result;
737 if (DataLength != NULL) {
738 *DataLength = QhResult.Complete;
741 UhciDestoryTds (Uhc, TDs);
743 UNMAP_DATA:
744 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
745 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
747 ON_EXIT:
748 gBS->RestoreTPL (OldTpl);
749 return Status;
754 Submits bulk transfer to a bulk endpoint of a USB device.
756 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
757 @param DeviceAddress Target device address.
758 @param EndPointAddress Endpoint number and direction.
759 @param DeviceSpeed Device speed.
760 @param MaximumPacketLength Maximum packet size of the target endpoint.
761 @param DataBuffersNumber Number of data buffers prepared for the transfer.
762 @param Data Array of pointers to the buffers of data.
763 @param DataLength On input, size of the data buffer, On output,
764 actually transferred data size.
765 @param DataToggle On input, data toggle to use; On output, next data toggle.
766 @param TimeOut Maximum time out, in microseconds.
767 @param Translator A pointr to the transaction translator data.
768 @param TransferResult Variable to receive transfer result.
770 @return EFI_SUCCESS The bulk transfer was completed successfully.
771 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
772 @return EFI_INVALID_PARAMETER Some parameters are invalid.
773 @return EFI_TIMEOUT Failed due to timeout.
774 @return EFI_DEVICE_ERROR Failed due to host controller or device error.
777 EFI_STATUS
778 EFIAPI
779 Uhci2BulkTransfer (
780 IN EFI_USB2_HC_PROTOCOL *This,
781 IN UINT8 DeviceAddress,
782 IN UINT8 EndPointAddress,
783 IN UINT8 DeviceSpeed,
784 IN UINTN MaximumPacketLength,
785 IN UINT8 DataBuffersNumber,
786 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
787 IN OUT UINTN *DataLength,
788 IN OUT UINT8 *DataToggle,
789 IN UINTN TimeOut,
790 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
791 OUT UINT32 *TransferResult
794 EFI_USB_DATA_DIRECTION Direction;
795 EFI_TPL OldTpl;
796 USB_HC_DEV *Uhc;
797 UHCI_TD_SW *TDs;
798 UHCI_QH_SW *BulkQh;
799 UHCI_QH_RESULT QhResult;
800 EFI_STATUS Status;
801 UINT8 PktId;
802 UINT8 *DataPhy;
803 VOID *DataMap;
805 Uhc = UHC_FROM_USB2_HC_PROTO (This);
806 DataPhy = NULL;
807 DataMap = NULL;
809 if (DeviceSpeed == EFI_USB_SPEED_LOW) {
810 return EFI_INVALID_PARAMETER;
813 if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
814 return EFI_INVALID_PARAMETER;
817 if ((*DataToggle != 1) && (*DataToggle != 0)) {
818 return EFI_INVALID_PARAMETER;
821 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
822 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
823 return EFI_INVALID_PARAMETER;
826 *TransferResult = EFI_USB_ERR_SYSTEM;
827 Status = EFI_OUT_OF_RESOURCES;
830 // If has errors that cause host controller halt,
831 // then return EFI_DEVICE_ERROR directly.
833 UhciAckAllInterrupt (Uhc);
835 if (!UhciIsHcWorking (Uhc->PciIo)) {
836 return EFI_DEVICE_ERROR;
839 OldTpl = gBS->RaiseTPL (UHCI_TPL);
842 // Map the source data buffer for bus master access,
843 // then create a list of TDs
845 if ((EndPointAddress & 0x80) != 0) {
846 Direction = EfiUsbDataIn;
847 } else {
848 Direction = EfiUsbDataOut;
851 Status = UhciMapUserData (Uhc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap);
853 if (EFI_ERROR (Status)) {
854 goto ON_EXIT;
857 Status = EFI_OUT_OF_RESOURCES;
858 TDs = UhciCreateBulkOrIntTds (
859 Uhc,
860 DeviceAddress,
861 EndPointAddress,
862 PktId,
863 (UINT8 *)*Data,
864 DataPhy,
865 *DataLength,
866 DataToggle,
867 (UINT8) MaximumPacketLength,
868 FALSE
871 if (TDs == NULL) {
872 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
873 goto ON_EXIT;
878 // Link the TDs to bulk queue head. According to the platfore
879 // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured
880 // to do full speed bandwidth reclamation or not.
882 BulkQh = Uhc->BulkQh;
884 UhciLinkTdToQh (Uhc, BulkQh, TDs);
885 Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);
886 UhciUnlinkTdFromQh (BulkQh, TDs);
888 Uhc->PciIo->Flush (Uhc->PciIo);
890 *TransferResult = QhResult.Result;
891 *DataToggle = QhResult.NextToggle;
892 *DataLength = QhResult.Complete;
894 UhciDestoryTds (Uhc, TDs);
895 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
897 ON_EXIT:
898 gBS->RestoreTPL (OldTpl);
899 return Status;
904 Submits an asynchronous interrupt transfer to an
905 interrupt endpoint of a USB device according to UEFI 2.0 spec.
907 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
908 @param DeviceAddress Target device address.
909 @param EndPointAddress Endpoint number and direction.
910 @param DeviceSpeed Device speed.
911 @param MaximumPacketLength Maximum packet size of the target endpoint.
912 @param IsNewTransfer If TRUE, submit a new transfer, if FALSE cancel old transfer.
913 @param DataToggle On input, data toggle to use; On output, next data toggle.
914 @param PollingInterval Interrupt poll rate in milliseconds.
915 @param DataLength On input, size of the data buffer, On output,
916 actually transferred data size.
917 @param Translator A pointr to the transaction translator data.
918 @param CallBackFunction Function to call periodically.
919 @param Context User context.
921 @return EFI_SUCCESS Transfer was submitted.
922 @return EFI_INVALID_PARAMETER Some parameters are invalid.
923 @return EFI_OUT_OF_RESOURCES Failed due to a lack of resources.
924 @return EFI_DEVICE_ERROR Can't read register.
927 EFI_STATUS
928 EFIAPI
929 Uhci2AsyncInterruptTransfer (
930 IN EFI_USB2_HC_PROTOCOL *This,
931 IN UINT8 DeviceAddress,
932 IN UINT8 EndPointAddress,
933 IN UINT8 DeviceSpeed,
934 IN UINTN MaximumPacketLength,
935 IN BOOLEAN IsNewTransfer,
936 IN OUT UINT8 *DataToggle,
937 IN UINTN PollingInterval,
938 IN UINTN DataLength,
939 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
940 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
941 IN VOID *Context
944 USB_HC_DEV *Uhc;
945 BOOLEAN IsSlowDevice;
946 UHCI_QH_SW *Qh;
947 UHCI_TD_SW *IntTds;
948 EFI_TPL OldTpl;
949 EFI_STATUS Status;
950 UINT8 *DataPtr;
951 UINT8 *DataPhy;
952 VOID *DataMap;
953 UINT8 PktId;
955 Uhc = UHC_FROM_USB2_HC_PROTO (This);
956 Qh = NULL;
957 IntTds = NULL;
958 DataPtr = NULL;
959 DataPhy = NULL;
960 DataMap = NULL;
962 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
964 if ((EndPointAddress & 0x80) == 0) {
965 return EFI_INVALID_PARAMETER;
969 // Delete Async interrupt transfer request
971 if (!IsNewTransfer) {
972 OldTpl = gBS->RaiseTPL (UHCI_TPL);
973 Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);
975 gBS->RestoreTPL (OldTpl);
976 return Status;
979 if (PollingInterval < 1 || PollingInterval > 255) {
980 return EFI_INVALID_PARAMETER;
983 if (DataLength == 0) {
984 return EFI_INVALID_PARAMETER;
987 if ((*DataToggle != 1) && (*DataToggle != 0)) {
988 return EFI_INVALID_PARAMETER;
992 // If has errors that cause host controller halt,
993 // then return EFI_DEVICE_ERROR directly.
995 UhciAckAllInterrupt (Uhc);
997 if (!UhciIsHcWorking (Uhc->PciIo)) {
998 return EFI_DEVICE_ERROR;
1002 // Allocate and map source data buffer for bus master access.
1004 DataPtr = UsbHcAllocateMem (Uhc->MemPool, DataLength);
1006 if (DataPtr == NULL) {
1007 return EFI_OUT_OF_RESOURCES;
1010 OldTpl = gBS->RaiseTPL (UHCI_TPL);
1013 // Map the user data then create a queue head and
1014 // list of TD for it.
1016 Status = UhciMapUserData (
1017 Uhc,
1018 EfiUsbDataIn,
1019 DataPtr,
1020 &DataLength,
1021 &PktId,
1022 &DataPhy,
1023 &DataMap
1026 if (EFI_ERROR (Status)) {
1027 goto FREE_DATA;
1030 Qh = UhciCreateQh (Uhc, PollingInterval);
1032 if (Qh == NULL) {
1033 Status = EFI_OUT_OF_RESOURCES;
1034 goto UNMAP_DATA;
1037 IntTds = UhciCreateBulkOrIntTds (
1038 Uhc,
1039 DeviceAddress,
1040 EndPointAddress,
1041 PktId,
1042 DataPtr,
1043 DataPhy,
1044 DataLength,
1045 DataToggle,
1046 (UINT8) MaximumPacketLength,
1047 IsSlowDevice
1050 if (IntTds == NULL) {
1051 Status = EFI_OUT_OF_RESOURCES;
1052 goto DESTORY_QH;
1055 UhciLinkTdToQh (Uhc, Qh, IntTds);
1058 // Save QH-TD structures to async Interrupt transfer list,
1059 // for monitor interrupt transfer execution routine use.
1061 Status = UhciCreateAsyncReq (
1062 Uhc,
1064 IntTds,
1065 DeviceAddress,
1066 EndPointAddress,
1067 DataLength,
1068 PollingInterval,
1069 DataMap,
1070 DataPtr,
1071 CallBackFunction,
1072 Context,
1073 IsSlowDevice
1076 if (EFI_ERROR (Status)) {
1077 goto DESTORY_QH;
1080 UhciLinkQhToFrameList (Uhc, Qh);
1082 gBS->RestoreTPL (OldTpl);
1083 return EFI_SUCCESS;
1085 DESTORY_QH:
1086 UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));
1088 UNMAP_DATA:
1089 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1091 FREE_DATA:
1092 gBS->FreePool (DataPtr);
1093 Uhc->PciIo->Flush (Uhc->PciIo);
1095 gBS->RestoreTPL (OldTpl);
1096 return Status;
1100 Submits synchronous interrupt transfer to an interrupt endpoint
1101 of a USB device according to UEFI 2.0 spec.
1104 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1105 @param DeviceAddress Target device address.
1106 @param EndPointAddress Endpoint number and direction.
1107 @param DeviceSpeed Device speed.
1108 @param MaximumPacketLength Maximum packet size of the target endpoint.
1109 @param Data Array of pointers to the buffers of data.
1110 @param DataLength On input, size of the data buffer, On output,
1111 actually transferred data size.
1112 @param DataToggle On input, data toggle to use; On output, next data toggle.
1113 @param TimeOut Maximum time out, in microseconds.
1114 @param Translator A pointr to the transaction translator data.
1115 @param TransferResult Variable to receive transfer result.
1117 @return EFI_SUCCESS The transfer was completed successfully.
1118 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
1119 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1120 @return EFI_TIMEOUT Failed due to timeout.
1121 @return EFI_DEVICE_ERROR Failed due to host controller or device error.
1124 EFI_STATUS
1125 EFIAPI
1126 Uhci2SyncInterruptTransfer (
1127 IN EFI_USB2_HC_PROTOCOL *This,
1128 IN UINT8 DeviceAddress,
1129 IN UINT8 EndPointAddress,
1130 IN UINT8 DeviceSpeed,
1131 IN UINTN MaximumPacketLength,
1132 IN OUT VOID *Data,
1133 IN OUT UINTN *DataLength,
1134 IN OUT UINT8 *DataToggle,
1135 IN UINTN TimeOut,
1136 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1137 OUT UINT32 *TransferResult
1140 EFI_STATUS Status;
1141 USB_HC_DEV *Uhc;
1142 UHCI_TD_SW *TDs;
1143 UHCI_QH_RESULT QhResult;
1144 EFI_TPL OldTpl;
1145 UINT8 *DataPhy;
1146 VOID *DataMap;
1147 UINT8 PktId;
1148 BOOLEAN IsSlowDevice;
1150 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1151 DataPhy = NULL;
1152 DataMap = NULL;
1153 TDs = NULL;
1155 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1156 return EFI_INVALID_PARAMETER;
1159 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
1161 if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
1162 return EFI_INVALID_PARAMETER;
1165 if ((EndPointAddress & 0x80) == 0) {
1166 return EFI_INVALID_PARAMETER;
1169 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1170 return EFI_INVALID_PARAMETER;
1173 if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
1174 return EFI_INVALID_PARAMETER;
1177 if (IsSlowDevice && (MaximumPacketLength > 8)) {
1178 return EFI_INVALID_PARAMETER;
1181 *TransferResult = EFI_USB_ERR_SYSTEM;
1182 Status = EFI_DEVICE_ERROR;
1185 UhciAckAllInterrupt (Uhc);
1187 if (!UhciIsHcWorking (Uhc->PciIo)) {
1188 return Status;
1191 OldTpl = gBS->RaiseTPL (UHCI_TPL);
1194 // Map the source data buffer for bus master access.
1195 // Create Tds list, then link it to the UHC's interrupt list
1197 Status = UhciMapUserData (
1198 Uhc,
1199 EfiUsbDataIn,
1200 Data,
1201 DataLength,
1202 &PktId,
1203 &DataPhy,
1204 &DataMap
1207 if (EFI_ERROR (Status)) {
1208 goto ON_EXIT;
1211 TDs = UhciCreateBulkOrIntTds (
1212 Uhc,
1213 DeviceAddress,
1214 EndPointAddress,
1215 PktId,
1216 (UINT8 *)Data,
1217 DataPhy,
1218 *DataLength,
1219 DataToggle,
1220 (UINT8) MaximumPacketLength,
1221 IsSlowDevice
1224 if (TDs == NULL) {
1225 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1227 Status = EFI_OUT_OF_RESOURCES;
1228 goto ON_EXIT;
1232 UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);
1234 Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
1236 UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
1237 Uhc->PciIo->Flush (Uhc->PciIo);
1239 *TransferResult = QhResult.Result;
1240 *DataToggle = QhResult.NextToggle;
1241 *DataLength = QhResult.Complete;
1243 UhciDestoryTds (Uhc, TDs);
1244 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1246 ON_EXIT:
1247 gBS->RestoreTPL (OldTpl);
1248 return Status;
1253 Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
1255 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1256 @param DeviceAddress Target device address.
1257 @param EndPointAddress Endpoint number and direction.
1258 @param DeviceSpeed Device speed.
1259 @param MaximumPacketLength Maximum packet size of the target endpoint.
1260 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1261 @param Data Array of pointers to the buffers of data.
1262 @param DataLength On input, size of the data buffer, On output,
1263 actually transferred data size.
1264 @param Translator A pointr to the transaction translator data.
1265 @param TransferResult Variable to receive transfer result.
1267 @return EFI_UNSUPPORTED
1270 EFI_STATUS
1271 EFIAPI
1272 Uhci2IsochronousTransfer (
1273 IN EFI_USB2_HC_PROTOCOL *This,
1274 IN UINT8 DeviceAddress,
1275 IN UINT8 EndPointAddress,
1276 IN UINT8 DeviceSpeed,
1277 IN UINTN MaximumPacketLength,
1278 IN UINT8 DataBuffersNumber,
1279 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1280 IN UINTN DataLength,
1281 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1282 OUT UINT32 *TransferResult
1285 return EFI_UNSUPPORTED;
1290 Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
1292 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1293 @param DeviceAddress Target device address.
1294 @param EndPointAddress Endpoint number and direction.
1295 @param DeviceSpeed Device speed.
1296 @param MaximumPacketLength Maximum packet size of the target endpoint.
1297 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1298 @param Data Array of pointers to the buffers of data.
1299 @param DataLength On input, size of the data buffer, On output,
1300 actually transferred data size.
1301 @param Translator A pointr to the transaction translator data.
1302 @param IsochronousCallBack Function to call when the transfer complete.
1303 @param Context Pass to the call back function as parameter.
1305 @return EFI_UNSUPPORTED
1308 EFI_STATUS
1309 EFIAPI
1310 Uhci2AsyncIsochronousTransfer (
1311 IN EFI_USB2_HC_PROTOCOL *This,
1312 IN UINT8 DeviceAddress,
1313 IN UINT8 EndPointAddress,
1314 IN UINT8 DeviceSpeed,
1315 IN UINTN MaximumPacketLength,
1316 IN UINT8 DataBuffersNumber,
1317 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1318 IN UINTN DataLength,
1319 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1320 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1321 IN VOID *Context
1324 return EFI_UNSUPPORTED;
1328 Entry point for EFI drivers.
1330 @param ImageHandle EFI_HANDLE.
1331 @param SystemTable EFI_SYSTEM_TABLE.
1333 @retval EFI_SUCCESS Driver is successfully loaded.
1334 @return Others Failed.
1337 EFI_STATUS
1338 EFIAPI
1339 UhciDriverEntryPoint (
1340 IN EFI_HANDLE ImageHandle,
1341 IN EFI_SYSTEM_TABLE *SystemTable
1344 return EfiLibInstallDriverBindingComponentName2 (
1345 ImageHandle,
1346 SystemTable,
1347 &gUhciDriverBinding,
1348 ImageHandle,
1349 &gUhciComponentName,
1350 &gUhciComponentName2
1356 Test to see if this driver supports ControllerHandle. Any
1357 ControllerHandle that has UsbHcProtocol installed will be supported.
1359 @param This Protocol instance pointer.
1360 @param Controller Handle of device to test.
1361 @param RemainingDevicePath Not used.
1363 @return EFI_SUCCESS This driver supports this device.
1364 @return EFI_UNSUPPORTED This driver does not support this device.
1367 EFI_STATUS
1368 EFIAPI
1369 UhciDriverBindingSupported (
1370 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1371 IN EFI_HANDLE Controller,
1372 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1375 EFI_STATUS OpenStatus;
1376 EFI_STATUS Status;
1377 EFI_PCI_IO_PROTOCOL *PciIo;
1378 USB_CLASSC UsbClassCReg;
1381 // Test whether there is PCI IO Protocol attached on the controller handle.
1383 OpenStatus = gBS->OpenProtocol (
1384 Controller,
1385 &gEfiPciIoProtocolGuid,
1386 (VOID **) &PciIo,
1387 This->DriverBindingHandle,
1388 Controller,
1389 EFI_OPEN_PROTOCOL_BY_DRIVER
1392 if (EFI_ERROR (OpenStatus)) {
1393 return OpenStatus;
1396 Status = PciIo->Pci.Read (
1397 PciIo,
1398 EfiPciIoWidthUint8,
1399 PCI_CLASSCODE_OFFSET,
1400 sizeof (USB_CLASSC) / sizeof (UINT8),
1401 &UsbClassCReg
1404 if (EFI_ERROR (Status)) {
1405 Status = EFI_UNSUPPORTED;
1406 goto ON_EXIT;
1410 // Test whether the controller belongs to UHCI type
1412 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1413 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1414 (UsbClassCReg.PI != PCI_IF_UHCI)
1417 Status = EFI_UNSUPPORTED;
1420 ON_EXIT:
1421 gBS->CloseProtocol (
1422 Controller,
1423 &gEfiPciIoProtocolGuid,
1424 This->DriverBindingHandle,
1425 Controller
1428 return Status;
1434 Allocate and initialize the empty UHCI device.
1436 @param PciIo The PCIIO to use.
1437 @param OriginalPciAttributes The original PCI attributes.
1439 @return Allocated UHCI device. If err, return NULL.
1442 USB_HC_DEV *
1443 UhciAllocateDev (
1444 IN EFI_PCI_IO_PROTOCOL *PciIo,
1445 IN UINT64 OriginalPciAttributes
1448 USB_HC_DEV *Uhc;
1449 EFI_STATUS Status;
1451 Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
1453 if (Uhc == NULL) {
1454 return NULL;
1458 // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
1459 // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
1461 Uhc->Signature = USB_HC_DEV_SIGNATURE;
1462 Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;
1463 Uhc->Usb2Hc.Reset = Uhci2Reset;
1464 Uhc->Usb2Hc.GetState = Uhci2GetState;
1465 Uhc->Usb2Hc.SetState = Uhci2SetState;
1466 Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;
1467 Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;
1468 Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;
1469 Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;
1470 Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;
1471 Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;
1472 Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;
1473 Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;
1474 Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;
1475 Uhc->Usb2Hc.MajorRevision = 0x1;
1476 Uhc->Usb2Hc.MinorRevision = 0x1;
1478 Uhc->PciIo = PciIo;
1479 Uhc->OriginalPciAttributes = OriginalPciAttributes;
1480 Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);
1482 if (Uhc->MemPool == NULL) {
1483 Status = EFI_OUT_OF_RESOURCES;
1484 goto ON_ERROR;
1487 InitializeListHead (&Uhc->AsyncIntList);
1489 Status = gBS->CreateEvent (
1490 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1491 TPL_CALLBACK,
1492 UhciMonitorAsyncReqList,
1493 Uhc,
1494 &Uhc->AsyncIntMonitor
1497 if (EFI_ERROR (Status)) {
1498 UsbHcFreeMemPool (Uhc->MemPool);
1499 goto ON_ERROR;
1502 return Uhc;
1504 ON_ERROR:
1505 FreePool (Uhc);
1506 return NULL;
1511 Free the UHCI device and release its associated resources.
1513 @param Uhc The UHCI device to release.
1516 VOID
1517 UhciFreeDev (
1518 IN USB_HC_DEV *Uhc
1521 if (Uhc->AsyncIntMonitor != NULL) {
1522 gBS->CloseEvent (Uhc->AsyncIntMonitor);
1525 if (Uhc->ExitBootServiceEvent != NULL) {
1526 gBS->CloseEvent (Uhc->ExitBootServiceEvent);
1529 if (Uhc->MemPool != NULL) {
1530 UsbHcFreeMemPool (Uhc->MemPool);
1533 if (Uhc->CtrlNameTable != NULL) {
1534 FreeUnicodeStringTable (Uhc->CtrlNameTable);
1537 FreePool (Uhc);
1542 Uninstall all Uhci Interface.
1544 @param Controller Controller handle.
1545 @param This Protocol instance pointer.
1548 VOID
1549 UhciCleanDevUp (
1550 IN EFI_HANDLE Controller,
1551 IN EFI_USB2_HC_PROTOCOL *This
1554 USB_HC_DEV *Uhc;
1557 // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
1559 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1560 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1562 gBS->UninstallProtocolInterface (
1563 Controller,
1564 &gEfiUsb2HcProtocolGuid,
1565 &Uhc->Usb2Hc
1568 UhciFreeAllAsyncReq (Uhc);
1569 UhciDestoryFrameList (Uhc);
1572 // Restore original PCI attributes
1574 Uhc->PciIo->Attributes (
1575 Uhc->PciIo,
1576 EfiPciIoAttributeOperationSet,
1577 Uhc->OriginalPciAttributes,
1578 NULL
1581 UhciFreeDev (Uhc);
1585 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1587 @param Event Pointer to this event
1588 @param Context Event hanlder private data
1591 VOID
1592 EFIAPI
1593 UhcExitBootService (
1594 EFI_EVENT Event,
1595 VOID *Context
1598 USB_HC_DEV *Uhc;
1600 Uhc = (USB_HC_DEV *) Context;
1603 // Stop the Host Controller
1605 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1607 return;
1611 Starting the Usb UHCI Driver.
1613 @param This Protocol instance pointer.
1614 @param Controller Handle of device to test.
1615 @param RemainingDevicePath Not used.
1617 @retval EFI_SUCCESS This driver supports this device.
1618 @retval EFI_UNSUPPORTED This driver does not support this device.
1619 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
1620 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
1623 EFI_STATUS
1624 EFIAPI
1625 UhciDriverBindingStart (
1626 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1627 IN EFI_HANDLE Controller,
1628 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1631 EFI_STATUS Status;
1632 EFI_PCI_IO_PROTOCOL *PciIo;
1633 USB_HC_DEV *Uhc;
1634 UINT64 Supports;
1635 UINT64 OriginalPciAttributes;
1636 BOOLEAN PciAttributesSaved;
1639 // Open PCIIO, then enable the EHC device and turn off emulation
1641 Uhc = NULL;
1642 Status = gBS->OpenProtocol (
1643 Controller,
1644 &gEfiPciIoProtocolGuid,
1645 (VOID **) &PciIo,
1646 This->DriverBindingHandle,
1647 Controller,
1648 EFI_OPEN_PROTOCOL_BY_DRIVER
1651 if (EFI_ERROR (Status)) {
1652 return Status;
1655 PciAttributesSaved = FALSE;
1657 // Save original PCI attributes
1659 Status = PciIo->Attributes (
1660 PciIo,
1661 EfiPciIoAttributeOperationGet,
1663 &OriginalPciAttributes
1666 if (EFI_ERROR (Status)) {
1667 goto CLOSE_PCIIO;
1669 PciAttributesSaved = TRUE;
1672 // Robustnesss improvement such as for UoL
1673 // Default is not required.
1675 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1676 UhciTurnOffUsbEmulation (PciIo);
1679 Status = PciIo->Attributes (
1680 PciIo,
1681 EfiPciIoAttributeOperationSupported,
1683 &Supports
1685 if (!EFI_ERROR (Status)) {
1686 Supports &= EFI_PCI_DEVICE_ENABLE;
1687 Status = PciIo->Attributes (
1688 PciIo,
1689 EfiPciIoAttributeOperationEnable,
1690 Supports,
1691 NULL
1695 if (EFI_ERROR (Status)) {
1696 goto CLOSE_PCIIO;
1699 Uhc = UhciAllocateDev (PciIo, OriginalPciAttributes);
1701 if (Uhc == NULL) {
1702 Status = EFI_OUT_OF_RESOURCES;
1703 goto CLOSE_PCIIO;
1707 // Allocate and Init Host Controller's Frame List Entry
1709 Status = UhciInitFrameList (Uhc);
1711 if (EFI_ERROR (Status)) {
1712 Status = EFI_OUT_OF_RESOURCES;
1713 goto FREE_UHC;
1716 Status = gBS->SetTimer (
1717 Uhc->AsyncIntMonitor,
1718 TimerPeriodic,
1719 UHC_ASYNC_POLL_INTERVAL
1722 if (EFI_ERROR (Status)) {
1723 goto FREE_UHC;
1727 // Install USB2_HC_PROTOCOL
1729 Status = gBS->InstallMultipleProtocolInterfaces (
1730 &Controller,
1731 &gEfiUsb2HcProtocolGuid,
1732 &Uhc->Usb2Hc,
1733 NULL
1736 if (EFI_ERROR (Status)) {
1737 goto FREE_UHC;
1741 // Create event to stop the HC when exit boot service.
1743 Status = gBS->CreateEventEx (
1744 EVT_NOTIFY_SIGNAL,
1745 TPL_NOTIFY,
1746 UhcExitBootService,
1747 Uhc,
1748 &gEfiEventExitBootServicesGuid,
1749 &Uhc->ExitBootServiceEvent
1751 if (EFI_ERROR (Status)) {
1752 goto UNINSTALL_USBHC;
1756 // Install the component name protocol
1758 Uhc->CtrlNameTable = NULL;
1760 AddUnicodeString2 (
1761 "eng",
1762 gUhciComponentName.SupportedLanguages,
1763 &Uhc->CtrlNameTable,
1764 L"Usb Universal Host Controller",
1765 TRUE
1767 AddUnicodeString2 (
1768 "en",
1769 gUhciComponentName2.SupportedLanguages,
1770 &Uhc->CtrlNameTable,
1771 L"Usb Universal Host Controller",
1772 FALSE
1777 // Start the UHCI hardware, also set its reclamation point to 64 bytes
1779 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
1781 return EFI_SUCCESS;
1783 UNINSTALL_USBHC:
1784 gBS->UninstallMultipleProtocolInterfaces (
1785 Controller,
1786 &gEfiUsb2HcProtocolGuid,
1787 &Uhc->Usb2Hc,
1788 NULL
1791 FREE_UHC:
1792 UhciFreeDev (Uhc);
1794 CLOSE_PCIIO:
1795 if (PciAttributesSaved) {
1797 // Restore original PCI attributes
1799 PciIo->Attributes (
1800 PciIo,
1801 EfiPciIoAttributeOperationSet,
1802 OriginalPciAttributes,
1803 NULL
1807 gBS->CloseProtocol (
1808 Controller,
1809 &gEfiPciIoProtocolGuid,
1810 This->DriverBindingHandle,
1811 Controller
1814 return Status;
1819 Stop this driver on ControllerHandle. Support stoping any child handles
1820 created by this driver.
1822 @param This Protocol instance pointer.
1823 @param Controller Handle of device to stop driver on.
1824 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1825 @param ChildHandleBuffer List of handles for the children we need to stop.
1827 @return EFI_SUCCESS
1828 @return others
1831 EFI_STATUS
1832 EFIAPI
1833 UhciDriverBindingStop (
1834 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1835 IN EFI_HANDLE Controller,
1836 IN UINTN NumberOfChildren,
1837 IN EFI_HANDLE *ChildHandleBuffer
1840 EFI_USB2_HC_PROTOCOL *Usb2Hc;
1841 EFI_STATUS Status;
1843 Status = gBS->OpenProtocol (
1844 Controller,
1845 &gEfiUsb2HcProtocolGuid,
1846 (VOID **) &Usb2Hc,
1847 This->DriverBindingHandle,
1848 Controller,
1849 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1853 // Test whether the Controller handler passed in is a valid
1854 // Usb controller handle that should be supported, if not,
1855 // return the error status directly
1857 if (EFI_ERROR (Status)) {
1858 return Status;
1861 UhciCleanDevUp (Controller, Usb2Hc);
1863 gBS->CloseProtocol (
1864 Controller,
1865 &gEfiPciIoProtocolGuid,
1866 This->DriverBindingHandle,
1867 Controller
1870 return EFI_SUCCESS;