--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EhcPeim.h"\r
+\r
+//\r
+// Two arrays used to translate the EHCI port state (change)\r
+// to the UEFI protocol's port state (change).\r
+//\r
+USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
+ {PORTSC_CONN, USB_PORT_STAT_CONNECTION},\r
+ {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},\r
+ {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},\r
+ {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},\r
+ {PORTSC_RESET, USB_PORT_STAT_RESET},\r
+ {PORTSC_POWER, USB_PORT_STAT_POWER},\r
+ {PORTSC_OWNER, USB_PORT_STAT_OWNER}\r
+};\r
+\r
+USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
+ {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},\r
+ {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},\r
+ {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}\r
+};\r
+\r
+/**\r
+ Read Ehc Operation register.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset The operation register offset.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+ \r
+ ASSERT (Ehc->CapLen != 0);\r
+\r
+ Data = MmioRead32 (Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset);\r
+ \r
+ return Data;\r
+}\r
+\r
+/**\r
+ Write the data to the EHCI operation register.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset EHCI operation register offset.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+\r
+ ASSERT (Ehc->CapLen != 0);\r
+\r
+ MmioWrite32(Ehc->UsbHostControllerBaseAddress + Ehc->CapLen + Offset, Data);\r
+\r
+}\r
+\r
+/**\r
+ Set one bit of the operational register while keeping other bits.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to set.\r
+\r
+**/\r
+VOID\r
+EhcSetOpRegBit (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = EhcReadOpReg (Ehc, Offset);\r
+ Data |= Bit;\r
+ EhcWriteOpReg (Ehc, Offset, Data);\r
+}\r
+\r
+/**\r
+ Clear one bit of the operational register while keeping other bits.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to clear.\r
+\r
+**/\r
+VOID\r
+EhcClearOpRegBit (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit\r
+ )\r
+{\r
+ UINT32 Data;\r
+\r
+ Data = EhcReadOpReg (Ehc, Offset);\r
+ Data &= ~Bit;\r
+ EhcWriteOpReg (Ehc, Offset, Data);\r
+}\r
+\r
+/**\r
+ Wait the operation register's bit as specified by Bit \r
+ to become set (or clear).\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset The offset of the operational register.\r
+ @param Bit The bit mask of the register to wait for.\r
+ @param WaitToSet Wait the bit to set or clear.\r
+ @param Timeout The time to wait before abort (in millisecond).\r
+\r
+ @retval EFI_SUCCESS The bit successfully changed by host controller.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcWaitOpRegBit (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Bit,\r
+ IN BOOLEAN WaitToSet,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < Timeout / EHC_SYNC_POLL_INTERVAL + 1; Index++) {\r
+ if (EHC_REG_BIT_IS_SET (Ehc, Offset, Bit) == WaitToSet) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Read EHCI capability register.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset Capability register address.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadCapRegister (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Data;\r
+ \r
+ Data = MmioRead32(Ehc->UsbHostControllerBaseAddress + Offset);\r
+ \r
+ return Data;\r
+}\r
+\r
+/**\r
+ Set door bell and wait it to be ACKed by host controller.\r
+ This function is used to synchronize with the hardware.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout The time to wait before abort (in millisecond, ms).\r
+\r
+ @retval EFI_TIMEOUT Time out happened while waiting door bell to set.\r
+ @retval EFI_SUCCESS Synchronized with the hardware.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Data;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_IAAD);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_IAA, TRUE, Timeout);\r
+\r
+ //\r
+ // ACK the IAA bit in USBSTS register. Make sure other\r
+ // interrupt bits are not ACKed. These bits are WC (Write Clean).\r
+ //\r
+ Data = EhcReadOpReg (Ehc, EHC_USBSTS_OFFSET);\r
+ Data &= ~USBSTS_INTACK_MASK;\r
+ Data |= USBSTS_IAA;\r
+\r
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Clear all the interrutp status bits, these bits \r
+ are Write-Clean.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EhcWriteOpReg (Ehc, EHC_USBSTS_OFFSET, USBSTS_INTACK_MASK);\r
+}\r
+\r
+/**\r
+ Enable the periodic schedule then wait EHC to \r
+ actually enable it.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout The time to wait before abort (in millisecond, ms).\r
+\r
+ @retval EFI_TIMEOUT Time out happened while enabling periodic schedule.\r
+ @retval EFI_SUCCESS The periodical schedule is enabled.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcEnablePeriodSchd (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_PERIOD);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_PERIOD_ENABLED, TRUE, Timeout);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Enable asynchrounous schedule.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_SUCCESS The EHCI asynchronous schedule is enabled.\r
+ @retval Others Failed to enable the asynchronous scheudle.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcEnableAsyncSchd (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_ENABLE_ASYNC);\r
+\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_ASYNC_ENABLED, TRUE, Timeout);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check whether Ehc is halted.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval TRUE The controller is halted.\r
+ @retval FALSE The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT);\r
+}\r
+\r
+/**\r
+ Check whether system error occurred.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval TRUE System error happened.\r
+ @retval FALSE No system error.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ return EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR);\r
+}\r
+\r
+/**\r
+ Reset the host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort (in millisecond, ms).\r
+\r
+ @retval EFI_TIMEOUT The transfer failed due to time out.\r
+ @retval Others Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Host can only be reset when it is halt. If not so, halt it\r
+ //\r
+ if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {\r
+ Status = EhcHaltHC (Ehc, Timeout);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET);\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RESET, FALSE, Timeout);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Halt the host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.\r
+ @retval EFI_SUCCESS The EHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcClearOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, TRUE, Timeout);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the EHCI to run.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_SUCCESS The EHCI is running.\r
+ @retval Others Failed to set the EHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+ Status = EhcWaitOpRegBit (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT, FALSE, Timeout);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize the HC hardware. \r
+ EHCI spec lists the five things to do to initialize the hardware.\r
+ 1. Program CTRLDSSEGMENT.\r
+ 2. Set USBINTR to enable interrupts.\r
+ 3. Set periodic list base.\r
+ 4. Set USBCMD, interrupt threshold, frame list size etc.\r
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval EFI_SUCCESS The EHCI has come out of halt state.\r
+ @retval EFI_TIMEOUT Time out happened.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+ UINTN PageNumber;\r
+ \r
+ ASSERT (EhcIsHalt (Ehc));\r
+\r
+ //\r
+ // Allocate the periodic frame and associated memeory\r
+ // management facilities if not already done.\r
+ //\r
+ if (Ehc->PeriodFrame != NULL) {\r
+ EhcFreeSched (Ehc);\r
+ }\r
+ PageNumber = sizeof(PEI_URB)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+ Ehc->Urb = (PEI_URB *) ((UINTN) TempPtr);\r
+ if (Ehc->Urb == NULL) {\r
+ return Status;\r
+ }\r
+ \r
+ Status = EhcInitSched (Ehc);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // 1. Program the CTRLDSSEGMENT register with the high 32 bit addr\r
+ //\r
+ EhcWriteOpReg (Ehc, EHC_CTRLDSSEG_OFFSET, Ehc->High32bitAddr);\r
+\r
+ //\r
+ // 2. Clear USBINTR to disable all the interrupt. UEFI works by polling\r
+ //\r
+ EhcWriteOpReg (Ehc, EHC_USBINTR_OFFSET, 0);\r
+\r
+ //\r
+ // 3. Program periodic frame list, already done in EhcInitSched\r
+ // 4. Start the Host Controller\r
+ //\r
+ EhcSetOpRegBit (Ehc, EHC_USBCMD_OFFSET, USBCMD_RUN);\r
+\r
+ //\r
+ // 5. Set all ports routing to EHC\r
+ //\r
+ EhcSetOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);\r
+\r
+ //\r
+ // Wait roothub port power stable\r
+ //\r
+ MicroSecondDelay (EHC_ROOT_PORT_RECOVERY_STALL);\r
+\r
+ Status = EhcEnablePeriodSchd (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EhcEnableAsyncSchd (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param DeviceSpeed Device speed, Low speed device doesn't support \r
+ bulk transfer.\r
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of \r
+ sending or receiving.\r
+ @param Data Array of pointers to the buffers of data to transmit \r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of \r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param Translator A pointr to the transaction translator data. \r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ PEI_USB2_HC_DEV *Ehc;\r
+ PEI_URB *Urb;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Validate the parameters\r
+ //\r
+ if ((DataLength == NULL) || (*DataLength == 0) || \r
+ (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ehc =PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ EhcAckAllInterrupt (Ehc);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ //\r
+ // Create a new URB, insert it into the asynchronous\r
+ // schedule list, then poll the execution status.\r
+ //\r
+ Urb = EhcCreateUrb (\r
+ Ehc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ *DataToggle,\r
+ MaximumPacketLength,\r
+ Translator,\r
+ EHC_BULK_TRANSFER,\r
+ NULL,\r
+ Data[0],\r
+ *DataLength,\r
+ NULL,\r
+ NULL,\r
+ 1\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcLinkQhToAsync (Ehc, Urb->Qh);\r
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
+\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+ *DataToggle = Urb->DataToggle;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ EhcFreeUrb (Ehc, Urb);\r
+\r
+ON_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[out] PortNumber The pointer to the number of the root hub ports. \r
+ \r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetRootHubPortNumber (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *PortNumber\r
+ )\r
+{\r
+\r
+ PEI_USB2_HC_DEV *EhcDev;\r
+ EhcDev = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+ \r
+ if (PortNumber == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } \r
+ \r
+ *PortNumber = (UINT8)(EhcDev->HcStructParams & HCSP_NPORTS);\r
+ return EFI_SUCCESS;\r
+ \r
+}\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared \r
+ for the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcClearRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ PEI_USB2_HC_DEV *Ehc;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINT32 TotalPort;\r
+ EFI_STATUS Status;\r
+\r
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+ if (PortNumber >= TotalPort) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);\r
+ State = EhcReadOpReg (Ehc, Offset);\r
+ State &= ~PORTSC_CHANGE_MASK;\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ //\r
+ // Clear PORT_ENABLE feature means disable port.\r
+ //\r
+ State &= ~PORTSC_ENABLED;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ //\r
+ // A write of zero to this bit is ignored by the host\r
+ // controller. The host controller will unconditionally\r
+ // set this bit to a zero when:\r
+ // 1. software sets the Forct Port Resume bit to a zero from a one.\r
+ // 2. software sets the Port Reset bit to a one frome a zero.\r
+ //\r
+ State &= ~PORSTSC_RESUME;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ //\r
+ // Clear PORT_RESET means clear the reset signal.\r
+ //\r
+ State &= ~PORTSC_RESET;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortOwner:\r
+ //\r
+ // Clear port owner means this port owned by EHC\r
+ //\r
+ State &= ~PORTSC_OWNER;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortConnectChange:\r
+ //\r
+ // Clear connect status change\r
+ //\r
+ State |= PORTSC_CONN_CHANGE;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortEnableChange:\r
+ //\r
+ // Clear enable status change\r
+ //\r
+ State |= PORTSC_ENABLE_CHANGE;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortOverCurrentChange:\r
+ //\r
+ // Clear PortOverCurrent change\r
+ //\r
+ State |= PORTSC_OVERCUR_CHANGE;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ case EfiUsbPortSuspendChange:\r
+ case EfiUsbPortResetChange:\r
+ //\r
+ // Not supported or not related operation\r
+ //\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ON_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI\r
+ @param PortNumber Root hub port to set.\r
+ @param PortFeature Feature to set.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcSetRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ PEI_USB2_HC_DEV *Ehc;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINT32 TotalPort;\r
+ EFI_STATUS Status;\r
+\r
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+ if (PortNumber >= TotalPort) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
+ State = EhcReadOpReg (Ehc, Offset);\r
+\r
+ //\r
+ // Mask off the port status change bits, these bits are\r
+ // write clean bit\r
+ //\r
+ State &= ~PORTSC_CHANGE_MASK;\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ //\r
+ // Sofeware can't set this bit, Port can only be enable by\r
+ // EHCI as a part of the reset and enable\r
+ //\r
+ State |= PORTSC_ENABLED;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ State |= PORTSC_SUSPEND;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ //\r
+ // Make sure Host Controller not halt before reset it\r
+ //\r
+ if (EhcIsHalt (Ehc)) {\r
+ Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Set one to PortReset bit must also set zero to PortEnable bit\r
+ //\r
+ State |= PORTSC_RESET;\r
+ State &= ~PORTSC_ENABLED;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ //\r
+ // Not supported, ignore the operation\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+\r
+ case EfiUsbPortOwner:\r
+ State |= PORTSC_OWNER;\r
+ EhcWriteOpReg (Ehc, Offset, State);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ON_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param PortNumber The root hub port to retrieve the state from. \r
+ @param PortStatus Variable to receive the port state.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified.\r
+ by PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcGetRootHubPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ PEI_USB2_HC_DEV *Ehc;\r
+ UINT32 Offset;\r
+ UINT32 State;\r
+ UINT32 TotalPort;\r
+ UINTN Index;\r
+ UINTN MapSize;\r
+ EFI_STATUS Status;\r
+\r
+ if (PortStatus == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(This);\r
+ Status = EFI_SUCCESS;\r
+\r
+ TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);\r
+\r
+ if (PortNumber >= TotalPort) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ State = EhcReadOpReg (Ehc, Offset);\r
+\r
+ //\r
+ // Identify device speed. If in K state, it is low speed.\r
+ // If the port is enabled after reset, the device is of \r
+ // high speed. The USB bus driver should retrieve the actual\r
+ // port speed after reset. \r
+ //\r
+ if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+\r
+ } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
+ }\r
+ \r
+ //\r
+ // Convert the EHCI port/port change state to UEFI status\r
+ //\r
+ MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
+ PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
+ }\r
+ }\r
+\r
+ MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
+\r
+ for (Index = 0; Index < MapSize; Index++) {\r
+ if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
+ PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
+ }\r
+ }\r
+\r
+ON_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer \r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ @param Translator Transaction translator to be used by this device.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ PEI_USB2_HC_DEV *Ehc;\r
+ PEI_URB *Urb;\r
+ UINT8 Endpoint;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Validate parameters\r
+ //\r
+ if ((Request == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbDataIn) &&\r
+ (TransferDirection != EfiUsbDataOut) &&\r
+ (TransferDirection != EfiUsbNoData)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection == EfiUsbNoData) && \r
+ ((Data != NULL) || (*DataLength != 0))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((TransferDirection != EfiUsbNoData) && \r
+ ((Data == NULL) || (*DataLength == 0))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
+ (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+\r
+ if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
+ ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
+ ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ehc = PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS (This);\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ EhcAckAllInterrupt (Ehc);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+\r
+ //\r
+ // Create a new URB, insert it into the asynchronous\r
+ // schedule list, then poll the execution status.\r
+ //\r
+ //\r
+ // Encode the direction in address, although default control\r
+ // endpoint is bidirectional. EhcCreateUrb expects this\r
+ // combination of Ep addr and its direction.\r
+ //\r
+ Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
+ Urb = EhcCreateUrb (\r
+ Ehc,\r
+ DeviceAddress,\r
+ Endpoint,\r
+ DeviceSpeed,\r
+ 0,\r
+ MaximumPacketLength,\r
+ Translator,\r
+ EHC_CTRL_TRANSFER,\r
+ Request,\r
+ Data,\r
+ *DataLength,\r
+ NULL,\r
+ NULL,\r
+ 1\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EhcLinkQhToAsync (Ehc, Urb->Qh);\r
+ Status = EhcExecTransfer (Ehc, Urb, TimeOut);\r
+ EhcUnlinkQhFromAsync (Ehc, Urb->Qh);\r
+\r
+ //\r
+ // Get the status from URB. The result is updated in EhcCheckUrbResult\r
+ // which is called by EhcExecTransfer\r
+ //\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+\r
+ if (*TransferResult == EFI_USB_NOERROR) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ EhcAckAllInterrupt (Ehc);\r
+ EhcFreeUrb (Ehc, Urb);\r
+\r
+ON_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS PPI successfully installed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EhcPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINTN ControllerType;\r
+ UINTN BaseAddress;\r
+ UINTN MemPages;\r
+ PEI_USB2_HC_DEV *EhcDev;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbControllerPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &ChipSetUsbControllerPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Index = 0;\r
+ while (TRUE) {\r
+ Status = ChipSetUsbControllerPpi->GetUsbController (\r
+ (EFI_PEI_SERVICES **) PeiServices,\r
+ ChipSetUsbControllerPpi,\r
+ Index,\r
+ &ControllerType,\r
+ &BaseAddress\r
+ );\r
+ //\r
+ // When status is error, meant no controller is found\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ \r
+ //\r
+ // This PEIM is for UHC type controller.\r
+ //\r
+ if (ControllerType != PEI_EHCI_CONTROLLER) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ MemPages = sizeof (PEI_USB2_HC_DEV) / PAGESIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);\r
+ EhcDev = (PEI_USB2_HC_DEV *) ((UINTN) TempPtr);\r
+\r
+ EhcDev->Signature = USB2_HC_DEV_SIGNATURE;\r
+\r
+ EhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+\r
+\r
+ EhcDev->HcStructParams = EhcReadCapRegister (EhcDev, EHC_HCSPARAMS_OFFSET);\r
+ EhcDev->HcCapParams = EhcReadCapRegister (EhcDev, EHC_HCCPARAMS_OFFSET);\r
+ EhcDev->CapLen = EhcReadCapRegister (EhcDev, EHC_CAPLENGTH_OFFSET) & 0x0FF;\r
+ //\r
+ // Initialize Uhc's hardware\r
+ //\r
+ Status = InitializeUsbHC (EhcDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ EhcDev->Usb2HostControllerPpi.ControlTransfer = EhcControlTransfer;\r
+ EhcDev->Usb2HostControllerPpi.BulkTransfer = EhcBulkTransfer;\r
+ EhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = EhcGetRootHubPortNumber;\r
+ EhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = EhcGetRootHubPortStatus;\r
+ EhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = EhcSetRootHubPortFeature;\r
+ EhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = EhcClearRootHubPortFeature;\r
+\r
+ EhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ EhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
+ EhcDev->PpiDescriptor.Ppi = &EhcDev->Usb2HostControllerPpi;\r
+\r
+ Status = PeiServicesInstallPpi (&EhcDev->PpiDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ Index++;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ @param EhcDev EHCI Device.\r
+\r
+ @retval EFI_SUCCESS EHCI successfully initialized.\r
+ @retval EFI_ABORTED EHCI was failed to be initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+ IN PEI_USB2_HC_DEV *EhcDev \r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ \r
+ EhcResetHC (EhcDev, EHC_RESET_TIMEOUT);\r
+\r
+ Status = EhcInitHC (EhcDev);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_ABORTED; \r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _RECOVERY_EHC_H_\r
+#define _RECOVERY_EHC_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/Usb2HostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+\r
+typedef struct _PEI_USB2_HC_DEV PEI_USB2_HC_DEV;\r
+\r
+#define EFI_LIST_ENTRY LIST_ENTRY\r
+\r
+#include "UsbHcMem.h"\r
+#include "EhciReg.h"\r
+#include "EhciUrb.h"\r
+#include "EhciSched.h"\r
+\r
+#define EFI_USB_SPEED_FULL 0x0000\r
+#define EFI_USB_SPEED_LOW 0x0001\r
+#define EFI_USB_SPEED_HIGH 0x0002\r
+\r
+#define PAGESIZE 4096\r
+\r
+#define EHC_1_MICROSECOND 1\r
+#define EHC_1_MILLISECOND (1000 * EHC_1_MICROSECOND)\r
+#define EHC_1_SECOND (1000 * EHC_1_MILLISECOND)\r
+\r
+//\r
+// EHCI register operation timeout, set by experience\r
+//\r
+#define EHC_RESET_TIMEOUT (1 * EHC_1_SECOND)\r
+#define EHC_GENERIC_TIMEOUT (10 * EHC_1_MILLISECOND)\r
+\r
+\r
+//\r
+// Wait for roothub port power stable, refers to Spec[EHCI1.0-2.3.9]\r
+//\r
+#define EHC_ROOT_PORT_RECOVERY_STALL (20 * EHC_1_MILLISECOND)\r
+\r
+//\r
+// Sync and Async transfer polling interval, set by experience, \r
+// and the unit of Async is 100us, means 50ms as interval.\r
+//\r
+#define EHC_SYNC_POLL_INTERVAL (6 * EHC_1_MILLISECOND)\r
+\r
+#define EHC_ASYNC_POLL_INTERVAL (50 * 10000U)\r
+\r
+//\r
+//Iterate through the doule linked list. NOT delete safe\r
+//\r
+#define EFI_LIST_FOR_EACH(Entry, ListHead) \\r
+ for(Entry = (ListHead)->ForwardLink; Entry != (ListHead); Entry = Entry->ForwardLink)\r
+\r
+//\r
+//Iterate through the doule linked list. This is delete-safe.\r
+//Don't touch NextEntry\r
+//\r
+#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead) \\r
+ for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\\r
+ Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)\r
+\r
+#define EFI_LIST_CONTAINER(Entry, Type, Field) BASE_CR(Entry, Type, Field)\r
+\r
+\r
+#define EHC_LOW_32BIT(Addr64) ((UINT32)(((UINTN)(Addr64)) & 0XFFFFFFFF))\r
+#define EHC_HIGH_32BIT(Addr64) ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+#define EHC_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define EHC_REG_BIT_IS_SET(Ehc, Offset, Bit) \\r
+ (EHC_BIT_IS_SET(EhcReadOpReg ((Ehc), (Offset)), (Bit)))\r
+\r
+#define USB2_HC_DEV_SIGNATURE SIGNATURE_32 ('e', 'h', 'c', 'i')\r
+\r
+struct _PEI_USB2_HC_DEV {\r
+ UINTN Signature;\r
+ PEI_USB2_HOST_CONTROLLER_PPI Usb2HostControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor; \r
+ UINT32 UsbHostControllerBaseAddress;\r
+ PEI_URB *Urb;\r
+ USBHC_MEM_POOL *MemPool;\r
+\r
+ //\r
+ // Schedule data shared between asynchronous and periodic\r
+ // transfers:\r
+ // ShortReadStop, as its name indicates, is used to terminate\r
+ // the short read except the control transfer. EHCI follows\r
+ // the alternative next QTD point when a short read happens.\r
+ // For control transfer, even the short read happens, try the\r
+ // status stage.\r
+ //\r
+ PEI_EHC_QTD *ShortReadStop;\r
+ EFI_EVENT PollTimer;\r
+ \r
+ //\r
+ // Asynchronous(bulk and control) transfer schedule data: \r
+ // ReclaimHead is used as the head of the asynchronous transfer\r
+ // list. It acts as the reclamation header. \r
+ //\r
+ PEI_EHC_QH *ReclaimHead;\r
+ \r
+ //\r
+ // Peroidic (interrupt) transfer schedule data:\r
+ //\r
+ VOID *PeriodFrame; // Mapped as common buffer \r
+ VOID *PeriodFrameHost;\r
+ VOID *PeriodFrameMap;\r
+ \r
+ PEI_EHC_QH *PeriodOne;\r
+ EFI_LIST_ENTRY AsyncIntTransfers;\r
+\r
+ //\r
+ // EHCI configuration data\r
+ //\r
+ UINT32 HcStructParams; // Cache of HC structure parameter, EHC_HCSPARAMS_OFFSET\r
+ UINT32 HcCapParams; // Cache of HC capability parameter, HCCPARAMS\r
+ UINT32 CapLen; // Capability length\r
+ UINT32 High32bitAddr;\r
+};\r
+\r
+#define PEI_RECOVERY_USB_EHC_DEV_FROM_EHCI_THIS(a) CR (a, PEI_USB2_HC_DEV, Usb2HostControllerPpi, USB2_HC_DEV_SIGNATURE)\r
+\r
+/**\r
+ @param EhcDev EHCI Device.\r
+\r
+ @retval EFI_SUCCESS EHCI successfully initialized.\r
+ @retval EFI_ABORTED EHCI was failed to be initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+ IN PEI_USB2_HC_DEV *EhcDev \r
+ );\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Check4G Whether the host controller requires allocated memory \r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ )\r
+;\r
+ \r
+/**\r
+ Release the memory management pool.\r
+ \r
+ @param Pool The USB memory pool to free.\r
+\r
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ )\r
+;\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+;\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+;\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for EhcPeim PEIM to produce gPeiUsb2HostControllerPpiGuid \r
+# based on gPeiUsbControllerPpiGuid which is used to enable recovery function from USB Drivers.\r
+#\r
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution. The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# \r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = EhciPei\r
+ FILE_GUID = BAB4F20F-0981-4b5f-A047-6EF83BEEAB3C\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = EhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ EhcPeim.c\r
+ EhcPeim.h\r
+ EhciUrb.c\r
+ EhciSched.c\r
+ UsbHcMem.c\r
+ EhciReg.h\r
+ EhciSched.h\r
+ EhciUrb.h\r
+ UsbHcMem.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ PeiServicesLib\r
+\r
+\r
+[Ppis]\r
+ gPeiUsb2HostControllerPpiGuid # PPI ALWAYS_PRODUCED\r
+ gPeiUsbControllerPpiGuid # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_REG_H_\r
+#define _EFI_EHCI_REG_H_\r
+\r
+\r
+\r
+//\r
+// Capability register offset\r
+//\r
+#define EHC_CAPLENGTH_OFFSET 0 // Capability register length offset\r
+#define EHC_HCSPARAMS_OFFSET 0x04 // Structural Parameters 04-07h\r
+#define EHC_HCCPARAMS_OFFSET 0x08 // Capability parameters offset\r
+\r
+//\r
+// Capability register bit definition\r
+//\r
+#define HCSP_NPORTS 0x0F // Number of root hub port\r
+#define HCCP_64BIT 0x01 // 64-bit addressing capability\r
+\r
+//\r
+// Operational register offset\r
+//\r
+#define EHC_USBCMD_OFFSET 0x0 // USB command register offset\r
+#define EHC_USBSTS_OFFSET 0x04 // Statue register offset\r
+#define EHC_USBINTR_OFFSET 0x08 // USB interrutp offset\r
+#define EHC_FRINDEX_OFFSET 0x0C // Frame index offset\r
+#define EHC_CTRLDSSEG_OFFSET 0x10 // Control data structure segment offset\r
+#define EHC_FRAME_BASE_OFFSET 0x14 // Frame list base address offset\r
+#define EHC_ASYNC_HEAD_OFFSET 0x18 // Next asynchronous list address offset\r
+#define EHC_CONFIG_FLAG_OFFSET 0x40 // Configure flag register offset\r
+#define EHC_PORT_STAT_OFFSET 0x44 // Port status/control offset\r
+\r
+#define EHC_FRAME_LEN 1024\r
+\r
+//\r
+// Register bit definition\r
+//\r
+#define CONFIGFLAG_ROUTE_EHC 0x01 // Route port to EHC\r
+\r
+#define USBCMD_RUN 0x01 // Run/stop\r
+#define USBCMD_RESET 0x02 // Start the host controller reset\r
+#define USBCMD_ENABLE_PERIOD 0x10 // Enable periodic schedule\r
+#define USBCMD_ENABLE_ASYNC 0x20 // Enable asynchronous schedule\r
+#define USBCMD_IAAD 0x40 // Interrupt on async advance doorbell\r
+\r
+#define USBSTS_IAA 0x20 // Interrupt on async advance\r
+#define USBSTS_PERIOD_ENABLED 0x4000 // Periodic schedule status\r
+#define USBSTS_ASYNC_ENABLED 0x8000 // Asynchronous schedule status\r
+#define USBSTS_HALT 0x1000 // Host controller halted\r
+#define USBSTS_SYS_ERROR 0x10 // Host system error\r
+#define USBSTS_INTACK_MASK 0x003F // Mask for the interrupt ACK, the WC\r
+ // (write clean) bits in USBSTS register\r
+\r
+#define PORTSC_CONN 0x01 // Current Connect Status\r
+#define PORTSC_CONN_CHANGE 0x02 // Connect Status Change\r
+#define PORTSC_ENABLED 0x04 // Port Enable / Disable\r
+#define PORTSC_ENABLE_CHANGE 0x08 // Port Enable / Disable Change\r
+#define PORTSC_OVERCUR 0x10 // Over current Active\r
+#define PORTSC_OVERCUR_CHANGE 0x20 // Over current Change\r
+#define PORSTSC_RESUME 0x40 // Force Port Resume\r
+#define PORTSC_SUSPEND 0x80 // Port Suspend State\r
+#define PORTSC_RESET 0x100 // Port Reset\r
+#define PORTSC_LINESTATE_K 0x400 // Line Status K-state\r
+#define PORTSC_LINESTATE_J 0x800 // Line Status J-state\r
+#define PORTSC_POWER 0x1000 // Port Power\r
+#define PORTSC_OWNER 0x2000 // Port Owner\r
+#define PORTSC_CHANGE_MASK 0x2A // Mask of the port change bits,\r
+ // they are WC (write clean)\r
+//\r
+// PCI Configuration Registers\r
+//\r
+#define EHC_BAR_INDEX 0 // how many bytes away from USB_BASE to 0x10\r
+\r
+#define EHC_LINK_TERMINATED(Link) (((Link) & 0x01) != 0)\r
+\r
+#define EHC_ADDR(High, QhHw32) \\r
+ ((VOID *) (UINTN) (LShiftU64 ((High), 32) | ((QhHw32) & 0xFFFFFFF0)))\r
+\r
+#define EHCI_IS_DATAIN(EndpointAddr) EHC_BIT_IS_SET((EndpointAddr), 0x80)\r
+\r
+//\r
+// Structure to map the hardware port states to the \r
+// UEFI's port states. \r
+//\r
+typedef struct {\r
+ UINT16 HwState;\r
+ UINT16 UefiState;\r
+} USB_PORT_STATE_MAP;\r
+\r
+//\r
+// Ehci Data and Ctrl Structures\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+ UINT8 Pi;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+} USB_CLASSC;\r
+#pragma pack()\r
+\r
+\r
+/**\r
+ Read EHCI capability register.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset Capability register address.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadCapRegister (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+;\r
+\r
+/**\r
+ Read Ehc Operation register.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset The operation register offset.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT32\r
+EhcReadOpReg (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset\r
+ )\r
+;\r
+\r
+/**\r
+ Write the data to the EHCI operation register.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Offset EHCI operation register offset.\r
+ @param Data The data to write.\r
+\r
+**/\r
+VOID\r
+EhcWriteOpReg (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 Data\r
+ )\r
+;\r
+\r
+/**\r
+ Stop the legacy USB SMI support.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcClearLegacySupport (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Set door bell and wait it to be ACKed by host controller.\r
+ This function is used to synchronize with the hardware.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout The time to wait before abort (in millisecond, ms).\r
+\r
+ @retval EFI_TIMEOUT Time out happened while waiting door bell to set.\r
+ @retval EFI_SUCCESS Synchronized with the hardware.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcSetAndWaitDoorBell (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+/**\r
+ Clear all the interrutp status bits, these bits \r
+ are Write-Clean.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcAckAllInterrupt (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Check whether Ehc is halted.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval TRUE The controller is halted.\r
+ @retval FALSE The controller isn't halted.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsHalt (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Check whether system error occurred.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval TRUE System error happened.\r
+ @retval FALSE No system error.\r
+\r
+**/\r
+BOOLEAN\r
+EhcIsSysError (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Reset the host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort (in millisecond, ms).\r
+\r
+ @retval EFI_TIMEOUT The transfer failed due to time out.\r
+ @retval Others Failed to reset the host.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcResetHC (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+/**\r
+ Halt the host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_TIMEOUT Failed to halt the controller before Timeout.\r
+ @retval EFI_SUCCESS The EHCI is halt.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcHaltHC (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+/**\r
+ Set the EHCI to run\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Timeout Time to wait before abort.\r
+\r
+ @retval EFI_SUCCESS The EHCI is running.\r
+ @retval Others Failed to set the EHCI to run.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcRunHC (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT32 Timeout\r
+ )\r
+;\r
+\r
+/**\r
+ Initialize the HC hardware. \r
+ EHCI spec lists the five things to do to initialize the hardware.\r
+ 1. Program CTRLDSSEGMENT.\r
+ 2. Set USBINTR to enable interrupts.\r
+ 3. Set periodic list base.\r
+ 4. Set USBCMD, interrupt threshold, frame list size etc.\r
+ 5. Write 1 to CONFIGFLAG to route all ports to EHCI.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval EFI_SUCCESS The EHCI has come out of halt state.\r
+ @retval EFI_TIMEOUT Time out happened.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitHC (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EhcPeim.h"\r
+\r
+/**\r
+ Create helper QTD/QH for the EHCI device.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for helper QTD/QH.\r
+ @retval EFI_SUCCESS Helper QH/QTD are created.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcCreateHelpQ (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ USB_ENDPOINT Ep;\r
+ PEI_EHC_QH *Qh;\r
+ QH_HW *QhHw;\r
+ PEI_EHC_QTD *Qtd;\r
+\r
+ //\r
+ // Create an inactive Qtd to terminate the short packet read.\r
+ //\r
+ Qtd = EhcCreateQtd (Ehc, NULL, 0, QTD_PID_INPUT, 0, 64);\r
+\r
+ if (Qtd == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Qtd->QtdHw.Status = QTD_STAT_HALTED;\r
+ Ehc->ShortReadStop = Qtd;\r
+\r
+ //\r
+ // Create a QH to act as the EHC reclamation header.\r
+ // Set the header to loopback to itself.\r
+ //\r
+ Ep.DevAddr = 0;\r
+ Ep.EpAddr = 1;\r
+ Ep.Direction = EfiUsbDataIn;\r
+ Ep.DevSpeed = EFI_USB_SPEED_HIGH;\r
+ Ep.MaxPacket = 64;\r
+ Ep.HubAddr = 0;\r
+ Ep.HubPort = 0;\r
+ Ep.Toggle = 0;\r
+ Ep.Type = EHC_BULK_TRANSFER;\r
+ Ep.PollRate = 1;\r
+\r
+ Qh = EhcCreateQh (Ehc, &Ep);\r
+\r
+ if (Qh == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ QhHw = &Qh->QhHw;\r
+ QhHw->HorizonLink = QH_LINK (QhHw, EHC_TYPE_QH, FALSE);\r
+ QhHw->Status = QTD_STAT_HALTED;\r
+ QhHw->ReclaimHead = 1;\r
+ Ehc->ReclaimHead = Qh;\r
+\r
+ //\r
+ // Create a dummy QH to act as the terminator for periodical schedule\r
+ //\r
+ Ep.EpAddr = 2;\r
+ Ep.Type = EHC_INT_TRANSFER_SYNC;\r
+\r
+ Qh = EhcCreateQh (Ehc, &Ep);\r
+\r
+ if (Qh == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Qh->QhHw.Status = QTD_STAT_HALTED;\r
+ Ehc->PeriodOne = Qh;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize the schedule data structure such as frame list.\r
+ \r
+ @param Ehc The EHCI device to init schedule data for.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data.\r
+ @retval EFI_SUCCESS The schedule data is initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitSched (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ VOID *Map;\r
+ UINTN Index;\r
+ UINT32 *Desc;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // First initialize the periodical schedule data:\r
+ // 1. Allocate and map the memory for the frame list\r
+ // 2. Create the help QTD/QH\r
+ // 3. Initialize the frame entries\r
+ // 4. Set the frame list register\r
+ //\r
+ //\r
+ // The Frame List ocupies 4K bytes,\r
+ // and must be aligned on 4-Kbyte boundaries.\r
+ //\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ 1,\r
+ &PhyAddr\r
+ );\r
+\r
+ Map = NULL;\r
+ Ehc->PeriodFrameHost = (VOID *)(UINTN)PhyAddr;\r
+ Ehc->PeriodFrame = (VOID *)(UINTN)PhyAddr;\r
+ Ehc->PeriodFrameMap = Map;\r
+ Ehc->High32bitAddr = EHC_HIGH_32BIT (PhyAddr);\r
+\r
+ //\r
+ // Init memory pool management then create the helper\r
+ // QTD/QH. If failed, previously allocated resources\r
+ // will be freed by EhcFreeSched\r
+ //\r
+ Ehc->MemPool = UsbHcInitMemPool (\r
+ Ehc,\r
+ EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT),\r
+ Ehc->High32bitAddr\r
+ );\r
+\r
+ if (Ehc->MemPool == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EhcCreateHelpQ (Ehc);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Initialize the frame list entries then set the registers\r
+ //\r
+ Desc = (UINT32 *) Ehc->PeriodFrame;\r
+\r
+ for (Index = 0; Index < EHC_FRAME_LEN; Index++) {\r
+ Desc[Index] = QH_LINK (Ehc->PeriodOne, EHC_TYPE_QH, FALSE);\r
+ }\r
+\r
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, EHC_LOW_32BIT (Ehc->PeriodFrame));\r
+\r
+ //\r
+ // Second initialize the asynchronous schedule:\r
+ // Only need to set the AsynListAddr register to\r
+ // the reclamation header\r
+ //\r
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, EHC_LOW_32BIT (Ehc->ReclaimHead));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Free the schedule data. It may be partially initialized.\r
+ \r
+ @param Ehc The EHCI device. \r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EhcWriteOpReg (Ehc, EHC_FRAME_BASE_OFFSET, 0);\r
+ EhcWriteOpReg (Ehc, EHC_ASYNC_HEAD_OFFSET, 0);\r
+\r
+ if (Ehc->PeriodOne != NULL) {\r
+ UsbHcFreeMem (Ehc->MemPool, Ehc->PeriodOne, sizeof (PEI_EHC_QH));\r
+ Ehc->PeriodOne = NULL;\r
+ }\r
+\r
+ if (Ehc->ReclaimHead != NULL) {\r
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ReclaimHead, sizeof (PEI_EHC_QH));\r
+ Ehc->ReclaimHead = NULL;\r
+ }\r
+\r
+ if (Ehc->ShortReadStop != NULL) {\r
+ UsbHcFreeMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (PEI_EHC_QTD));\r
+ Ehc->ShortReadStop = NULL;\r
+ }\r
+\r
+ if (Ehc->MemPool != NULL) {\r
+ UsbHcFreeMemPool (Ehc->MemPool);\r
+ Ehc->MemPool = NULL;\r
+ }\r
+\r
+ if (Ehc->PeriodFrame != NULL) {\r
+ Ehc->PeriodFrame = NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Link the queue head to the asynchronous schedule list.\r
+ UEFI only supports one CTRL/BULK transfer at a time\r
+ due to its interfaces. This simplifies the AsynList\r
+ management: A reclamation header is always linked to\r
+ the AsyncListAddr, the only active QH is appended to it.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+{\r
+ PEI_EHC_QH *Head;\r
+\r
+ //\r
+ // Append the queue head after the reclaim header, then\r
+ // fix the hardware visiable parts (EHCI R1.0 page 72).\r
+ // ReclaimHead is always linked to the EHCI's AsynListAddr.\r
+ //\r
+ Head = Ehc->ReclaimHead;\r
+\r
+ Qh->NextQh = Head->NextQh;\r
+ Head->NextQh = Qh;\r
+\r
+ Qh->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);;\r
+ Head->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+}\r
+\r
+/**\r
+ Unlink a queue head from the asynchronous schedule list.\r
+ Need to synchronize with hardware.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+{\r
+ PEI_EHC_QH *Head;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (Ehc->ReclaimHead->NextQh == Qh);\r
+\r
+ //\r
+ // Remove the QH from reclamation head, then update the hardware\r
+ // visiable part: Only need to loopback the ReclaimHead. The Qh\r
+ // is pointing to ReclaimHead (which is staill in the list).\r
+ //\r
+ Head = Ehc->ReclaimHead;\r
+\r
+ Head->NextQh = Qh->NextQh;\r
+ Qh->NextQh = NULL;\r
+\r
+ Head->QhHw.HorizonLink = QH_LINK (Head, EHC_TYPE_QH, FALSE);\r
+\r
+ //\r
+ // Set and wait the door bell to synchronize with the hardware\r
+ //\r
+ Status = EhcSetAndWaitDoorBell (Ehc, EHC_GENERIC_TIMEOUT);\r
+ \r
+ return;\r
+}\r
+\r
+/**\r
+ Link a queue head for interrupt transfer to the periodic\r
+ schedule frame list. This code is very much the same as\r
+ that in UHCI.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+{\r
+ UINT32 *Frames;\r
+ UINTN Index;\r
+ PEI_EHC_QH *Prev;\r
+ PEI_EHC_QH *Next;\r
+\r
+ Frames = Ehc->PeriodFrame;\r
+\r
+ for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
+ //\r
+ // First QH can't be NULL because we always keep PeriodOne\r
+ // heads on the frame list\r
+ //\r
+ ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
+ Next = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+ Prev = NULL;\r
+\r
+ //\r
+ // Now, insert the queue head (Qh) into this frame:\r
+ // 1. Find a queue head with the same poll interval, just insert\r
+ // Qh after this queue head, then we are done.\r
+ //\r
+ // 2. Find the position to insert the queue head into:\r
+ // Previous head's interval is bigger than Qh's\r
+ // Next head's interval is less than Qh's\r
+ // Then, insert the Qh between then\r
+ //\r
+ while (Next->Interval > Qh->Interval) {\r
+ Prev = Next;\r
+ Next = Next->NextQh;\r
+ }\r
+\r
+ ASSERT (Next != NULL);\r
+\r
+ //\r
+ // The entry may have been linked into the frame by early insertation.\r
+ // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh\r
+ // with Qh.Interval == 8 on the frame. If so, we are done with this frame.\r
+ // It isn't necessary to compare all the QH with the same interval to\r
+ // Qh. This is because if there is other QH with the same interval, Qh\r
+ // should has been inserted after that at Frames[0] and at Frames[0] it is\r
+ // impossible for (Next == Qh)\r
+ //\r
+ if (Next == Qh) {\r
+ continue;\r
+ }\r
+\r
+ if (Next->Interval == Qh->Interval) {\r
+ //\r
+ // If there is a QH with the same interval, it locates at\r
+ // Frames[0], and we can simply insert it after this QH. We\r
+ // are all done.\r
+ //\r
+ ASSERT ((Index == 0) && (Qh->NextQh == NULL));\r
+\r
+ Prev = Next;\r
+ Next = Next->NextQh;\r
+\r
+ Qh->NextQh = Next;\r
+ Prev->NextQh = Qh;\r
+\r
+ Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink;\r
+ Prev->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+ break;\r
+ }\r
+ \r
+ //\r
+ // OK, find the right position, insert it in. If Qh's next\r
+ // link has already been set, it is in position. This is\r
+ // guarranted by 2^n polling interval.\r
+ //\r
+ if (Qh->NextQh == NULL) {\r
+ Qh->NextQh = Next;\r
+ Qh->QhHw.HorizonLink = QH_LINK (Next, EHC_TYPE_QH, FALSE);\r
+ }\r
+\r
+ if (Prev == NULL) {\r
+ Frames[Index] = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+ } else {\r
+ Prev->NextQh = Qh;\r
+ Prev->QhHw.HorizonLink = QH_LINK (Qh, EHC_TYPE_QH, FALSE);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Unlink an interrupt queue head from the periodic \r
+ schedule frame list.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+{\r
+ UINT32 *Frames;\r
+ UINTN Index;\r
+ PEI_EHC_QH *Prev;\r
+ PEI_EHC_QH *This;\r
+\r
+ Frames = Ehc->PeriodFrame;\r
+\r
+ for (Index = 0; Index < EHC_FRAME_LEN; Index += Qh->Interval) {\r
+ //\r
+ // Frame link can't be NULL because we always keep PeroidOne\r
+ // on the frame list\r
+ //\r
+ ASSERT (!EHC_LINK_TERMINATED (Frames[Index]));\r
+ This = EHC_ADDR (Ehc->High32bitAddr, Frames[Index]);\r
+ Prev = NULL;\r
+\r
+ //\r
+ // Walk through the frame's QH list to find the\r
+ // queue head to remove\r
+ //\r
+ while ((This != NULL) && (This != Qh)) {\r
+ Prev = This;\r
+ This = This->NextQh;\r
+ }\r
+ \r
+ //\r
+ // Qh may have already been unlinked from this frame\r
+ // by early action. See the comments in EhcLinkQhToPeriod.\r
+ //\r
+ if (This == NULL) {\r
+ continue;\r
+ }\r
+\r
+ if (Prev == NULL) {\r
+ //\r
+ // Qh is the first entry in the frame\r
+ //\r
+ Frames[Index] = Qh->QhHw.HorizonLink;\r
+ } else {\r
+ Prev->NextQh = Qh->NextQh;\r
+ Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Check the URB's execution result and update the URB's\r
+ result accordingly. \r
+\r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to check result.\r
+\r
+ @retval TRUE URB transfer is finialized.\r
+ @retval FALSE URB transfer is not finialized.\r
+\r
+**/\r
+BOOLEAN\r
+EhcCheckUrbResult (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb\r
+ )\r
+{\r
+ EFI_LIST_ENTRY *Entry;\r
+ PEI_EHC_QTD *Qtd;\r
+ QTD_HW *QtdHw;\r
+ UINT8 State;\r
+ BOOLEAN Finished;\r
+\r
+ ASSERT ((Ehc != NULL) && (Urb != NULL) && (Urb->Qh != NULL));\r
+\r
+ Finished = TRUE;\r
+ Urb->Completed = 0;\r
+\r
+ Urb->Result = EFI_USB_NOERROR;\r
+\r
+ if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {\r
+ Urb->Result |= EFI_USB_ERR_SYSTEM;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+ QtdHw = &Qtd->QtdHw;\r
+ State = (UINT8) QtdHw->Status;\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_HALTED)) {\r
+ //\r
+ // EHCI will halt the queue head when met some error.\r
+ // If it is halted, the result of URB is finialized.\r
+ //\r
+ if ((State & QTD_STAT_ERR_MASK) == 0) {\r
+ Urb->Result |= EFI_USB_ERR_STALL;\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BABBLE_ERR)) {\r
+ Urb->Result |= EFI_USB_ERR_BABBLE;\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_BUFF_ERR)) {\r
+ Urb->Result |= EFI_USB_ERR_BUFFER;\r
+ }\r
+\r
+ if (EHC_BIT_IS_SET (State, QTD_STAT_TRANS_ERR) && (QtdHw->ErrCnt == 0)) {\r
+ Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
+ }\r
+\r
+ Finished = TRUE;\r
+ goto ON_EXIT;\r
+ \r
+ } else if (EHC_BIT_IS_SET (State, QTD_STAT_ACTIVE)) {\r
+ //\r
+ // The QTD is still active, no need to check furthur.\r
+ //\r
+ Urb->Result |= EFI_USB_ERR_NOTEXECUTE;\r
+ \r
+ Finished = FALSE;\r
+ goto ON_EXIT;\r
+\r
+ } else {\r
+ //\r
+ // This QTD is finished OK or met short packet read. Update the\r
+ // transfer length if it isn't a setup.\r
+ //\r
+ if (QtdHw->Pid != QTD_PID_SETUP) {\r
+ Urb->Completed += Qtd->DataLen - QtdHw->TotalBytes;\r
+ }\r
+\r
+ if ((QtdHw->TotalBytes != 0) && (QtdHw->Pid == QTD_PID_INPUT)) {\r
+ //EHC_DUMP_QH ((Urb->Qh, "Short packet read", FALSE));\r
+\r
+ //\r
+ // Short packet read condition. If it isn't a setup transfer,\r
+ // no need to check furthur: the queue head will halt at the\r
+ // ShortReadStop. If it is a setup transfer, need to check the\r
+ // Status Stage of the setup transfer to get the finial result\r
+ //\r
+ if (QtdHw->AltNext == QTD_LINK (Ehc->ShortReadStop, FALSE)) {\r
+ \r
+ Finished = TRUE;\r
+ goto ON_EXIT;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ON_EXIT:\r
+ //\r
+ // Return the data toggle set by EHCI hardware, bulk and interrupt\r
+ // transfer will use this to initialize the next transaction. For\r
+ // Control transfer, it always start a new data toggle sequence for\r
+ // new transfer.\r
+ //\r
+ // NOTICE: don't move DT update before the loop, otherwise there is\r
+ // a race condition that DT is wrong.\r
+ //\r
+ Urb->DataToggle = (UINT8) Urb->Qh->QhHw.DataToggle;\r
+\r
+ return Finished;\r
+}\r
+\r
+/**\r
+ Execute the transfer by polling the URB. This is a synchronous operation.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to execute.\r
+ @param TimeOut The time to wait before abort, in millisecond.\r
+\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @retval EFI_TIMEOUT The transfer failed due to time out.\r
+ @retval EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcExecTransfer (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb,\r
+ IN UINTN TimeOut\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN Loop;\r
+ BOOLEAN Finished;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Loop = (TimeOut * EHC_1_MILLISECOND / EHC_SYNC_POLL_INTERVAL) + 1;\r
+ Finished = FALSE;\r
+\r
+ for (Index = 0; Index < Loop; Index++) {\r
+ Finished = EhcCheckUrbResult (Ehc, Urb);\r
+\r
+ if (Finished) {\r
+ break;\r
+ }\r
+\r
+ MicroSecondDelay (EHC_SYNC_POLL_INTERVAL);\r
+ }\r
+\r
+ if (!Finished) {\r
+ Status = EFI_TIMEOUT;\r
+ } else if (Urb->Result != EFI_USB_NOERROR) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Delete a single asynchronous interrupt transfer for\r
+ the device and endpoint.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param DevAddr The address of the target device.\r
+ @param EpNum The endpoint of the target.\r
+ @param DataToggle Return the next data toggle to use.\r
+\r
+ @retval EFI_NOT_FOUND No transfer for the device is found.\r
+ @retval EFI_SUCCESS An asynchronous transfer is removed.\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpNum, \r
+ OUT UINT8 *DataToggle\r
+ )\r
+{\r
+ EFI_LIST_ENTRY *Entry;\r
+ EFI_LIST_ENTRY *Next;\r
+ PEI_URB *Urb;\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+\r
+ Direction = (((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
+ EpNum &= 0x0F;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+ Urb = EFI_LIST_CONTAINER (Entry, PEI_URB, UrbList);\r
+\r
+ if ((Urb->Ep.DevAddr == DevAddr) && (Urb->Ep.EpAddr == EpNum) && \r
+ (Urb->Ep.Direction == Direction)) {\r
+ //\r
+ // Check the URB status to retrieve the next data toggle\r
+ // from the associated queue head.\r
+ //\r
+ EhcCheckUrbResult (Ehc, Urb);\r
+ *DataToggle = Urb->DataToggle;\r
+\r
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+ RemoveEntryList (&Urb->UrbList);\r
+\r
+ EhcFreeUrb (Ehc, Urb);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Remove all the asynchronous interrutp transfers.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+{\r
+ EFI_LIST_ENTRY *Entry;\r
+ EFI_LIST_ENTRY *Next;\r
+ PEI_URB *Urb;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+ Urb = EFI_LIST_CONTAINER (Entry, PEI_URB, UrbList);\r
+\r
+ EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);\r
+ RemoveEntryList (&Urb->UrbList);\r
+\r
+ EhcFreeUrb (Ehc, Urb);\r
+ }\r
+}\r
+\r
+/**\r
+ Flush data from PCI controller specific address to mapped system \r
+ memory address.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to unmap.\r
+\r
+ @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.\r
+ @retval EFI_SUCCESS Success to flush data to mapped system memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcFlushAsyncIntMap (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Urb->DataMap = NULL;\r
+ PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) Urb->Data;\r
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Update the queue head for next round of asynchronous transfer.\r
+\r
+ @param Urb The URB to update.\r
+\r
+**/\r
+VOID\r
+EhcUpdateAsyncRequest (\r
+ IN PEI_URB *Urb\r
+ )\r
+{\r
+ EFI_LIST_ENTRY *Entry;\r
+ PEI_EHC_QTD *FirstQtd;\r
+ QH_HW *QhHw;\r
+ PEI_EHC_QTD *Qtd;\r
+ QTD_HW *QtdHw;\r
+ UINTN Index;\r
+\r
+ Qtd = NULL;\r
+\r
+ if (Urb->Result == EFI_USB_NOERROR) {\r
+ FirstQtd = NULL;\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &Urb->Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+\r
+ if (FirstQtd == NULL) {\r
+ FirstQtd = Qtd;\r
+ }\r
+ \r
+ //\r
+ // Update the QTD for next round of transfer. Host control\r
+ // may change dt/Total Bytes to Transfer/C_Page/Cerr/Status/\r
+ // Current Offset. These fields need to be updated. DT isn't\r
+ // used by interrupt transfer. It uses DT in queue head.\r
+ // Current Offset is in Page[0], only need to reset Page[0]\r
+ // to initial data buffer.\r
+ //\r
+ QtdHw = &Qtd->QtdHw;\r
+ QtdHw->Status = QTD_STAT_ACTIVE;\r
+ QtdHw->ErrCnt = QTD_MAX_ERR;\r
+ QtdHw->CurPage = 0;\r
+ QtdHw->TotalBytes = (UINT32) Qtd->DataLen;\r
+ QtdHw->Page[0] = EHC_LOW_32BIT (Qtd->Data);\r
+ }\r
+ \r
+ //\r
+ // Update QH for next round of transfer. Host control only\r
+ // touch the fields in transfer overlay area. Only need to\r
+ // zero out the overlay area and set NextQtd to the first\r
+ // QTD. DateToggle bit is left untouched.\r
+ //\r
+ QhHw = &Urb->Qh->QhHw;\r
+ QhHw->CurQtd = QTD_LINK (0, TRUE);\r
+ QhHw->AltQtd = 0;\r
+\r
+ QhHw->Status = 0;\r
+ QhHw->Pid = 0;\r
+ QhHw->ErrCnt = 0;\r
+ QhHw->CurPage = 0;\r
+ QhHw->Ioc = 0;\r
+ QhHw->TotalBytes = 0;\r
+\r
+ for (Index = 0; Index < 5; Index++) {\r
+ QhHw->Page[Index] = 0;\r
+ QhHw->PageHigh[Index] = 0;\r
+ }\r
+\r
+ QhHw->NextQtd = QTD_LINK (FirstQtd, FALSE);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Remove all the asynchronous interrutp transfers.\r
+ \r
+ @param Event Interrupt event.\r
+ @param Context Pointer to PEI_USB2_HC_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EhcMoniteAsyncRequests (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ PEI_USB2_HC_DEV *Ehc;\r
+ EFI_LIST_ENTRY *Entry;\r
+ EFI_LIST_ENTRY *Next;\r
+ BOOLEAN Finished;\r
+ UINT8 *ProcBuf;\r
+ PEI_URB *Urb;\r
+ EFI_STATUS Status;\r
+ UINTN PageNumber;\r
+\r
+ Ehc = (PEI_USB2_HC_DEV *) Context;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Ehc->AsyncIntTransfers) {\r
+ Urb = EFI_LIST_CONTAINER (Entry, PEI_URB, UrbList);\r
+\r
+ //\r
+ // Check the result of URB execution. If it is still\r
+ // active, check the next one.\r
+ //\r
+ Finished = EhcCheckUrbResult (Ehc, Urb);\r
+\r
+ if (!Finished) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Flush any PCI posted write transactions from a PCI host \r
+ // bridge to system memory.\r
+ //\r
+ Status = EhcFlushAsyncIntMap (Ehc, Urb);\r
+ \r
+ //\r
+ // Allocate a buffer then copy the transferred data for user.\r
+ // If failed to allocate the buffer, update the URB for next\r
+ // round of transfer. Ignore the data of this round.\r
+ //\r
+ ProcBuf = NULL;\r
+\r
+ if (Urb->Result == EFI_USB_NOERROR) {\r
+ ASSERT (Urb->Completed <= Urb->DataLen);\r
+ PageNumber = Urb->Completed/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ (EFI_PHYSICAL_ADDRESS *)ProcBuf\r
+ );\r
+ if (ProcBuf == NULL) {\r
+ EhcUpdateAsyncRequest (Urb);\r
+ continue;\r
+ }\r
+\r
+ CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
+ }\r
+\r
+ EhcUpdateAsyncRequest (Urb);\r
+\r
+ //\r
+ // Leave error recovery to its related device driver. A\r
+ // common case of the error recovery is to re-submit the\r
+ // interrupt transfer which is linked to the head of the\r
+ // list. This function scans from head to tail. So the\r
+ // re-submitted interrupt transfer's callback function\r
+ // will not be called again in this round. Don't touch this\r
+ // URB after the callback, it may have been removed by the\r
+ // callback.\r
+ //\r
+ if (Urb->Callback != NULL) {\r
+ (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
+ }\r
+\r
+ if (ProcBuf != NULL) {\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_SCHED_H_\r
+#define _EFI_EHCI_SCHED_H_\r
+\r
+/**\r
+ Initialize the schedule data structure such as frame list.\r
+ \r
+ @param Ehc The EHCI device to init schedule data for.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to init schedule data.\r
+ @retval EFI_SUCCESS The schedule data is initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcInitSched (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Free the schedule data. It may be partially initialized.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhcFreeSched (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Link the queue head to the asynchronous schedule list.\r
+ UEFI only supports one CTRL/BULK transfer at a time\r
+ due to its interfaces. This simplifies the AsynList\r
+ management: A reclamation header is always linked to\r
+ the AsyncListAddr, the only active QH is appended to it.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToAsync (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+;\r
+\r
+/**\r
+ Unlink a queue head from the asynchronous schedule list.\r
+ Need to synchronize with hardware.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromAsync (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+;\r
+\r
+/**\r
+ Link a queue head for interrupt transfer to the periodic\r
+ schedule frame list. This code is very much the same as\r
+ that in UHCI.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to link.\r
+\r
+**/\r
+VOID\r
+EhcLinkQhToPeriod (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+;\r
+\r
+/**\r
+ Unlink an interrupt queue head from the periodic \r
+ schedule frame list.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qh The queue head to unlink.\r
+\r
+**/\r
+VOID\r
+EhcUnlinkQhFromPeriod (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_EHC_QH *Qh\r
+ )\r
+;\r
+\r
+/**\r
+ Execute the transfer by polling the URB. This is a synchronous operation.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to execute.\r
+ @param TimeOut The time to wait before abort, in millisecond.\r
+\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @retval EFI_TIMEOUT The transfer failed due to time out.\r
+ @retval EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcExecTransfer (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb,\r
+ IN UINTN TimeOut\r
+ )\r
+;\r
+\r
+/**\r
+ Delete a single asynchronous interrupt transfer for\r
+ the device and endpoint.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param DevAddr The address of the target device.\r
+ @param EpNum The endpoint of the target.\r
+ @param DataToggle Return the next data toggle to use.\r
+\r
+ @retval EFI_NOT_FOUND No transfer for the device is found.\r
+ @retval EFI_SUCCESS An asynchronous transfer is removed.\r
+\r
+**/\r
+EFI_STATUS\r
+EhciDelAsyncIntTransfer (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpNum, \r
+ OUT UINT8 *DataToggle\r
+ )\r
+;\r
+\r
+/**\r
+ Remove all the asynchronous interrutp transfers.\r
+ \r
+ @param Ehc The EHCI device.\r
+\r
+**/\r
+VOID\r
+EhciDelAllAsyncIntTransfers (\r
+ IN PEI_USB2_HC_DEV *Ehc\r
+ )\r
+;\r
+\r
+/**\r
+ Remove all the asynchronous interrutp transfers.\r
+ \r
+ @param Event Interrupt event.\r
+ @param Context Pointer to PEI_USB2_HC_DEV.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EhcMoniteAsyncRequests (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EhcPeim.h"\r
+\r
+/**\r
+ Delete a single asynchronous interrupt transfer for\r
+ the device and endpoint.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Data Current data not associated with a QTD.\r
+ @param DataLen The length of the data.\r
+ @param PktId Packet ID to use in the QTD.\r
+ @param Toggle Data toggle to use in the QTD.\r
+ @param MaxPacket Maximu packet length of the endpoint.\r
+\r
+ @retval the pointer to the created QTD or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QTD *\r
+EhcCreateQtd (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT8 *Data,\r
+ IN UINTN DataLen,\r
+ IN UINT8 PktId,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket\r
+ )\r
+{\r
+ PEI_EHC_QTD *Qtd;\r
+ QTD_HW *QtdHw;\r
+ UINTN Index;\r
+ UINTN Len;\r
+ UINTN ThisBufLen;\r
+\r
+ ASSERT (Ehc != NULL);\r
+\r
+ Qtd = UsbHcAllocateMem (Ehc, Ehc->MemPool, sizeof (PEI_EHC_QTD));\r
+\r
+ if (Qtd == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Qtd->Signature = EHC_QTD_SIG;\r
+ Qtd->Data = Data;\r
+ Qtd->DataLen = 0;\r
+\r
+ InitializeListHead (&Qtd->QtdList);\r
+\r
+ QtdHw = &Qtd->QtdHw;\r
+ QtdHw->NextQtd = QTD_LINK (NULL, TRUE);\r
+ QtdHw->AltNext = QTD_LINK (NULL, TRUE);\r
+ QtdHw->Status = QTD_STAT_ACTIVE;\r
+ QtdHw->Pid = PktId;\r
+ QtdHw->ErrCnt = QTD_MAX_ERR;\r
+ QtdHw->Ioc = 0;\r
+ QtdHw->TotalBytes = 0;\r
+ QtdHw->DataToggle = Toggle;\r
+\r
+ //\r
+ // Fill in the buffer points\r
+ //\r
+ if (Data != NULL) {\r
+ Len = 0;\r
+\r
+ for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {\r
+ //\r
+ // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to\r
+ // compute the offset and clear Reserved fields. This is already\r
+ // done in the data point.\r
+ //\r
+ QtdHw->Page[Index] = EHC_LOW_32BIT (Data);\r
+ QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (Data);\r
+\r
+ ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (Data) & QTD_BUF_MASK);\r
+\r
+ if (Len + ThisBufLen >= DataLen) {\r
+ Len = DataLen;\r
+ break;\r
+ }\r
+\r
+ Len += ThisBufLen;\r
+ Data += ThisBufLen;\r
+ }\r
+ \r
+ //\r
+ // Need to fix the last pointer if the Qtd can't hold all the\r
+ // user's data to make sure that the length is in the unit of\r
+ // max packets. If it can hold all the data, there is no such\r
+ // need.\r
+ //\r
+ if (Len < DataLen) {\r
+ Len = Len - Len % MaxPacket;\r
+ }\r
+\r
+ QtdHw->TotalBytes = (UINT32) Len;\r
+ Qtd->DataLen = Len;\r
+ }\r
+\r
+ return Qtd;\r
+}\r
+\r
+/**\r
+ Initialize the queue head for interrupt transfer,\r
+ that is, initialize the following three fields:\r
+ 1. SplitXState in the Status field.\r
+ 2. Microframe S-mask.\r
+ 3. Microframe C-mask.\r
+ \r
+ @param Ep The queue head's related endpoint.\r
+ @param QhHw The queue head to initialize.\r
+\r
+**/\r
+VOID\r
+EhcInitIntQh (\r
+ IN USB_ENDPOINT *Ep,\r
+ IN QH_HW *QhHw\r
+ )\r
+{\r
+ //\r
+ // Because UEFI interface can't utilitize an endpoint with\r
+ // poll rate faster than 1ms, only need to set one bit in\r
+ // the queue head. simple. But it may be changed later. If\r
+ // sub-1ms interrupt is supported, need to update the S-Mask\r
+ // here\r
+ //\r
+ if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {\r
+ QhHw->SMask = QH_MICROFRAME_0;\r
+ return ;\r
+ }\r
+ \r
+ //\r
+ // For low/full speed device, the transfer must go through\r
+ // the split transaction. Need to update three fields\r
+ // 1. SplitXState in the status\r
+ // 2. Microframe S-Mask\r
+ // 3. Microframe C-Mask\r
+ // UEFI USB doesn't exercise admission control. It simplely\r
+ // schedule the high speed transactions in microframe 0, and\r
+ // full/low speed transactions at microframe 1. This also\r
+ // avoid the use of FSTN.\r
+ //\r
+ QhHw->SMask = QH_MICROFRAME_1;\r
+ QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;\r
+}\r
+\r
+/**\r
+ Allocate and initialize a EHCI queue head.\r
+ \r
+ @param Ehci The EHCI device.\r
+ @param Ep The endpoint to create queue head for.\r
+\r
+ @retval the pointer to the created queue head or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QH *\r
+EhcCreateQh (\r
+ IN PEI_USB2_HC_DEV *Ehci,\r
+ IN USB_ENDPOINT *Ep\r
+ )\r
+{\r
+ PEI_EHC_QH *Qh;\r
+ QH_HW *QhHw;\r
+\r
+ Qh = UsbHcAllocateMem (Ehci, Ehci->MemPool, sizeof (PEI_EHC_QH));\r
+\r
+ if (Qh == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Qh->Signature = EHC_QH_SIG;\r
+ Qh->NextQh = NULL;\r
+ Qh->Interval = Ep->PollRate;\r
+ \r
+ InitializeListHead (&Qh->Qtds);\r
+\r
+ QhHw = &Qh->QhHw;\r
+ QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);\r
+ QhHw->DeviceAddr = Ep->DevAddr;\r
+ QhHw->Inactive = 0;\r
+ QhHw->EpNum = Ep->EpAddr;\r
+ QhHw->EpSpeed = Ep->DevSpeed;\r
+ QhHw->DtCtrl = 0;\r
+ QhHw->ReclaimHead = 0;\r
+ QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;\r
+ QhHw->CtrlEp = 0;\r
+ QhHw->NakReload = QH_NAK_RELOAD;\r
+ QhHw->HubAddr = Ep->HubAddr;\r
+ QhHw->PortNum = Ep->HubPort;\r
+ QhHw->Multiplier = 1;\r
+ QhHw->DataToggle = Ep->Toggle;\r
+\r
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
+ QhHw->Status |= QTD_STAT_DO_SS;\r
+ }\r
+\r
+ switch (Ep->Type) {\r
+ case EHC_CTRL_TRANSFER:\r
+ //\r
+ // Special initialization for the control transfer:\r
+ // 1. Control transfer initialize data toggle from each QTD\r
+ // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.\r
+ //\r
+ QhHw->DtCtrl = 1;\r
+\r
+ if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
+ QhHw->CtrlEp = 1;\r
+ }\r
+ break;\r
+\r
+ case EHC_INT_TRANSFER_ASYNC:\r
+ case EHC_INT_TRANSFER_SYNC:\r
+ //\r
+ // Special initialization for the interrupt transfer\r
+ // to set the S-Mask and C-Mask\r
+ //\r
+ QhHw->NakReload = 0;\r
+ EhcInitIntQh (Ep, QhHw);\r
+ break;\r
+\r
+ case EHC_BULK_TRANSFER:\r
+ if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {\r
+ QhHw->Status |= QTD_STAT_DO_PING;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ return Qh;\r
+}\r
+\r
+/**\r
+ Convert the poll interval from application to that\r
+ be used by EHCI interface data structure. Only need\r
+ to get the max 2^n that is less than interval. UEFI\r
+ can't support high speed endpoint with a interval less\r
+ than 8 microframe because interval is specified in\r
+ the unit of ms (millisecond).\r
+ \r
+ @param Interval The interval to convert.\r
+\r
+ @retval The converted interval.\r
+\r
+**/\r
+UINTN\r
+EhcConvertPollRate (\r
+ IN UINTN Interval\r
+ )\r
+{\r
+ UINTN BitCount;\r
+\r
+ if (Interval == 0) {\r
+ return 1;\r
+ }\r
+ \r
+ //\r
+ // Find the index (1 based) of the highest non-zero bit\r
+ //\r
+ BitCount = 0;\r
+\r
+ while (Interval != 0) {\r
+ Interval >>= 1;\r
+ BitCount++;\r
+ }\r
+\r
+ return (UINTN)1 << (BitCount - 1);\r
+}\r
+\r
+/**\r
+ Free a list of QTDs.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Qtds The list head of the QTD.\r
+\r
+**/\r
+VOID\r
+EhcFreeQtds (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN EFI_LIST_ENTRY *Qtds\r
+ )\r
+{\r
+ EFI_LIST_ENTRY *Entry;\r
+ EFI_LIST_ENTRY *Next;\r
+ PEI_EHC_QTD *Qtd;\r
+\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+\r
+ RemoveEntryList (&Qtd->QtdList);\r
+ UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (PEI_EHC_QTD));\r
+ }\r
+}\r
+\r
+/**\r
+ Free an allocated URB. It is possible for it to be partially inited.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to free.\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb\r
+ )\r
+{\r
+ if (Urb->Qh != NULL) {\r
+ //\r
+ // Ensure that this queue head has been unlinked from the\r
+ // schedule data structures. Free all the associated QTDs\r
+ //\r
+ EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r
+ UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (PEI_EHC_QH));\r
+ }\r
+}\r
+\r
+/**\r
+ Create a list of QTDs for the URB.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to create QTDs for.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.\r
+ @retval EFI_SUCCESS The QTDs are allocated for the URB.\r
+\r
+**/\r
+EFI_STATUS\r
+EhcCreateQtds (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb\r
+ )\r
+{\r
+ USB_ENDPOINT *Ep;\r
+ PEI_EHC_QH *Qh;\r
+ PEI_EHC_QTD *Qtd;\r
+ PEI_EHC_QTD *StatusQtd;\r
+ PEI_EHC_QTD *NextQtd;\r
+ EFI_LIST_ENTRY *Entry;\r
+ UINT32 AlterNext;\r
+ UINT8 Toggle;\r
+ UINTN Len;\r
+ UINT8 Pid;\r
+\r
+ ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r
+\r
+ //\r
+ // EHCI follows the alternet next QTD pointer if it meets\r
+ // a short read and the AlterNext pointer is valid. UEFI\r
+ // EHCI driver should terminate the transfer except the\r
+ // control transfer.\r
+ //\r
+ Toggle = 0;\r
+ Qh = Urb->Qh;\r
+ Ep = &Urb->Ep;\r
+ StatusQtd = NULL;\r
+ AlterNext = QTD_LINK (NULL, TRUE);\r
+\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);\r
+ }\r
+ \r
+ //\r
+ // Build the Setup and status packets for control transfer\r
+ //\r
+ if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
+\r
+ if (Qtd == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
+\r
+ //\r
+ // Create the status packet now. Set the AlterNext to it. So, when\r
+ // EHCI meets a short control read, it can resume at the status stage.\r
+ // Use the opposite direction of the data stage, or IN if there is\r
+ // no data stage.\r
+ //\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ Pid = QTD_PID_OUTPUT;\r
+ } else {\r
+ Pid = QTD_PID_INPUT;\r
+ }\r
+\r
+ StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);\r
+\r
+ if (StatusQtd == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ AlterNext = QTD_LINK (StatusQtd, FALSE);\r
+ }\r
+\r
+ Toggle = 1;\r
+ }\r
+\r
+ //\r
+ // Build the data packets for all the transfers\r
+ //\r
+ if (Ep->Direction == EfiUsbDataIn) {\r
+ Pid = QTD_PID_INPUT;\r
+ } else {\r
+ Pid = QTD_PID_OUTPUT;\r
+ }\r
+\r
+ Qtd = NULL;\r
+ Len = 0;\r
+\r
+ while (Len < Urb->DataLen) {\r
+ Qtd = EhcCreateQtd (\r
+ Ehc,\r
+ (UINT8 *) Urb->DataPhy + Len,\r
+ Urb->DataLen - Len,\r
+ Pid,\r
+ Toggle,\r
+ Ep->MaxPacket\r
+ );\r
+\r
+ if (Qtd == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Qtd->QtdHw.AltNext = AlterNext;\r
+ InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
+\r
+ //\r
+ // Switch the Toggle bit if odd number of packets are included in the QTD.\r
+ //\r
+ if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r
+ Toggle = (UINT8) (1 - Toggle);\r
+ }\r
+\r
+ Len += Qtd->DataLen;\r
+ }\r
+ \r
+ //\r
+ // Insert the status packet for control transfer\r
+ //\r
+ if (Ep->Type == EHC_CTRL_TRANSFER) {\r
+ InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r
+ }\r
+\r
+ //\r
+ // OK, all the QTDs needed are created. Now, fix the NextQtd point\r
+ //\r
+ EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
+ Qtd = EFI_LIST_CONTAINER (Entry, PEI_EHC_QTD, QtdList);\r
+\r
+ //\r
+ // break if it is the last entry on the list\r
+ //\r
+ if (Entry->ForwardLink == &Qh->Qtds) {\r
+ break;\r
+ }\r
+\r
+ NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, PEI_EHC_QTD, QtdList);\r
+ Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);\r
+ }\r
+\r
+ //\r
+ // Link the QTDs to the queue head\r
+ //\r
+ NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, PEI_EHC_QTD, QtdList);\r
+ Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);\r
+ return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+ EhcFreeQtds (Ehc, &Qh->Qtds);\r
+ return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+/**\r
+ Create a new URB and its associated QTD.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param DevAddr The device address.\r
+ @param EpAddr Endpoint addrress & its direction.\r
+ @param DevSpeed The device speed.\r
+ @param Toggle Initial data toggle to use.\r
+ @param MaxPacket The max packet length of the endpoint.\r
+ @param Hub The transaction translator to use.\r
+ @param Type The transaction type.\r
+ @param Request The standard USB request for control transfer.\r
+ @param Data The user data to transfer.\r
+ @param DataLen The length of data buffer.\r
+ @param Callback The function to call when data is transferred.\r
+ @param Context The context to the callback.\r
+ @param Interval The interval for interrupt transfer.\r
+\r
+ @retval the pointer to the created URB or NULL.\r
+\r
+**/\r
+PEI_URB *\r
+EhcCreateUrb (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpAddr, \r
+ IN UINT8 DevSpeed,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN VOID *Data,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context,\r
+ IN UINTN Interval\r
+ )\r
+{\r
+ USB_ENDPOINT *Ep;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ EFI_STATUS Status;\r
+ UINTN Len;\r
+ PEI_URB *Urb;\r
+ VOID *Map;\r
+\r
+ \r
+ Map = NULL;\r
+ \r
+ Urb = Ehc->Urb;\r
+ Urb->Signature = EHC_URB_SIG;\r
+ InitializeListHead (&Urb->UrbList);\r
+\r
+ Ep = &Urb->Ep;\r
+ Ep->DevAddr = DevAddr;\r
+ Ep->EpAddr = (UINT8) (EpAddr & 0x0F);\r
+ Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
+ Ep->DevSpeed = DevSpeed;\r
+ Ep->MaxPacket = MaxPacket;\r
+\r
+ Ep->HubAddr = 0;\r
+ Ep->HubPort = 0;\r
+\r
+ if (DevSpeed != EFI_USB_SPEED_HIGH) {\r
+ ASSERT (Hub != NULL);\r
+\r
+ Ep->HubAddr = Hub->TranslatorHubAddress;\r
+ Ep->HubPort = Hub->TranslatorPortNumber;\r
+ }\r
+\r
+ Ep->Toggle = Toggle;\r
+ Ep->Type = Type;\r
+ Ep->PollRate = EhcConvertPollRate (Interval);\r
+\r
+ Urb->Request = Request;\r
+ Urb->Data = Data;\r
+ Urb->DataLen = DataLen;\r
+ Urb->Callback = Callback;\r
+ Urb->Context = Context;\r
+ Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);\r
+\r
+ if (Urb->Qh == NULL) {\r
+ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Map the request and user data\r
+ //\r
+ if (Request != NULL) {\r
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) Request ;\r
+ if ( (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);\r
+ Urb->RequestMap = Map;\r
+ }\r
+\r
+ if (Data != NULL) {\r
+ Len = DataLen;\r
+ PhyAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) Data ;\r
+ if ( (Len != DataLen)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
+ Urb->DataMap = Map;\r
+ }\r
+\r
+ Status = EhcCreateQtds (Ehc, Urb);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_ERROR;\r
+ }\r
+\r
+ return Urb;\r
+\r
+ON_ERROR:\r
+ EhcFreeUrb (Ehc, Urb);\r
+ return NULL;\r
+}\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_URB_H_\r
+#define _EFI_EHCI_URB_H_\r
+\r
+typedef struct _PEI_EHC_QTD PEI_EHC_QTD;\r
+typedef struct _PEI_EHC_QH PEI_EHC_QH;\r
+typedef struct _PEI_URB PEI_URB;\r
+\r
+#define EHC_CTRL_TRANSFER 0x01\r
+#define EHC_BULK_TRANSFER 0x02\r
+#define EHC_INT_TRANSFER_SYNC 0x04\r
+#define EHC_INT_TRANSFER_ASYNC 0x08\r
+\r
+#define EHC_QTD_SIG SIGNATURE_32 ('U', 'S', 'B', 'T')\r
+#define EHC_QH_SIG SIGNATURE_32 ('U', 'S', 'B', 'H')\r
+#define EHC_URB_SIG SIGNATURE_32 ('U', 'S', 'B', 'R')\r
+\r
+//\r
+// Hardware related bit definitions\r
+//\r
+#define EHC_TYPE_ITD 0x00\r
+#define EHC_TYPE_QH 0x02\r
+#define EHC_TYPE_SITD 0x04\r
+#define EHC_TYPE_FSTN 0x06\r
+\r
+#define QH_NAK_RELOAD 3\r
+#define QH_HSHBW_MULTI 1\r
+\r
+#define QTD_MAX_ERR 3\r
+#define QTD_PID_OUTPUT 0x00\r
+#define QTD_PID_INPUT 0x01\r
+#define QTD_PID_SETUP 0x02\r
+\r
+#define QTD_STAT_DO_OUT 0\r
+#define QTD_STAT_DO_SS 0\r
+#define QTD_STAT_DO_PING 0x01\r
+#define QTD_STAT_DO_CS 0x02\r
+#define QTD_STAT_TRANS_ERR 0x08\r
+#define QTD_STAT_BABBLE_ERR 0x10\r
+#define QTD_STAT_BUFF_ERR 0x20\r
+#define QTD_STAT_HALTED 0x40\r
+#define QTD_STAT_ACTIVE 0x80\r
+#define QTD_STAT_ERR_MASK (QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR)\r
+\r
+#define QTD_MAX_BUFFER 4\r
+#define QTD_BUF_LEN 4096\r
+#define QTD_BUF_MASK 0x0FFF\r
+\r
+#define QH_MICROFRAME_0 0x01\r
+#define QH_MICROFRAME_1 0x02\r
+#define QH_MICROFRAME_2 0x04\r
+#define QH_MICROFRAME_3 0x08\r
+#define QH_MICROFRAME_4 0x10\r
+#define QH_MICROFRAME_5 0x20\r
+#define QH_MICROFRAME_6 0x40\r
+#define QH_MICROFRAME_7 0x80\r
+\r
+#define USB_ERR_SHORT_PACKET 0x200\r
+\r
+//\r
+// Fill in the hardware link point: pass in a EHC_QH/QH_HW \r
+// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK\r
+//\r
+#define QH_LINK(Addr, Type, Term) \\r
+ ((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))\r
+\r
+#define QTD_LINK(Addr, Term) QH_LINK((Addr), 0, (Term))\r
+\r
+//\r
+// The defination of EHCI hardware used data structure for \r
+// little endian architecture. The QTD and QH structures \r
+// are required to be 32 bytes aligned. Don't add members \r
+// to the head of the associated software strucuture.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+ UINT32 NextQtd;\r
+ UINT32 AltNext;\r
+ \r
+ UINT32 Status : 8;\r
+ UINT32 Pid : 2;\r
+ UINT32 ErrCnt : 2;\r
+ UINT32 CurPage : 3;\r
+ UINT32 Ioc : 1;\r
+ UINT32 TotalBytes : 15;\r
+ UINT32 DataToggle : 1;\r
+\r
+ UINT32 Page[5];\r
+ UINT32 PageHigh[5];\r
+} QTD_HW;\r
+\r
+typedef struct {\r
+ UINT32 HorizonLink; \r
+ //\r
+ // Endpoint capabilities/Characteristics DWord 1 and DWord 2\r
+ //\r
+ UINT32 DeviceAddr : 7;\r
+ UINT32 Inactive : 1;\r
+ UINT32 EpNum : 4;\r
+ UINT32 EpSpeed : 2;\r
+ UINT32 DtCtrl : 1;\r
+ UINT32 ReclaimHead : 1;\r
+ UINT32 MaxPacketLen : 11;\r
+ UINT32 CtrlEp : 1;\r
+ UINT32 NakReload : 4;\r
+\r
+ UINT32 SMask : 8;\r
+ UINT32 CMask : 8;\r
+ UINT32 HubAddr : 7;\r
+ UINT32 PortNum : 7;\r
+ UINT32 Multiplier : 2;\r
+\r
+ //\r
+ // Transaction execution overlay area\r
+ //\r
+ UINT32 CurQtd;\r
+ UINT32 NextQtd;\r
+ UINT32 AltQtd;\r
+ \r
+ UINT32 Status : 8;\r
+ UINT32 Pid : 2;\r
+ UINT32 ErrCnt : 2;\r
+ UINT32 CurPage : 3;\r
+ UINT32 Ioc : 1;\r
+ UINT32 TotalBytes : 15;\r
+ UINT32 DataToggle : 1;\r
+\r
+ UINT32 Page[5];\r
+ UINT32 PageHigh[5];\r
+} QH_HW;\r
+#pragma pack()\r
+\r
+\r
+//\r
+// Endpoint address and its capabilities\r
+//\r
+typedef struct _USB_ENDPOINT {\r
+ UINT8 DevAddr;\r
+ UINT8 EpAddr; // Endpoint address, no direction encoded in\r
+ EFI_USB_DATA_DIRECTION Direction;\r
+ UINT8 DevSpeed;\r
+ UINTN MaxPacket;\r
+ UINT8 HubAddr;\r
+ UINT8 HubPort;\r
+ UINT8 Toggle; // Data toggle, not used for control transfer\r
+ UINTN Type;\r
+ UINTN PollRate; // Polling interval used by EHCI\r
+} USB_ENDPOINT;\r
+\r
+//\r
+// Software QTD strcture, this is used to manage all the \r
+// QTD generated from a URB. Don't add fields before QtdHw.\r
+//\r
+struct _PEI_EHC_QTD {\r
+ QTD_HW QtdHw;\r
+ UINT32 Signature;\r
+ EFI_LIST_ENTRY QtdList; // The list of QTDs to one end point\r
+ UINT8 *Data; // Buffer of the original data\r
+ UINTN DataLen; // Original amount of data in this QTD\r
+};\r
+\r
+\r
+\r
+//\r
+// Software QH structure. All three different transaction types \r
+// supported by UEFI USB, that is the control/bulk/interrupt \r
+// transfers use the queue head and queue token strcuture. \r
+//\r
+// Interrupt QHs are linked to periodic frame list in the reversed\r
+// 2^N tree. Each interrupt QH is linked to the list starting at \r
+// frame 0. There is a dummy interrupt QH linked to each frame as\r
+// a sentinental whose polling interval is 1. Synchronous interrupt\r
+// transfer is linked after this dummy QH. \r
+// \r
+// For control/bulk transfer, only synchronous (in the sense of UEFI) \r
+// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr\r
+// as the reclamation header. New transfer is inserted after this QH.\r
+//\r
+struct _PEI_EHC_QH {\r
+ QH_HW QhHw;\r
+ UINT32 Signature;\r
+ PEI_EHC_QH *NextQh; // The queue head pointed to by horizontal link\r
+ EFI_LIST_ENTRY Qtds; // The list of QTDs to this queue head\r
+ UINTN Interval; \r
+};\r
+\r
+//\r
+// URB (Usb Request Block) contains information for all kinds of \r
+// usb requests.\r
+//\r
+struct _PEI_URB {\r
+ UINT32 Signature;\r
+ EFI_LIST_ENTRY UrbList;\r
+ \r
+ //\r
+ // Transaction information\r
+ //\r
+ USB_ENDPOINT Ep;\r
+ EFI_USB_DEVICE_REQUEST *Request; // Control transfer only\r
+ VOID *RequestPhy; // Address of the mapped request\r
+ VOID *RequestMap;\r
+ VOID *Data;\r
+ UINTN DataLen;\r
+ VOID *DataPhy; // Address of the mapped user data\r
+ VOID *DataMap;\r
+ EFI_ASYNC_USB_TRANSFER_CALLBACK Callback; \r
+ VOID *Context;\r
+\r
+ //\r
+ // Schedule data\r
+ //\r
+ PEI_EHC_QH *Qh;\r
+ \r
+ //\r
+ // Transaction result\r
+ //\r
+ UINT32 Result;\r
+ UINTN Completed; // completed data length\r
+ UINT8 DataToggle;\r
+};\r
+\r
+/**\r
+ Delete a single asynchronous interrupt transfer for\r
+ the device and endpoint.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Data Current data not associated with a QTD.\r
+ @param DataLen The length of the data.\r
+ @param PktId Packet ID to use in the QTD.\r
+ @param Toggle Data toggle to use in the QTD.\r
+ @param MaxPacket Maximu packet length of the endpoint.\r
+\r
+ @retval the pointer to the created QTD or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QTD *\r
+EhcCreateQtd (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT8 *Data,\r
+ IN UINTN DataLen,\r
+ IN UINT8 PktId,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket\r
+ )\r
+;\r
+\r
+/**\r
+ Allocate and initialize a EHCI queue head.\r
+ \r
+ @param Ehci The EHCI device.\r
+ @param Ep The endpoint to create queue head for.\r
+\r
+ @retval the pointer to the created queue head or NULL if failed to create one.\r
+\r
+**/\r
+PEI_EHC_QH *\r
+EhcCreateQh (\r
+ IN PEI_USB2_HC_DEV *Ehci,\r
+ IN USB_ENDPOINT *Ep\r
+ )\r
+;\r
+\r
+/**\r
+ Free an allocated URB. It is possible for it to be partially inited.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Urb The URB to free.\r
+\r
+**/\r
+VOID\r
+EhcFreeUrb (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN PEI_URB *Urb\r
+ )\r
+;\r
+\r
+/**\r
+ Create a new URB and its associated QTD.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param DevAddr The device address.\r
+ @param EpAddr Endpoint addrress & its direction.\r
+ @param DevSpeed The device speed.\r
+ @param Toggle Initial data toggle to use.\r
+ @param MaxPacket The max packet length of the endpoint.\r
+ @param Hub The transaction translator to use.\r
+ @param Type The transaction type.\r
+ @param Request The standard USB request for control transfer.\r
+ @param Data The user data to transfer.\r
+ @param DataLen The length of data buffer.\r
+ @param Callback The function to call when data is transferred.\r
+ @param Context The context to the callback.\r
+ @param Interval The interval for interrupt transfer.\r
+\r
+ @retval the pointer to the created URB or NULL.\r
+\r
+**/\r
+PEI_URB *\r
+EhcCreateUrb (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 EpAddr, \r
+ IN UINT8 DevSpeed,\r
+ IN UINT8 Toggle,\r
+ IN UINTN MaxPacket,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN VOID *Data,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context,\r
+ IN UINTN Interval\r
+ )\r
+;\r
+#endif\r
--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EhcPeim.h"\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool.\r
+\r
+ @param Ehc The EHCI device.\r
+ @param Pool The buffer pool to allocate memory for.\r
+ @param Pages How many pages to allocate.\r
+\r
+ @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+ VOID *BufHost;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
+ EFI_STATUS Status;\r
+ UINTN PageNumber;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ Mapping = NULL;\r
+ PageNumber = sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);\r
+ \r
+ //\r
+ // each bit in the bit array represents USBHC_MEM_UNIT\r
+ // bytes of memory in the memory block.\r
+ //\r
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+ \r
+ Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+ \r
+ PageNumber = (Block->BitsLen)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE); \r
+\r
+ Block->Bits = (UINT8 *)(UINTN)TempPtr;\r
+\r
+ \r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ Pages,\r
+ &TempPtr\r
+ );\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE);\r
+\r
+ BufHost = (VOID *)(UINTN)TempPtr;\r
+ MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost;\r
+ //\r
+ // Check whether the data structure used by the host controller\r
+ // should be restricted into the same 4G\r
+ //\r
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
+ return NULL;\r
+ }\r
+\r
+ Block->BufHost = BufHost;\r
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
+ Block->Mapping = Mapping;\r
+ Block->Next = NULL;\r
+\r
+ return Block;\r
+\r
+}\r
+\r
+/**\r
+ Free the memory block from the memory pool.\r
+\r
+ @param Pool The memory pool to free the block from.\r
+ @param Block The memory block to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+ Alloc some memory from the block.\r
+\r
+ @param Block The memory block to allocate memory from.\r
+ @param Units Number of memory units to allocate.\r
+\r
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+ the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocMemFromBlock (\r
+ IN USBHC_MEM_BLOCK *Block,\r
+ IN UINTN Units\r
+ )\r
+{\r
+ UINTN Byte;\r
+ UINT8 Bit;\r
+ UINTN StartByte;\r
+ UINT8 StartBit;\r
+ UINTN Available;\r
+ UINTN Count;\r
+\r
+ ASSERT ((Block != 0) && (Units != 0));\r
+\r
+ StartByte = 0;\r
+ StartBit = 0;\r
+ Available = 0;\r
+\r
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+ //\r
+ // If current bit is zero, the corresponding memory unit is\r
+ // available, otherwise we need to restart our searching.\r
+ // Available counts the consective number of zero bit.\r
+ //\r
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+ Available++;\r
+\r
+ if (Available >= Units) {\r
+ break;\r
+ }\r
+\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ } else {\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ Available = 0;\r
+ StartByte = Byte;\r
+ StartBit = Bit;\r
+ }\r
+ }\r
+\r
+ if (Available < Units) {\r
+ return NULL;\r
+ }\r
+ \r
+ //\r
+ // Mark the memory as allocated\r
+ //\r
+ Byte = StartByte;\r
+ Bit = StartBit;\r
+\r
+ for (Count = 0; Count < Units; Count++) {\r
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ return Block->Buf + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
+}\r
+\r
+/**\r
+ Insert the memory block to the pool's list of the blocks.\r
+\r
+ @param Head The head of the memory pool's block list.\r
+ @param Block The memory block to insert.\r
+\r
+**/\r
+VOID\r
+UsbHcInsertMemBlockToPool (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Head != NULL) && (Block != NULL));\r
+ Block->Next = Head->Next;\r
+ Head->Next = Block;\r
+}\r
+\r
+/**\r
+ Is the memory block empty?\r
+\r
+ @param Block The memory block to check.\r
+\r
+ @retval TRUE The memory block is empty.\r
+ @retval FALSE The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ \r
+ for (Index = 0; Index < Block->BitsLen; Index++) {\r
+ if (Block->Bits[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Unlink the memory block from the pool's list.\r
+\r
+ @param Head The block list head of the memory's pool.\r
+ @param BlockToUnlink The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+UsbHcUnlinkMemBlock (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *BlockToUnlink\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ if (Block->Next == BlockToUnlink) {\r
+ Block->Next = BlockToUnlink->Next;\r
+ BlockToUnlink->Next = NULL;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Check4G Whether the host controller requires allocated memory.\r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ )\r
+{\r
+ USBHC_MEM_POOL *Pool;\r
+ UINTN PageNumber;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+ \r
+ PageNumber = sizeof(USBHC_MEM_POOL)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE); \r
+\r
+ Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr); \r
+\r
+ Pool->Check4G = Check4G;\r
+ Pool->Which4G = Which4G;\r
+ Pool->Head = UsbHcAllocMemBlock (Ehc, Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ Pool = NULL;\r
+ }\r
+\r
+ return Pool;\r
+}\r
+\r
+/**\r
+ Release the memory management pool.\r
+ \r
+ @param Pool The USB memory pool to free.\r
+\r
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT (Pool->Head != NULL);\r
+\r
+ //\r
+ // Unlink all the memory blocks from the pool, then free them.\r
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
+ // first block.\r
+ //\r
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ UsbHcFreeMemBlock (Pool, Pool->Head);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+ \r
+ @param Ehc The EHCI device.\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN PEI_USB2_HC_DEV *Ehc,\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ USBHC_MEM_BLOCK *NewBlock;\r
+ VOID *Mem;\r
+ UINTN AllocSize;\r
+ UINTN Pages;\r
+\r
+ Mem = NULL;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ Head = Pool->Head;\r
+ ASSERT (Head != NULL);\r
+\r
+ //\r
+ // First check whether current memory blocks can satisfy the allocation.\r
+ //\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Mem != NULL) {\r
+ return Mem;\r
+ }\r
+\r
+ //\r
+ // Create a new memory block if there is not enough memory\r
+ // in the pool. If the allocation size is larger than the\r
+ // default page number, just allocate a large enough memory\r
+ // block. Otherwise allocate default pages.\r
+ //\r
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+ } else {\r
+ Pages = USBHC_MEM_DEFAULT_PAGES;\r
+ }\r
+ NewBlock = UsbHcAllocMemBlock (Ehc,Pool, Pages);\r
+\r
+ if (NewBlock == NULL) {\r
+ return NULL;\r
+ }\r
+ \r
+ //\r
+ // Add the new memory block to the pool, then allocate memory from it\r
+ //\r
+ UsbHcInsertMemBlockToPool (Head, NewBlock);\r
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ }\r
+\r
+ return Mem;\r
+}\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ UINT8 *ToFree;\r
+ UINTN AllocSize;\r
+ UINTN Byte;\r
+ UINTN Bit;\r
+ UINTN Count;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ ToFree = (UINT8 *) Mem;\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the memory to free.\r
+ //\r
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+ //\r
+ // compute the start byte and bit in the bit array\r
+ //\r
+ Byte = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) / 8;\r
+ Bit = ((ToFree - Block->Buf) / USBHC_MEM_UNIT) % 8;\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If Block == NULL, it means that the current memory isn't\r
+ // in the host controller's pool. This is critical because\r
+ // the caller has passed in a wrong memory point\r
+ //\r
+ ASSERT (Block != NULL);\r
+\r
+ //\r
+ // Release the current memory block if it is empty and not the head\r
+ //\r
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_EHCI_MEM_H_\r
+#define _EFI_EHCI_MEM_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+#define USB_HC_HIGH_32BIT(Addr64) \\r
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+\r
+struct _USBHC_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen; \r
+ UINT8 *Buf;\r
+ UINT8 *BufHost;\r
+ UINTN BufLen; // Memory size in bytes\r
+ VOID *Mapping; \r
+ USBHC_MEM_BLOCK *Next;\r
+};\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB \r
+// host controller. EHCI requires the control memory and transfer\r
+// data to be on the same 4G memory. \r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+ BOOLEAN Check4G; \r
+ UINT32 Which4G; \r
+ USBHC_MEM_BLOCK *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, must be 2^n, n>4\r
+//\r
+#define USBHC_MEM_UNIT 64\r
+\r
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)\r
+#define USBHC_MEM_DEFAULT_PAGES 16\r
+\r
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0) \r
+\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+which is used to enable recovery function from USB Drivers.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. <BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UhcPeim.h"\r
+\r
+/**\r
+ Initializes Usb Host Controller.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS PPI successfully installed.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINTN ControllerType;\r
+ UINTN BaseAddress;\r
+ UINTN MemPages;\r
+ USB_UHC_DEV *UhcDev;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbControllerPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &ChipSetUsbControllerPpi\r
+ );\r
+ //\r
+ // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Index = 0;\r
+ while (TRUE) {\r
+ Status = ChipSetUsbControllerPpi->GetUsbController (\r
+ (EFI_PEI_SERVICES **) PeiServices,\r
+ ChipSetUsbControllerPpi,\r
+ Index,\r
+ &ControllerType,\r
+ &BaseAddress\r
+ );\r
+ //\r
+ // When status is error, meant no controller is found\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // This PEIM is for UHC type controller.\r
+ //\r
+ if (ControllerType != PEI_UHCI_CONTROLLER) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ MemPages = sizeof (USB_UHC_DEV) / EFI_PAGE_SIZE + 1;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ MemPages,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);\r
+ UhcDev->Signature = USB_UHC_DEV_SIGNATURE;\r
+ UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+\r
+ //\r
+ // Init local memory management service\r
+ //\r
+ Status = InitializeMemoryManagement (UhcDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Initialize Uhc's hardware\r
+ //\r
+ Status = InitializeUsbHC (UhcDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ UhcDev->UsbHostControllerPpi.ControlTransfer = UhcControlTransfer;\r
+ UhcDev->UsbHostControllerPpi.BulkTransfer = UhcBulkTransfer;\r
+ UhcDev->UsbHostControllerPpi.GetRootHubPortNumber = UhcGetRootHubPortNumber;\r
+ UhcDev->UsbHostControllerPpi.GetRootHubPortStatus = UhcGetRootHubPortStatus;\r
+ UhcDev->UsbHostControllerPpi.SetRootHubPortFeature = UhcSetRootHubPortFeature;\r
+ UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature = UhcClearRootHubPortFeature;\r
+\r
+ UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ UhcDev->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;\r
+ UhcDev->PpiDescriptor.Ppi = &UhcDev->UsbHostControllerPpi;\r
+\r
+ Status = PeiServicesInstallPpi (&UhcDev->PpiDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ Index++;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer \r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN OUT UINTN *DataLength OPTIONAL,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_UHC_DEV *UhcDev;\r
+ UINT32 StatusReg;\r
+ UINT8 PktID;\r
+ QH_STRUCT *PtrQH;\r
+ TD_STRUCT *PtrTD;\r
+ TD_STRUCT *PtrPreTD;\r
+ TD_STRUCT *PtrSetupTD;\r
+ TD_STRUCT *PtrStatusTD;\r
+ EFI_STATUS Status;\r
+ UINT32 DataLen;\r
+ UINT8 *PtrDataSource;\r
+ UINT8 *Ptr;\r
+ UINT8 DataToggle;\r
+\r
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+\r
+ StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS;\r
+\r
+ PktID = INPUT_PACKET_ID;\r
+\r
+ if (Request == NULL || TransferResult == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // if errors exist that cause host controller halt,\r
+ // then return EFI_DEVICE_ERROR.\r
+ //\r
+\r
+ if (!IsStatusOK (UhcDev, StatusReg)) {\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+\r
+ //\r
+ // generate Setup Stage TD\r
+ //\r
+\r
+ PtrQH = UhcDev->ConfigQH;\r
+\r
+ GenSetupStageTD (\r
+ UhcDev,\r
+ DeviceAddress,\r
+ 0,\r
+ DeviceSpeed,\r
+ (UINT8 *) Request,\r
+ (UINT8) sizeof (EFI_USB_DEVICE_REQUEST),\r
+ &PtrSetupTD\r
+ );\r
+\r
+ //\r
+ // link setup TD structures to QH structure\r
+ //\r
+ LinkTDToQH (PtrQH, PtrSetupTD);\r
+\r
+ PtrPreTD = PtrSetupTD;\r
+\r
+ //\r
+ // Data Stage of Control Transfer\r
+ //\r
+ switch (TransferDirection) {\r
+\r
+ case EfiUsbDataIn:\r
+ PktID = INPUT_PACKET_ID;\r
+ PtrDataSource = Data;\r
+ DataLen = (UINT32) *DataLength;\r
+ Ptr = PtrDataSource;\r
+ break;\r
+\r
+ case EfiUsbDataOut:\r
+ PktID = OUTPUT_PACKET_ID;\r
+ PtrDataSource = Data;\r
+ DataLen = (UINT32) *DataLength;\r
+ Ptr = PtrDataSource;\r
+ break;\r
+\r
+ //\r
+ // no data stage\r
+ //\r
+ case EfiUsbNoData:\r
+ if (*DataLength != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PktID = OUTPUT_PACKET_ID;\r
+ PtrDataSource = NULL;\r
+ DataLen = 0;\r
+ Ptr = NULL;\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DataToggle = 1;\r
+\r
+ PtrTD = PtrSetupTD;\r
+ while (DataLen > 0) {\r
+ //\r
+ // create TD structures and link together\r
+ //\r
+ UINT8 PacketSize;\r
+\r
+ //\r
+ // PacketSize is the data load size of each TD carries.\r
+ //\r
+ PacketSize = (UINT8) DataLen;\r
+ if (DataLen > MaximumPacketLength) {\r
+ PacketSize = MaximumPacketLength;\r
+ }\r
+\r
+ GenDataTD (\r
+ UhcDev,\r
+ DeviceAddress,\r
+ 0,\r
+ Ptr,\r
+ PacketSize,\r
+ PktID,\r
+ DataToggle,\r
+ DeviceSpeed,\r
+ &PtrTD\r
+ );\r
+\r
+ //\r
+ // Link two TDs in vertical depth\r
+ //\r
+ LinkTDToTD (PtrPreTD, PtrTD);\r
+ PtrPreTD = PtrTD;\r
+\r
+ DataToggle ^= 1;\r
+ Ptr += PacketSize;\r
+ DataLen -= PacketSize;\r
+ }\r
+\r
+ //\r
+ // PtrPreTD points to the last TD before the Setup-Stage TD.\r
+ //\r
+ PtrPreTD = PtrTD;\r
+\r
+ //\r
+ // Status Stage of Control Transfer\r
+ //\r
+ if (PktID == OUTPUT_PACKET_ID) {\r
+ PktID = INPUT_PACKET_ID;\r
+ } else {\r
+ PktID = OUTPUT_PACKET_ID;\r
+ }\r
+ //\r
+ // create Status Stage TD structure\r
+ //\r
+ CreateStatusTD (\r
+ UhcDev,\r
+ DeviceAddress,\r
+ 0,\r
+ PktID,\r
+ DeviceSpeed,\r
+ &PtrStatusTD\r
+ );\r
+\r
+ LinkTDToTD (PtrPreTD, PtrStatusTD);\r
+\r
+ //\r
+ // Poll QH-TDs execution and get result.\r
+ // detail status is returned\r
+ //\r
+ Status = ExecuteControlTransfer (\r
+ UhcDev,\r
+ PtrSetupTD,\r
+ DataLength,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+\r
+ //\r
+ // TRUE means must search other framelistindex\r
+ //\r
+ SetQHVerticalValidorInvalid(PtrQH, FALSE);\r
+ DeleteQueuedTDs (UhcDev, PtrSetupTD);\r
+\r
+ //\r
+ // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
+ //\r
+ if (!IsStatusOK (UhcDev, StatusReg)) {\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+ *TransferResult |= EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of \r
+ sending or receiving.\r
+ @param Data Array of pointers to the buffers of data to transmit \r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of \r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_UHC_DEV *UhcDev;\r
+ UINT32 StatusReg;\r
+\r
+ UINT32 DataLen;\r
+\r
+ QH_STRUCT *PtrQH;\r
+ TD_STRUCT *PtrFirstTD;\r
+ TD_STRUCT *PtrTD;\r
+ TD_STRUCT *PtrPreTD;\r
+\r
+ UINT8 PktID;\r
+ UINT8 *PtrDataSource;\r
+ UINT8 *Ptr;\r
+\r
+ BOOLEAN IsFirstTD;\r
+\r
+ EFI_STATUS Status;\r
+\r
+ EFI_USB_DATA_DIRECTION TransferDirection;\r
+\r
+ BOOLEAN ShortPacketEnable;\r
+\r
+ UINT16 CommandContent;\r
+\r
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+\r
+ //\r
+ // Enable the maximum packet size (64bytes)\r
+ // that can be used for full speed bandwidth reclamation\r
+ // at the end of a frame.\r
+ //\r
+ CommandContent = USBReadPortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD);\r
+ if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {\r
+ CommandContent |= USBCMD_MAXP;\r
+ USBWritePortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, CommandContent);\r
+ }\r
+\r
+ StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS;\r
+\r
+ //\r
+ // these code lines are added here per complier's strict demand\r
+ //\r
+ PktID = INPUT_PACKET_ID;\r
+ PtrTD = NULL;\r
+ PtrFirstTD = NULL;\r
+ PtrPreTD = NULL;\r
+ DataLen = 0;\r
+ Ptr = NULL;\r
+\r
+ ShortPacketEnable = FALSE;\r
+\r
+ if ((DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (MaximumPacketLength != 8 && MaximumPacketLength != 16\r
+ && MaximumPacketLength != 32 && MaximumPacketLength != 64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
+ //\r
+ if (!IsStatusOK (UhcDev, StatusReg)) {\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+\r
+ if ((EndPointAddress & 0x80) != 0) {\r
+ TransferDirection = EfiUsbDataIn;\r
+ } else {\r
+ TransferDirection = EfiUsbDataOut;\r
+ }\r
+\r
+ switch (TransferDirection) {\r
+\r
+ case EfiUsbDataIn:\r
+ ShortPacketEnable = TRUE;\r
+ PktID = INPUT_PACKET_ID;\r
+ PtrDataSource = Data;\r
+ DataLen = (UINT32) *DataLength;\r
+ Ptr = PtrDataSource;\r
+ break;\r
+\r
+ case EfiUsbDataOut:\r
+ PktID = OUTPUT_PACKET_ID;\r
+ PtrDataSource = Data;\r
+ DataLen = (UINT32) *DataLength;\r
+ Ptr = PtrDataSource;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ PtrQH = UhcDev->BulkQH;\r
+\r
+ IsFirstTD = TRUE;\r
+ while (DataLen > 0) {\r
+ //\r
+ // create TD structures and link together\r
+ //\r
+ UINT8 PacketSize;\r
+\r
+ PacketSize = (UINT8) DataLen;\r
+ if (DataLen > MaximumPacketLength) {\r
+ PacketSize = MaximumPacketLength;\r
+ }\r
+\r
+ GenDataTD (\r
+ UhcDev,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ Ptr,\r
+ PacketSize,\r
+ PktID,\r
+ *DataToggle,\r
+ USB_FULL_SPEED_DEVICE,\r
+ &PtrTD\r
+ );\r
+\r
+ //\r
+ // Enable short packet detection.\r
+ // (default action is disabling short packet detection)\r
+ //\r
+ if (ShortPacketEnable) {\r
+ EnableorDisableTDShortPacket (PtrTD, TRUE);\r
+ }\r
+\r
+ if (IsFirstTD) {\r
+ PtrFirstTD = PtrTD;\r
+ PtrFirstTD->PtrNextTD = NULL;\r
+ IsFirstTD = FALSE;\r
+ } else {\r
+ //\r
+ // Link two TDs in vertical depth\r
+ //\r
+ LinkTDToTD (PtrPreTD, PtrTD);\r
+ }\r
+\r
+ PtrPreTD = PtrTD;\r
+\r
+ *DataToggle ^= 1;\r
+ Ptr += PacketSize;\r
+ DataLen -= PacketSize;\r
+ }\r
+ //\r
+ // link TD structures to QH structure\r
+ //\r
+ LinkTDToQH (PtrQH, PtrFirstTD);\r
+\r
+ //\r
+ // Execute QH-TD and get result\r
+ //\r
+ //\r
+ // detail status is put into the Result field in the pIRP\r
+ // the Data Toggle value is also re-updated to the value\r
+ // of the last successful TD\r
+ //\r
+ Status = ExecBulkTransfer (\r
+ UhcDev,\r
+ PtrFirstTD,\r
+ DataLength,\r
+ DataToggle,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+\r
+ //\r
+ // Delete Bulk transfer TD structure\r
+ //\r
+ DeleteQueuedTDs (UhcDev, PtrFirstTD);\r
+\r
+ //\r
+ // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
+ //\r
+ if (!IsStatusOK (UhcDev, StatusReg)) {\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+ *TransferResult |= EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ClearStatusReg (UhcDev, StatusReg);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[out] PortNumber The pointer to the number of the root hub ports. \r
+ \r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortNumber (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *PortNumber\r
+ )\r
+{\r
+ USB_UHC_DEV *UhcDev;\r
+ UINT32 PSAddr;\r
+ UINT16 RHPortControl;\r
+ UINT32 Index;\r
+\r
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+\r
+ if (PortNumber == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *PortNumber = 0;\r
+\r
+ for (Index = 0; Index < 2; Index++) {\r
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + Index * 2;\r
+ RHPortControl = USBReadPortW (UhcDev, PSAddr);\r
+ //\r
+ // Port Register content is valid\r
+ //\r
+ if (RHPortControl != 0xff) {\r
+ (*PortNumber)++;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber The root hub port to retrieve the state from. \r
+ @param PortStatus Variable to receive the port state.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified.\r
+ by PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ USB_UHC_DEV *UhcDev;\r
+ UINT32 PSAddr;\r
+ UINT16 RHPortStatus;\r
+ UINT8 TotalPortNumber;\r
+\r
+ if (PortStatus == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);\r
+ if (PortNumber > TotalPortNumber) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;\r
+\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ RHPortStatus = USBReadPortW (UhcDev, PSAddr);\r
+\r
+ //\r
+ // Current Connect Status\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_CCS) != 0) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+ }\r
+ //\r
+ // Port Enabled/Disabled\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_PED) != 0) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+ }\r
+ //\r
+ // Port Suspend\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_SUSP) != 0) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+ }\r
+ //\r
+ // Port Reset\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_PR) != 0) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+ }\r
+ //\r
+ // Low Speed Device Attached\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_LSDA) != 0) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+ }\r
+ //\r
+ // Fill Port Status Change bits\r
+ //\r
+ //\r
+ // Connect Status Change\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_CSC) != 0) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+ }\r
+ //\r
+ // Port Enabled/Disabled Change\r
+ //\r
+ if ((RHPortStatus & USBPORTSC_PEDC) != 0) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI\r
+ @param PortNumber Root hub port to set.\r
+ @param PortFeature Feature to set.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcSetRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_UHC_DEV *UhcDev;\r
+ UINT32 PSAddr;\r
+ UINT32 CommandRegAddr;\r
+ UINT16 RHPortControl;\r
+ UINT8 TotalPortNumber;\r
+\r
+ UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);\r
+ if (PortNumber > TotalPortNumber) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;\r
+ CommandRegAddr = UhcDev->UsbHostControllerBaseAddress + USBCMD;\r
+\r
+ RHPortControl = USBReadPortW (UhcDev, PSAddr);\r
+\r
+ switch (PortFeature) {\r
+\r
+ case EfiUsbPortSuspend:\r
+ if ((USBReadPortW (UhcDev, CommandRegAddr) & USBCMD_EGSM) == 0) {\r
+ //\r
+ // if global suspend is not active, can set port suspend\r
+ //\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl |= USBPORTSC_SUSP;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl |= USBPORTSC_PR;\r
+ //\r
+ // Set the reset bit\r
+ //\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ break;\r
+\r
+ case EfiUsbPortEnable:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl |= USBPORTSC_PED;\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ USBWritePortW (UhcDev, PSAddr, RHPortControl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared \r
+ for the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcClearRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_UHC_DEV *UhcDev;\r
+ UINT32 PSAddr;\r
+ UINT16 RHPortControl;\r
+ UINT8 TotalPortNumber;\r
+\r
+ UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);\r
+\r
+ if (PortNumber > TotalPortNumber) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
+ PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;\r
+\r
+ RHPortControl = USBReadPortW (UhcDev, PSAddr);\r
+\r
+ switch (PortFeature) {\r
+ //\r
+ // clear PORT_ENABLE feature means disable port.\r
+ //\r
+ case EfiUsbPortEnable:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl &= ~USBPORTSC_PED;\r
+ break;\r
+\r
+ //\r
+ // clear PORT_SUSPEND feature means resume the port.\r
+ // (cause a resume on the specified port if in suspend mode)\r
+ //\r
+ case EfiUsbPortSuspend:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl &= ~USBPORTSC_SUSP;\r
+ break;\r
+\r
+ //\r
+ // no operation\r
+ //\r
+ case EfiUsbPortPower:\r
+ break;\r
+\r
+ //\r
+ // clear PORT_RESET means clear the reset signal.\r
+ //\r
+ case EfiUsbPortReset:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl &= ~USBPORTSC_PR;\r
+ break;\r
+\r
+ //\r
+ // clear connect status change\r
+ //\r
+ case EfiUsbPortConnectChange:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl |= USBPORTSC_CSC;\r
+ break;\r
+\r
+ //\r
+ // clear enable/disable status change\r
+ //\r
+ case EfiUsbPortEnableChange:\r
+ RHPortControl &= 0xfff5;\r
+ RHPortControl |= USBPORTSC_PEDC;\r
+ break;\r
+\r
+ //\r
+ // root hub does not support this request\r
+ //\r
+ case EfiUsbPortSuspendChange:\r
+ break;\r
+\r
+ //\r
+ // root hub does not support this request\r
+ //\r
+ case EfiUsbPortOverCurrentChange:\r
+ break;\r
+\r
+ //\r
+ // root hub does not support this request\r
+ //\r
+ case EfiUsbPortResetChange:\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ USBWritePortW (UhcDev, PSAddr, RHPortControl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize UHCI.\r
+\r
+ @param UhcDev UHCI Device.\r
+\r
+ @retval EFI_SUCCESS UHCI successfully initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+ IN USB_UHC_DEV *UhcDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 FrameListBaseAddrReg;\r
+ UINT32 CommandReg;\r
+ UINT16 Command;\r
+\r
+ //\r
+ // Create and Initialize Frame List For the Host Controller.\r
+ //\r
+ Status = CreateFrameList (UhcDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FrameListBaseAddrReg = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD;\r
+ CommandReg = UhcDev->UsbHostControllerBaseAddress + USBCMD;\r
+\r
+ //\r
+ // Set Frame List Base Address to the specific register to inform the hardware.\r
+ //\r
+ SetFrameListBaseAddress (UhcDev, FrameListBaseAddrReg, (UINT32) (UINTN) (UhcDev->FrameListEntry));\r
+\r
+ Command = USBReadPortW (UhcDev, CommandReg);\r
+ Command |= USBCMD_GRESET;\r
+ USBWritePortW (UhcDev, CommandReg, Command);\r
+\r
+ MicroSecondDelay (50 * 1000);\r
+\r
+\r
+ Command &= ~USBCMD_GRESET;\r
+\r
+ USBWritePortW (UhcDev, CommandReg, Command);\r
+\r
+ //\r
+ //UHCI spec page120 reset recovery time\r
+ //\r
+ MicroSecondDelay (20 * 1000);\r
+\r
+ //\r
+ // Set Run/Stop bit to 1.\r
+ //\r
+ Command = USBReadPortW (UhcDev, CommandReg);\r
+ Command |= USBCMD_RS | USBCMD_MAXP;\r
+ USBWritePortW (UhcDev, CommandReg, Command);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create Frame List Structure.\r
+\r
+ @param UhcDev UHCI device.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateFrameList (\r
+ USB_UHC_DEV *UhcDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS FrameListBaseAddr;\r
+ FRAMELIST_ENTRY *FrameListPtr;\r
+ UINTN Index;\r
+\r
+ //\r
+ // The Frame List ocupies 4K bytes,\r
+ // and must be aligned on 4-Kbyte boundaries.\r
+ //\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ 1,\r
+ &FrameListBaseAddr\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ //Create Control QH and Bulk QH and link them into Framelist Entry\r
+ //\r
+ Status = CreateQH(UhcDev, &UhcDev->ConfigQH);\r
+ if (Status != EFI_SUCCESS) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ Status = CreateQH(UhcDev, &UhcDev->BulkQH);\r
+ if (Status != EFI_SUCCESS) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ //Set the corresponding QH pointer \r
+ //\r
+ SetQHHorizontalLinkPtr(UhcDev->ConfigQH, UhcDev->BulkQH);\r
+ SetQHHorizontalQHorTDSelect (UhcDev->ConfigQH, TRUE);\r
+ SetQHHorizontalValidorInvalid (UhcDev->ConfigQH, TRUE);\r
+\r
+ UhcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) FrameListBaseAddr);\r
+\r
+ FrameListPtr = UhcDev->FrameListEntry;\r
+\r
+ for (Index = 0; Index < 1024; Index++) {\r
+ FrameListPtr->FrameListPtrTerminate = 0;\r
+ FrameListPtr->FrameListPtr = (UINT32)(UINTN)UhcDev->ConfigQH >> 4;\r
+ FrameListPtr->FrameListPtrQSelect = 1;\r
+ FrameListPtr->FrameListRsvd = 0;\r
+ FrameListPtr ++;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read a 16bit width data from Uhc HC IO space register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param Port The IO space address of the register.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT16\r
+USBReadPortW (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Port\r
+ )\r
+{\r
+ return IoRead16 (Port);\r
+}\r
+\r
+/**\r
+ Write a 16bit width data into Uhc HC IO space register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param Port The IO space address of the register.\r
+ @param Data The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortW (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Port,\r
+ IN UINT16 Data\r
+ )\r
+{\r
+ IoWrite16 (Port, Data);\r
+}\r
+\r
+/**\r
+ Write a 32bit width data into Uhc HC IO space register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param Port The IO space address of the register.\r
+ @param Data The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortDW (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Port,\r
+ IN UINT32 Data\r
+ )\r
+{\r
+ IoWrite32 (Port, Data);\r
+}\r
+\r
+/**\r
+ Clear the content of UHCI's Status Register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param StatusAddr The IO space address of the register.\r
+\r
+**/\r
+VOID\r
+ClearStatusReg (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 StatusAddr\r
+ )\r
+{\r
+ //\r
+ // Clear the content of UHCI's Status Register\r
+ //\r
+ USBWritePortW (UhcDev, StatusAddr, 0x003F);\r
+}\r
+\r
+/**\r
+ Check whether the host controller operates well.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param StatusRegAddr The io address of status register.\r
+\r
+ @retval TRUE Host controller is working.\r
+ @retval FALSE Host controller is halted or system error.\r
+\r
+**/\r
+BOOLEAN\r
+IsStatusOK (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 StatusRegAddr\r
+ )\r
+{\r
+ UINT16 StatusValue;\r
+\r
+ StatusValue = USBReadPortW (UhcDev, StatusRegAddr);\r
+\r
+ if ((StatusValue & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+}\r
+\r
+/**\r
+ Get Current Frame Number.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param FrameNumberAddr The address of frame list register.\r
+\r
+ @retval The content of the frame list register.\r
+\r
+**/\r
+UINT16\r
+GetCurrentFrameNumber (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 FrameNumberAddr\r
+ )\r
+{\r
+ //\r
+ // Gets value in the USB frame number register.\r
+ //\r
+ return (UINT16) (USBReadPortW (UhcDev, FrameNumberAddr) & 0x03FF);\r
+}\r
+\r
+/**\r
+ Set Frame List Base Address.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param FrameListRegAddr The address of frame list register.\r
+ @param Addr The address of frame list table.\r
+\r
+**/\r
+VOID\r
+SetFrameListBaseAddress (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 FrameListRegAddr,\r
+ IN UINT32 Addr\r
+ )\r
+{\r
+ //\r
+ // Sets value in the USB Frame List Base Address register.\r
+ //\r
+ USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32) (Addr & 0xFFFFF000));\r
+}\r
+\r
+/**\r
+ Create QH and initialize.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateQH (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT QH_STRUCT **PtrQH\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // allocate align memory for QH_STRUCT\r
+ //\r
+ Status = AllocateTDorQHStruct (UhcDev, sizeof(QH_STRUCT), (void **)PtrQH);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // init each field of the QH_STRUCT\r
+ //\r
+ SetQHHorizontalValidorInvalid (*PtrQH, FALSE);\r
+ SetQHVerticalValidorInvalid (*PtrQH, FALSE);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set the horizontal link pointer in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param PtrNext Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalLinkPtr (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN VOID *PtrNext\r
+ )\r
+{\r
+ //\r
+ // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
+ // Only the highest 28bit of the address is valid\r
+ // (take 32bit address as an example).\r
+ //\r
+ PtrQH->QueueHead.QHHorizontalPtr = (UINT32) (UINTN) PtrNext >> 4;\r
+}\r
+\r
+/**\r
+ Get the horizontal link pointer in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+\r
+ @retval The horizontal link pointer in QH.\r
+\r
+**/\r
+VOID *\r
+GetQHHorizontalLinkPtr (\r
+ IN QH_STRUCT *PtrQH\r
+ )\r
+{\r
+ //\r
+ // Restore the 28bit address to 32bit address\r
+ // (take 32bit address as an example)\r
+ //\r
+ return (VOID *) (UINTN) ((PtrQH->QueueHead.QHHorizontalPtr) << 4);\r
+}\r
+\r
+/**\r
+ Set a QH or TD horizontally to be connected with a specific QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsQH Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalQHorTDSelect (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsQH\r
+ )\r
+{\r
+ //\r
+ // if QH is connected, the specified bit is set,\r
+ // if TD is connected, the specified bit is cleared.\r
+ //\r
+ PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;\r
+}\r
+\r
+/**\r
+ Set the horizontal validor bit in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsValid Specify the horizontal linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalValidorInvalid (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsValid\r
+ )\r
+{\r
+ //\r
+ // Valid means the horizontal link pointer is valid,\r
+ // else, it's invalid.\r
+ //\r
+ PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;\r
+}\r
+\r
+/**\r
+ Set the vertical link pointer in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param PtrNext Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalLinkPtr (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN VOID *PtrNext\r
+ )\r
+{\r
+ //\r
+ // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
+ // Only the highest 28bit of the address is valid\r
+ // (take 32bit address as an example).\r
+ //\r
+ PtrQH->QueueHead.QHVerticalPtr = (UINT32) (UINTN) PtrNext >> 4;\r
+}\r
+\r
+/**\r
+ Set a QH or TD vertically to be connected with a specific QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsQH Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalQHorTDSelect (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsQH\r
+ )\r
+{\r
+ //\r
+ // Set the specified bit if the Vertical Link Pointer pointing to a QH,\r
+ // Clear the specified bit if the Vertical Link Pointer pointing to a TD.\r
+ //\r
+ PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;\r
+}\r
+\r
+/**\r
+ Set the vertical validor bit in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsValid Specify the vertical linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalValidorInvalid (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsValid\r
+ )\r
+{\r
+ //\r
+ // If TRUE, meaning the Vertical Link Pointer field is valid,\r
+ // else, the field is invalid.\r
+ //\r
+ PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;\r
+}\r
+\r
+/**\r
+ Get the vertical validor bit in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+\r
+ @retval The vertical linker is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetQHHorizontalValidorInvalid (\r
+ IN QH_STRUCT *PtrQH\r
+ )\r
+{\r
+ //\r
+ // If TRUE, meaning the Horizontal Link Pointer field is valid,\r
+ // else, the field is invalid.\r
+ //\r
+ return (BOOLEAN) (!(PtrQH->QueueHead.QHHorizontalTerminate));\r
+}\r
+\r
+/**\r
+ Allocate TD or QH Struct.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param Size The size of allocation.\r
+ @param PtrStruct Place to store TD_STRUCT pointer.\r
+\r
+ @return EFI_SUCCESS Allocate successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocateTDorQHStruct (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Size,\r
+ OUT VOID **PtrStruct\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+ *PtrStruct = NULL;\r
+\r
+ Status = UhcAllocatePool (\r
+ UhcDev,\r
+ (UINT8 **) PtrStruct,\r
+ Size\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ZeroMem (*PtrStruct, Size);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create a TD Struct.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param PtrTD Place to store TD_STRUCT pointer.\r
+\r
+ @return EFI_SUCCESS Allocate successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT TD_STRUCT **PtrTD\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ //\r
+ // create memory for TD_STRUCT, and align the memory.\r
+ //\r
+ Status = AllocateTDorQHStruct (UhcDev, sizeof(TD_STRUCT), (void **)PtrTD);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Make TD ready.\r
+ //\r
+ SetTDLinkPtrValidorInvalid (*PtrTD, FALSE);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Generate Setup Stage TD.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param DevAddr Device address.\r
+ @param Endpoint Endpoint number.\r
+ @param DeviceSpeed Device Speed.\r
+ @param DevRequest Device reuquest.\r
+ @param RequestLen Request length.\r
+ @param PtrTD TD_STRUCT generated.\r
+\r
+ @return EFI_SUCCESS Generate setup stage TD successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenSetupStageTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 Endpoint,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 *DevRequest,\r
+ IN UINT8 RequestLen,\r
+ OUT TD_STRUCT **PtrTD\r
+ )\r
+{\r
+ TD_STRUCT *TdStruct;\r
+ EFI_STATUS Status;\r
+\r
+ Status = CreateTD (UhcDev, &TdStruct);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SetTDLinkPtr (TdStruct, NULL);\r
+\r
+ //\r
+ // Depth first fashion\r
+ //\r
+ SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);\r
+\r
+ //\r
+ // initialize as the last TD in the QH context,\r
+ // this field will be updated in the TD linkage process.\r
+ //\r
+ SetTDLinkPtrValidorInvalid (TdStruct, FALSE);\r
+\r
+ //\r
+ // Disable Short Packet Detection by default\r
+ //\r
+ EnableorDisableTDShortPacket (TdStruct, FALSE);\r
+\r
+ //\r
+ // Max error counter is 3, retry 3 times when error encountered.\r
+ //\r
+ SetTDControlErrorCounter (TdStruct, 3);\r
+\r
+ //\r
+ // set device speed attribute\r
+ // (TRUE - Slow Device; FALSE - Full Speed Device)\r
+ //\r
+ switch (DeviceSpeed) {\r
+ case USB_SLOW_SPEED_DEVICE:\r
+ SetTDLoworFullSpeedDevice (TdStruct, TRUE);\r
+ break;\r
+\r
+ case USB_FULL_SPEED_DEVICE:\r
+ SetTDLoworFullSpeedDevice (TdStruct, FALSE);\r
+ break;\r
+ }\r
+ //\r
+ // Non isochronous transfer TD\r
+ //\r
+ SetTDControlIsochronousorNot (TdStruct, FALSE);\r
+\r
+ //\r
+ // Interrupt On Complete bit be set to zero,\r
+ // Disable IOC interrupt.\r
+ //\r
+ SetorClearTDControlIOC (TdStruct, FALSE);\r
+\r
+ //\r
+ // Set TD Active bit\r
+ //\r
+ SetTDStatusActiveorInactive (TdStruct, TRUE);\r
+\r
+ SetTDTokenMaxLength (TdStruct, RequestLen);\r
+\r
+ SetTDTokenDataToggle0 (TdStruct);\r
+\r
+ SetTDTokenEndPoint (TdStruct, Endpoint);\r
+\r
+ SetTDTokenDeviceAddress (TdStruct, DevAddr);\r
+\r
+ SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);\r
+\r
+ TdStruct->PtrTDBuffer = (UINT8 *) DevRequest;\r
+ TdStruct->TDBufferLength = RequestLen;\r
+ SetTDDataBuffer (TdStruct);\r
+\r
+ *PtrTD = TdStruct;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Generate Data Stage TD.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param DevAddr Device address.\r
+ @param Endpoint Endpoint number.\r
+ @param PtrData Data buffer.\r
+ @param Len Data length.\r
+ @param PktID PacketID.\r
+ @param Toggle Data toggle value.\r
+ @param DeviceSpeed Device Speed.\r
+ @param PtrTD TD_STRUCT generated.\r
+\r
+ @return EFI_SUCCESS Generate data stage TD successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenDataTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 Endpoint,\r
+ IN UINT8 *PtrData,\r
+ IN UINT8 Len,\r
+ IN UINT8 PktID,\r
+ IN UINT8 Toggle,\r
+ IN UINT8 DeviceSpeed,\r
+ OUT TD_STRUCT **PtrTD\r
+ )\r
+{\r
+ TD_STRUCT *TdStruct;\r
+ EFI_STATUS Status;\r
+\r
+ Status = CreateTD (UhcDev, &TdStruct);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SetTDLinkPtr (TdStruct, NULL);\r
+\r
+ //\r
+ // Depth first fashion\r
+ //\r
+ SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);\r
+\r
+ //\r
+ // Link pointer pointing to TD struct\r
+ //\r
+ SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);\r
+\r
+ //\r
+ // initialize as the last TD in the QH context,\r
+ // this field will be updated in the TD linkage process.\r
+ //\r
+ SetTDLinkPtrValidorInvalid (TdStruct, FALSE);\r
+\r
+ //\r
+ // Disable short packet detect\r
+ //\r
+ EnableorDisableTDShortPacket (TdStruct, FALSE);\r
+ //\r
+ // Max error counter is 3\r
+ //\r
+ SetTDControlErrorCounter (TdStruct, 3);\r
+\r
+ //\r
+ // set device speed attribute\r
+ // (TRUE - Slow Device; FALSE - Full Speed Device)\r
+ //\r
+ switch (DeviceSpeed) {\r
+ case USB_SLOW_SPEED_DEVICE:\r
+ SetTDLoworFullSpeedDevice (TdStruct, TRUE);\r
+ break;\r
+\r
+ case USB_FULL_SPEED_DEVICE:\r
+ SetTDLoworFullSpeedDevice (TdStruct, FALSE);\r
+ break;\r
+ }\r
+ //\r
+ // Non isochronous transfer TD\r
+ //\r
+ SetTDControlIsochronousorNot (TdStruct, FALSE);\r
+\r
+ //\r
+ // Disable Interrupt On Complete\r
+ // Disable IOC interrupt.\r
+ //\r
+ SetorClearTDControlIOC (TdStruct, FALSE);\r
+\r
+ //\r
+ // Set Active bit\r
+ //\r
+ SetTDStatusActiveorInactive (TdStruct, TRUE);\r
+\r
+ SetTDTokenMaxLength (TdStruct, Len);\r
+\r
+ if (Toggle != 0) {\r
+ SetTDTokenDataToggle1 (TdStruct);\r
+ } else {\r
+ SetTDTokenDataToggle0 (TdStruct);\r
+ }\r
+\r
+ SetTDTokenEndPoint (TdStruct, Endpoint);\r
+\r
+ SetTDTokenDeviceAddress (TdStruct, DevAddr);\r
+\r
+ SetTDTokenPacketID (TdStruct, PktID);\r
+\r
+ TdStruct->PtrTDBuffer = (UINT8 *) PtrData;\r
+ TdStruct->TDBufferLength = Len;\r
+ SetTDDataBuffer (TdStruct);\r
+\r
+ *PtrTD = TdStruct;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Generate Status Stage TD.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param DevAddr Device address.\r
+ @param Endpoint Endpoint number.\r
+ @param PktID PacketID.\r
+ @param DeviceSpeed Device Speed.\r
+ @param PtrTD TD_STRUCT generated.\r
+\r
+ @return EFI_SUCCESS Generate status stage TD successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateStatusTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 Endpoint,\r
+ IN UINT8 PktID,\r
+ IN UINT8 DeviceSpeed,\r
+ OUT TD_STRUCT **PtrTD\r
+ )\r
+{\r
+ TD_STRUCT *PtrTDStruct;\r
+ EFI_STATUS Status;\r
+\r
+ Status = CreateTD (UhcDev, &PtrTDStruct);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SetTDLinkPtr (PtrTDStruct, NULL);\r
+\r
+ //\r
+ // Depth first fashion\r
+ //\r
+ SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);\r
+\r
+ //\r
+ // initialize as the last TD in the QH context,\r
+ // this field will be updated in the TD linkage process.\r
+ //\r
+ SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);\r
+\r
+ //\r
+ // Disable short packet detect\r
+ //\r
+ EnableorDisableTDShortPacket (PtrTDStruct, FALSE);\r
+\r
+ //\r
+ // Max error counter is 3\r
+ //\r
+ SetTDControlErrorCounter (PtrTDStruct, 3);\r
+\r
+ //\r
+ // set device speed attribute\r
+ // (TRUE - Slow Device; FALSE - Full Speed Device)\r
+ //\r
+ switch (DeviceSpeed) {\r
+ case USB_SLOW_SPEED_DEVICE:\r
+ SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);\r
+ break;\r
+\r
+ case USB_FULL_SPEED_DEVICE:\r
+ SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);\r
+ break;\r
+ }\r
+ //\r
+ // Non isochronous transfer TD\r
+ //\r
+ SetTDControlIsochronousorNot (PtrTDStruct, FALSE);\r
+\r
+ //\r
+ // Disable Interrupt On Complete\r
+ // Disable IOC interrupt.\r
+ //\r
+ SetorClearTDControlIOC (PtrTDStruct, FALSE);\r
+\r
+ //\r
+ // Set TD Active bit\r
+ //\r
+ SetTDStatusActiveorInactive (PtrTDStruct, TRUE);\r
+\r
+ SetTDTokenMaxLength (PtrTDStruct, 0);\r
+\r
+ SetTDTokenDataToggle1 (PtrTDStruct);\r
+\r
+ SetTDTokenEndPoint (PtrTDStruct, Endpoint);\r
+\r
+ SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);\r
+\r
+ SetTDTokenPacketID (PtrTDStruct, PktID);\r
+\r
+ PtrTDStruct->PtrTDBuffer = NULL;\r
+ PtrTDStruct->TDBufferLength = 0;\r
+ SetTDDataBuffer (PtrTDStruct);\r
+\r
+ *PtrTD = PtrTDStruct;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set the link pointer validor bit in TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsValid Specify the linker pointer is valid or not.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrValidorInvalid (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsValid\r
+ )\r
+{\r
+ //\r
+ // Valid means the link pointer is valid,\r
+ // else, it's invalid.\r
+ //\r
+ PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);\r
+}\r
+\r
+/**\r
+ Set the Link Pointer pointing to a QH or TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsQH Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrQHorTDSelect (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsQH\r
+ )\r
+{\r
+ //\r
+ // Indicate whether the Link Pointer pointing to a QH or TD\r
+ //\r
+ PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);\r
+}\r
+\r
+/**\r
+ Set the traverse is depth-first or breadth-first.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsDepth Specify the traverse is depth-first or breadth-first.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrDepthorBreadth (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsDepth\r
+ )\r
+{\r
+ //\r
+ // If TRUE, indicating the host controller should process in depth first fashion,\r
+ // else, the host controller should process in breadth first fashion\r
+ //\r
+ PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);\r
+}\r
+\r
+/**\r
+ Set TD Link Pointer in TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param PtrNext Place to the next TD_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtr (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN VOID *PtrNext\r
+ )\r
+{\r
+ //\r
+ // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,\r
+ // only the highest 28 bits are valid. (if take 32bit address as an example)\r
+ //\r
+ PtrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) PtrNext >> 4;\r
+}\r
+\r
+/**\r
+ Get TD Link Pointer.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval Get TD Link Pointer in TD.\r
+\r
+**/\r
+VOID *\r
+GetTDLinkPtr (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Get TD Link Pointer. Restore it back to 32bit\r
+ // (if take 32bit address as an example)\r
+ //\r
+ return (VOID *) (UINTN) ((PtrTDStruct->TDData.TDLinkPtr) << 4);\r
+}\r
+\r
+/**\r
+ Get the information about whether the Link Pointer field pointing to\r
+ a QH or a TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval whether the Link Pointer field pointing to a QH or a TD.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDLinkPtrQHOrTD (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Get the information about whether the Link Pointer field pointing to\r
+ // a QH or a TD.\r
+ //\r
+ return (BOOLEAN) (PtrTDStruct->TDData.TDLinkPtrQSelect);\r
+}\r
+\r
+/**\r
+ Enable/Disable short packet detection mechanism.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsEnable Enable or disable short packet detection mechanism.\r
+\r
+**/\r
+VOID\r
+EnableorDisableTDShortPacket (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsEnable\r
+ )\r
+{\r
+ //\r
+ // TRUE means enable short packet detection mechanism.\r
+ //\r
+ PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);\r
+}\r
+\r
+/**\r
+ Set the max error counter in TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param MaxErrors The number of allowable error.\r
+\r
+**/\r
+VOID\r
+SetTDControlErrorCounter (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINT8 MaxErrors\r
+ )\r
+{\r
+ //\r
+ // valid value of MaxErrors is 0,1,2,3\r
+ //\r
+ if (MaxErrors > 3) {\r
+ MaxErrors = 3;\r
+ }\r
+\r
+ PtrTDStruct->TDData.TDStatusErr = MaxErrors;\r
+}\r
+\r
+/**\r
+ Set the TD is targeting a low-speed device or not.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsLowSpeedDevice Whether The device is low-speed.\r
+\r
+**/\r
+VOID\r
+SetTDLoworFullSpeedDevice (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsLowSpeedDevice\r
+ )\r
+{\r
+ //\r
+ // TRUE means the TD is targeting at a Low-speed device\r
+ //\r
+ PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);\r
+}\r
+\r
+/**\r
+ Set the TD is isochronous transfer type or not.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsIsochronous Whether the transaction isochronous transfer type.\r
+\r
+**/\r
+VOID\r
+SetTDControlIsochronousorNot (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsIsochronous\r
+ )\r
+{\r
+ //\r
+ // TRUE means the TD belongs to Isochronous transfer type.\r
+ //\r
+ PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);\r
+}\r
+\r
+/**\r
+ Set if UCHI should issue an interrupt on completion of the frame\r
+ in which this TD is executed\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsSet Whether HC should issue an interrupt on completion.\r
+\r
+**/\r
+VOID\r
+SetorClearTDControlIOC (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsSet\r
+ )\r
+{\r
+ //\r
+ // If this bit is set, it indicates that the host controller should issue\r
+ // an interrupt on completion of the frame in which this TD is executed.\r
+ //\r
+ PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;\r
+}\r
+\r
+/**\r
+ Set if the TD is active and can be executed.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsActive Whether the TD is active and can be executed.\r
+\r
+**/\r
+VOID\r
+SetTDStatusActiveorInactive (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsActive\r
+ )\r
+{\r
+ //\r
+ // If this bit is set, it indicates that the TD is active and can be\r
+ // executed.\r
+ //\r
+ if (IsActive) {\r
+ PtrTDStruct->TDData.TDStatus |= 0x80;\r
+ } else {\r
+ PtrTDStruct->TDData.TDStatus &= 0x7F;\r
+ }\r
+}\r
+\r
+/**\r
+ Specifies the maximum number of data bytes allowed for the transfer.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param MaxLen The maximum number of data bytes allowed.\r
+\r
+ @retval The allowed maximum number of data.\r
+**/\r
+UINT16\r
+SetTDTokenMaxLength (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINT16 MaxLen\r
+ )\r
+{\r
+ //\r
+ // Specifies the maximum number of data bytes allowed for the transfer.\r
+ // the legal value extent is 0 ~ 0x500.\r
+ //\r
+ if (MaxLen > 0x500) {\r
+ MaxLen = 0x500;\r
+ }\r
+\r
+ PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;\r
+\r
+ return MaxLen;\r
+}\r
+\r
+/**\r
+ Set the data toggle bit to DATA1.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle1 (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Set the data toggle bit to DATA1\r
+ //\r
+ PtrTDStruct->TDData.TDTokenDataToggle = 1;\r
+}\r
+\r
+/**\r
+ Set the data toggle bit to DATA0.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle0 (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Set the data toggle bit to DATA0\r
+ //\r
+ PtrTDStruct->TDData.TDTokenDataToggle = 0;\r
+}\r
+\r
+/**\r
+ Set EndPoint Number the TD is targeting at.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param EndPoint The Endport number of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenEndPoint (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINTN EndPoint\r
+ )\r
+{\r
+ //\r
+ // Set EndPoint Number the TD is targeting at.\r
+ //\r
+ PtrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;\r
+}\r
+\r
+/**\r
+ Set Device Address the TD is targeting at.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param DevAddr The Device Address of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDeviceAddress (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINTN DevAddr\r
+ )\r
+{\r
+ //\r
+ // Set Device Address the TD is targeting at.\r
+ //\r
+ PtrTDStruct->TDData.TDTokenDevAddr = (UINT8) DevAddr;\r
+}\r
+\r
+/**\r
+ Set Packet Identification the TD is targeting at.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param PacketID The Packet Identification of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenPacketID (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINT8 PacketID\r
+ )\r
+{\r
+ //\r
+ // Set the Packet Identification to be used for this transaction.\r
+ //\r
+ PtrTDStruct->TDData.TDTokenPID = PacketID;\r
+}\r
+\r
+/**\r
+ Set the beginning address of the data buffer that will be used\r
+ during the transaction.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDDataBuffer (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Set the beginning address of the data buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);\r
+}\r
+\r
+/**\r
+ Detect whether the TD is active.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The TD is active or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusActive (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether the TD is active.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x80);\r
+}\r
+\r
+/**\r
+ Detect whether the TD is stalled.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The TD is stalled or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusStalled (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether the device/endpoint addressed by this TD is stalled.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x40);\r
+}\r
+\r
+/**\r
+ Detect whether Data Buffer Error is happened.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The Data Buffer Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBufferError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether Data Buffer Error is happened.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x20);\r
+}\r
+\r
+/**\r
+ Detect whether Babble Error is happened.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The Babble Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBabbleError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether Babble Error is happened.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x10);\r
+}\r
+\r
+/**\r
+ Detect whether NAK is received.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The NAK is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusNAKReceived (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether NAK is received.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x08);\r
+}\r
+\r
+/**\r
+ Detect whether CRC/Time Out Error is encountered.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The CRC/Time Out Error is encountered or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusCRCTimeOutError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether CRC/Time Out Error is encountered.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x04);\r
+}\r
+\r
+/**\r
+ Detect whether Bitstuff Error is received.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The Bitstuff Error is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBitStuffError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ UINT8 TDStatus;\r
+\r
+ //\r
+ // Detect whether Bitstuff Error is received.\r
+ //\r
+ TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);\r
+ return (BOOLEAN) (TDStatus & 0x02);\r
+}\r
+\r
+/**\r
+ Retrieve the actual number of bytes that were tansferred.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The actual number of bytes that were tansferred.\r
+\r
+**/\r
+UINT16\r
+GetTDStatusActualLength (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Retrieve the actual number of bytes that were tansferred.\r
+ // the value is encoded as n-1. so return the decoded value.\r
+ //\r
+ return (UINT16) ((PtrTDStruct->TDData.TDStatusActualLength) + 1);\r
+}\r
+\r
+/**\r
+ Retrieve the information of whether the Link Pointer field is valid or not.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The linker pointer field is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetTDLinkPtrValidorInvalid (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ )\r
+{\r
+ //\r
+ // Retrieve the information of whether the Link Pointer field\r
+ // is valid or not.\r
+ //\r
+ if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Count TD Number from PtrFirstTD.\r
+\r
+ @param PtrFirstTD Place to store TD_STRUCT pointer.\r
+\r
+ @retval The queued TDs number.\r
+\r
+**/\r
+UINTN\r
+CountTDsNumber (\r
+ IN TD_STRUCT *PtrFirstTD\r
+ )\r
+{\r
+ UINTN Number;\r
+ TD_STRUCT *Ptr;\r
+\r
+ //\r
+ // Count the queued TDs number.\r
+ //\r
+ Number = 0;\r
+ Ptr = PtrFirstTD;\r
+ while (Ptr != 0) {\r
+ Ptr = (TD_STRUCT *) Ptr->PtrNextTD;\r
+ Number++;\r
+ }\r
+\r
+ return Number;\r
+}\r
+\r
+/**\r
+ Link TD To QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param PtrTD Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToQH (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN TD_STRUCT *PtrTD\r
+ )\r
+{\r
+ if (PtrQH == NULL || PtrTD == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ // Validate QH Vertical Ptr field\r
+ //\r
+ SetQHVerticalValidorInvalid (PtrQH, TRUE);\r
+\r
+ //\r
+ // Vertical Ptr pointing to TD structure\r
+ //\r
+ SetQHVerticalQHorTDSelect (PtrQH, FALSE);\r
+\r
+ SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);\r
+\r
+ PtrQH->PtrDown = (VOID *) PtrTD;\r
+}\r
+\r
+/**\r
+ Link TD To TD.\r
+\r
+ @param PtrPreTD Place to store TD_STRUCT pointer.\r
+ @param PtrTD Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToTD (\r
+ IN TD_STRUCT *PtrPreTD,\r
+ IN TD_STRUCT *PtrTD\r
+ )\r
+{\r
+ if (PtrPreTD == NULL || PtrTD == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ // Depth first fashion\r
+ //\r
+ SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);\r
+\r
+ //\r
+ // Link pointer pointing to TD struct\r
+ //\r
+ SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);\r
+\r
+ //\r
+ // Validate the link pointer valid bit\r
+ //\r
+ SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);\r
+\r
+ SetTDLinkPtr (PtrPreTD, PtrTD);\r
+\r
+ PtrPreTD->PtrNextTD = (VOID *) PtrTD;\r
+\r
+ PtrTD->PtrNextTD = NULL;\r
+}\r
+\r
+/**\r
+ Execute Control Transfer.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param PtrTD A pointer to TD_STRUCT data.\r
+ @param ActualLen Actual transfer Length.\r
+ @param TimeOut TimeOut value.\r
+ @param TransferResult Transfer Result.\r
+\r
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @return EFI_TIMEOUT The transfer failed due to time out.\r
+ @return EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecuteControlTransfer (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN TD_STRUCT *PtrTD,\r
+ OUT UINTN *ActualLen,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ UINTN ErrTDPos;\r
+ UINTN Delay;\r
+\r
+ ErrTDPos = 0;\r
+ *TransferResult = EFI_USB_NOERROR;\r
+ *ActualLen = 0;\r
+\r
+ Delay = (TimeOut * STALL_1_MILLI_SECOND / 200) + 1;\r
+\r
+ do {\r
+\r
+ CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);\r
+\r
+ //\r
+ // TD is inactive, means the control transfer is end.\r
+ //\r
+ if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
+ break;\r
+ }\r
+ MicroSecondDelay (200);\r
+ Delay--;\r
+\r
+ } while (Delay != 0);\r
+\r
+\r
+ if (*TransferResult != EFI_USB_NOERROR) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Execute Bulk Transfer.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param PtrTD A pointer to TD_STRUCT data.\r
+ @param ActualLen Actual transfer Length.\r
+ @param DataToggle DataToggle value.\r
+ @param TimeOut TimeOut value.\r
+ @param TransferResult Transfer Result.\r
+\r
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @return EFI_TIMEOUT The transfer failed due to time out.\r
+ @return EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecBulkTransfer (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN TD_STRUCT *PtrTD,\r
+ IN OUT UINTN *ActualLen,\r
+ IN UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ UINTN ErrTDPos;\r
+ UINTN ScrollNum;\r
+ UINTN Delay;\r
+\r
+ ErrTDPos = 0;\r
+ *TransferResult = EFI_USB_NOERROR;\r
+ *ActualLen = 0;\r
+\r
+ Delay = (TimeOut * STALL_1_MILLI_SECOND / 200) + 1;\r
+\r
+ do {\r
+\r
+ CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);\r
+ //\r
+ // TD is inactive, thus meaning bulk transfer's end.\r
+ //\r
+ if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
+ break;\r
+ }\r
+ MicroSecondDelay (200);\r
+ Delay--;\r
+\r
+ } while (Delay != 0);\r
+\r
+ //\r
+ // has error\r
+ //\r
+ if (*TransferResult != EFI_USB_NOERROR) {\r
+ //\r
+ // scroll the Data Toggle back to the last success TD\r
+ //\r
+ ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;\r
+ if ((ScrollNum % 2) != 0) {\r
+ *DataToggle ^= 1;\r
+ }\r
+\r
+ //\r
+ // If error, wait 100ms to retry by upper layer\r
+ //\r
+ MicroSecondDelay (100 * 1000);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Delete Queued TDs.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param PtrFirstTD Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+DeleteQueuedTDs (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN TD_STRUCT *PtrFirstTD\r
+ )\r
+{\r
+ TD_STRUCT *Tptr1;\r
+\r
+ TD_STRUCT *Tptr2;\r
+\r
+ Tptr1 = PtrFirstTD;\r
+ //\r
+ // Delete all the TDs in a queue.\r
+ //\r
+ while (Tptr1 != NULL) {\r
+\r
+ Tptr2 = Tptr1;\r
+\r
+ if (!GetTDLinkPtrValidorInvalid (Tptr2)) {\r
+ Tptr1 = NULL;\r
+ } else {\r
+ //\r
+ // has more than one TD in the queue.\r
+ //\r
+ Tptr1 = GetTDLinkPtr (Tptr2);\r
+ }\r
+\r
+ UhcFreePool (UhcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Check TDs Results.\r
+\r
+ @param PtrTD A pointer to TD_STRUCT data.\r
+ @param Result The result to return.\r
+ @param ErrTDPos The Error TD position.\r
+ @param ActualTransferSize Actual transfer size.\r
+\r
+ @retval The TD is executed successfully or not.\r
+\r
+**/\r
+BOOLEAN\r
+CheckTDsResults (\r
+ IN TD_STRUCT *PtrTD,\r
+ OUT UINT32 *Result,\r
+ OUT UINTN *ErrTDPos,\r
+ OUT UINTN *ActualTransferSize\r
+ )\r
+{\r
+ UINTN Len;\r
+\r
+ *Result = EFI_USB_NOERROR;\r
+ *ErrTDPos = 0;\r
+\r
+ //\r
+ // Init to zero.\r
+ //\r
+ *ActualTransferSize = 0;\r
+\r
+ while (PtrTD != NULL) {\r
+\r
+ if (IsTDStatusActive (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_NOTEXECUTE;\r
+ }\r
+\r
+ if (IsTDStatusStalled (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_STALL;\r
+ }\r
+\r
+ if (IsTDStatusBufferError (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_BUFFER;\r
+ }\r
+\r
+ if (IsTDStatusBabbleError (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_BABBLE;\r
+ }\r
+\r
+ if (IsTDStatusNAKReceived (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_NAK;\r
+ }\r
+\r
+ if (IsTDStatusCRCTimeOutError (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_TIMEOUT;\r
+ }\r
+\r
+ if (IsTDStatusBitStuffError (PtrTD)) {\r
+ *Result |= EFI_USB_ERR_BITSTUFF;\r
+ }\r
+ //\r
+ // Accumulate actual transferred data length in each TD.\r
+ //\r
+ Len = GetTDStatusActualLength (PtrTD) & 0x7FF;\r
+ *ActualTransferSize += Len;\r
+\r
+ //\r
+ // if any error encountered, stop processing the left TDs.\r
+ //\r
+ if ((*Result) != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ PtrTD = (TD_STRUCT *) (PtrTD->PtrNextTD);\r
+ //\r
+ // Record the first Error TD's position in the queue,\r
+ // this value is zero-based.\r
+ //\r
+ (*ErrTDPos)++;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Create Memory Block.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param MemoryHeader The Pointer to allocated memory block.\r
+ @param MemoryBlockSizeInPages The page size of memory block to be allocated.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateMemoryBlock (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT MEMORY_MANAGE_HEADER **MemoryHeader,\r
+ IN UINTN MemoryBlockSizeInPages\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+ UINTN MemPages;\r
+ UINT8 *Ptr;\r
+\r
+ //\r
+ // Memory Block uses MemoryBlockSizeInPages pages,\r
+ // memory management header and bit array use 1 page\r
+ //\r
+ MemPages = MemoryBlockSizeInPages + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ MemPages,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+\r
+ ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);\r
+\r
+ *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr;\r
+ //\r
+ // adjust Ptr pointer to the next empty memory\r
+ //\r
+ Ptr += sizeof (MEMORY_MANAGE_HEADER);\r
+ //\r
+ // Set Bit Array initial address\r
+ //\r
+ (*MemoryHeader)->BitArrayPtr = Ptr;\r
+\r
+ (*MemoryHeader)->Next = NULL;\r
+\r
+ //\r
+ // Memory block initial address\r
+ //\r
+ Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+ Ptr += EFI_PAGE_SIZE;\r
+ (*MemoryHeader)->MemoryBlockPtr = Ptr;\r
+ //\r
+ // set Memory block size\r
+ //\r
+ (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;\r
+ //\r
+ // each bit in Bit Array will manage 32byte memory in memory block\r
+ //\r
+ (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize UHCI memory management.\r
+\r
+ @param UhcDev The UCHI device.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeMemoryManagement (\r
+ IN USB_UHC_DEV *UhcDev\r
+ )\r
+{\r
+ MEMORY_MANAGE_HEADER *MemoryHeader;\r
+ EFI_STATUS Status;\r
+ UINTN MemPages;\r
+\r
+ MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
+ Status = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ UhcDev->Header1 = MemoryHeader;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize UHCI memory management.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param Pool Buffer pointer to store the buffer pointer.\r
+ @param AllocSize The size of the pool to be allocated.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+UhcAllocatePool (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT UINT8 **Pool,\r
+ IN UINTN AllocSize\r
+ )\r
+{\r
+ MEMORY_MANAGE_HEADER *MemoryHeader;\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+ MEMORY_MANAGE_HEADER *NewMemoryHeader;\r
+ UINTN RealAllocSize;\r
+ UINTN MemoryBlockSizeInPages;\r
+ EFI_STATUS Status;\r
+\r
+ *Pool = NULL;\r
+\r
+ MemoryHeader = UhcDev->Header1;\r
+\r
+ //\r
+ // allocate unit is 32 byte (align on 32 byte)\r
+ //\r
+ if ((AllocSize & 0x1F) != 0) {\r
+ RealAllocSize = (AllocSize / 32 + 1) * 32;\r
+ } else {\r
+ RealAllocSize = AllocSize;\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+ Status = AllocMemInMemoryBlock (\r
+ TempHeaderPtr,\r
+ (VOID **) Pool,\r
+ RealAllocSize / 32\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ //\r
+ // There is no enough memory,\r
+ // Create a new Memory Block\r
+ //\r
+ //\r
+ // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,\r
+ // just allocate a large enough memory block.\r
+ //\r
+ if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {\r
+ MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;\r
+ } else {\r
+ MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
+ }\r
+\r
+ Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Link the new Memory Block to the Memory Header list\r
+ //\r
+ InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);\r
+\r
+ Status = AllocMemInMemoryBlock (\r
+ NewMemoryHeader,\r
+ (VOID **) Pool,\r
+ RealAllocSize / 32\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Alloc Memory In MemoryBlock.\r
+\r
+ @param MemoryHeader The pointer to memory manage header.\r
+ @param Pool Buffer pointer to store the buffer pointer.\r
+ @param NumberOfMemoryUnit The size of the pool to be allocated.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocMemInMemoryBlock (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
+ OUT VOID **Pool,\r
+ IN UINTN NumberOfMemoryUnit\r
+ )\r
+{\r
+ UINTN TempBytePos;\r
+ UINTN FoundBytePos;\r
+ UINT8 Index;\r
+ UINT8 FoundBitPos;\r
+ UINT8 ByteValue;\r
+ UINT8 BitValue;\r
+ UINTN NumberOfZeros;\r
+ UINTN Count;\r
+\r
+ FoundBytePos = 0;\r
+ FoundBitPos = 0;\r
+\r
+ ByteValue = MemoryHeader->BitArrayPtr[0];\r
+ NumberOfZeros = 0;\r
+ Index = 0;\r
+ for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {\r
+ //\r
+ // Pop out BitValue from a byte in TempBytePos.\r
+ //\r
+ BitValue = (UINT8)(ByteValue & 0x1);\r
+\r
+ if (BitValue == 0) {\r
+ //\r
+ // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros\r
+ //\r
+ NumberOfZeros++;\r
+ //\r
+ // Found enough consecutive free space, break the loop\r
+ //\r
+ if (NumberOfZeros >= NumberOfMemoryUnit) {\r
+ break;\r
+ }\r
+ } else {\r
+ //\r
+ // Encountering a '1', meant the bit is ocupied.\r
+ //\r
+ if (NumberOfZeros >= NumberOfMemoryUnit) {\r
+ //\r
+ // Found enough consecutive free space,break the loop\r
+ //\r
+ break;\r
+ } else {\r
+ //\r
+ // the NumberOfZeros only record the number of those consecutive zeros,\r
+ // so reset the NumberOfZeros to 0 when encountering '1' before finding\r
+ // enough consecutive '0's\r
+ //\r
+ NumberOfZeros = 0;\r
+ //\r
+ // reset the (FoundBytePos,FoundBitPos) to the position of '1'\r
+ //\r
+ FoundBytePos = TempBytePos;\r
+ FoundBitPos = Index;\r
+ }\r
+ }\r
+ //\r
+ // right shift the byte\r
+ //\r
+ ByteValue /= 2;\r
+\r
+ //\r
+ // step forward a bit\r
+ //\r
+ Index++;\r
+ if (Index == 8) {\r
+ //\r
+ // step forward a byte, getting the byte value,\r
+ // and reset the bit pos.\r
+ //\r
+ TempBytePos += 1;\r
+ ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];\r
+ Index = 0;\r
+ }\r
+ }\r
+\r
+ if (NumberOfZeros < NumberOfMemoryUnit) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Found enough free space.\r
+ //\r
+ //\r
+ // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:\r
+ // 1)(FoundBytePos,FoundBitPos) record the position\r
+ // of the last '1' before the consecutive '0's, it must\r
+ // be adjusted to the start position of the consecutive '0's.\r
+ // 2)the start address of the consecutive '0's is just the start of\r
+ // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).\r
+ //\r
+ if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {\r
+ FoundBitPos += 1;\r
+ }\r
+ //\r
+ // Have the (FoundBytePos,FoundBitPos) make sense.\r
+ //\r
+ if (FoundBitPos > 7) {\r
+ FoundBytePos += 1;\r
+ FoundBitPos -= 8;\r
+ }\r
+ //\r
+ // Set the memory as allocated\r
+ //\r
+ for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {\r
+\r
+ MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));\r
+ Index++;\r
+ if (Index == 8) {\r
+ TempBytePos += 1;\r
+ Index = 0;\r
+ }\r
+ }\r
+\r
+ *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Uhci Free Pool.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param Pool A pointer to store the buffer address.\r
+ @param AllocSize The size of the pool to be freed.\r
+\r
+**/\r
+VOID\r
+UhcFreePool (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 *Pool,\r
+ IN UINTN AllocSize\r
+ )\r
+{\r
+ MEMORY_MANAGE_HEADER *MemoryHeader;\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+ UINTN StartBytePos;\r
+ UINTN Index;\r
+ UINT8 StartBitPos;\r
+ UINT8 Index2;\r
+ UINTN Count;\r
+ UINTN RealAllocSize;\r
+\r
+ MemoryHeader = UhcDev->Header1;\r
+\r
+ //\r
+ // allocate unit is 32 byte (align on 32 byte)\r
+ //\r
+ if ((AllocSize & 0x1F) != 0) {\r
+ RealAllocSize = (AllocSize / 32 + 1) * 32;\r
+ } else {\r
+ RealAllocSize = AllocSize;\r
+ }\r
+\r
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;\r
+ TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+ if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&\r
+ ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +\r
+ TempHeaderPtr->MemoryBlockSizeInBytes))) {\r
+\r
+ //\r
+ // Pool is in the Memory Block area,\r
+ // find the start byte and bit in the bit array\r
+ //\r
+ StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;\r
+ StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\r
+\r
+ TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));\r
+ Index2++;\r
+ if (Index2 == 8) {\r
+ Index += 1;\r
+ Index2 = 0;\r
+ }\r
+ }\r
+ //\r
+ // break the loop\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Insert a new memory header into list.\r
+\r
+ @param MemoryHeader A pointer to the memory header list.\r
+ @param NewMemoryHeader A new memory header to be inserted into the list.\r
+\r
+**/\r
+VOID\r
+InsertMemoryHeaderToList (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader\r
+ )\r
+{\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+\r
+ for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+ if (TempHeaderPtr->Next == NULL) {\r
+ TempHeaderPtr->Next = NewMemoryHeader;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Judge the memory block in the memory header is empty or not.\r
+\r
+ @param MemoryHeaderPtr A pointer to the memory header list.\r
+\r
+ @retval Whether the memory block in the memory header is empty or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsMemoryBlockEmptied (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {\r
+ if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ remove a memory header from list.\r
+\r
+ @param FirstMemoryHeader A pointer to the memory header list.\r
+ @param FreeMemoryHeader A memory header to be removed into the list.\r
+\r
+**/\r
+VOID\r
+DelinkMemoryBlock (\r
+ IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,\r
+ IN MEMORY_MANAGE_HEADER *FreeMemoryHeader\r
+ )\r
+{\r
+ MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
+\r
+ if ((FirstMemoryHeader == NULL) || (FreeMemoryHeader == NULL)) {\r
+ return ;\r
+ }\r
+\r
+ for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {\r
+\r
+ if (TempHeaderPtr->Next == FreeMemoryHeader) {\r
+ //\r
+ // Link the before and after\r
+ //\r
+ TempHeaderPtr->Next = FreeMemoryHeader->Next;\r
+ break;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Private Header file for Usb Host Controller PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _RECOVERY_UHC_H_\r
+#define _RECOVERY_UHC_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/UsbHostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#define USB_SLOW_SPEED_DEVICE 0x01\r
+#define USB_FULL_SPEED_DEVICE 0x02\r
+\r
+//\r
+// One memory block uses 16 page\r
+//\r
+#define NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES 16\r
+\r
+#define USBCMD 0 /* Command Register Offset 00-01h */\r
+#define USBCMD_RS BIT0 /* Run/Stop */\r
+#define USBCMD_HCRESET BIT1 /* Host reset */\r
+#define USBCMD_GRESET BIT2 /* Global reset */\r
+#define USBCMD_EGSM BIT3 /* Global Suspend Mode */\r
+#define USBCMD_FGR BIT4 /* Force Global Resume */\r
+#define USBCMD_SWDBG BIT5 /* SW Debug mode */\r
+#define USBCMD_CF BIT6 /* Config Flag (sw only) */\r
+#define USBCMD_MAXP BIT7 /* Max Packet (0 = 32, 1 = 64) */\r
+\r
+/* Status register */\r
+#define USBSTS 2 /* Status Register Offset 02-03h */\r
+#define USBSTS_USBINT BIT0 /* Interrupt due to IOC */\r
+#define USBSTS_ERROR BIT1 /* Interrupt due to error */\r
+#define USBSTS_RD BIT2 /* Resume Detect */\r
+#define USBSTS_HSE BIT3 /* Host System Error - basically PCI problems */\r
+#define USBSTS_HCPE BIT4 /* Host Controller Process Error - the scripts were buggy */\r
+#define USBSTS_HCH BIT5 /* HC Halted */\r
+\r
+/* Interrupt enable register */\r
+#define USBINTR 4 /* Interrupt Enable Register 04-05h */\r
+#define USBINTR_TIMEOUT BIT0 /* Timeout/CRC error enable */\r
+#define USBINTR_RESUME BIT1 /* Resume interrupt enable */\r
+#define USBINTR_IOC BIT2 /* Interrupt On Complete enable */\r
+#define USBINTR_SP BIT3 /* Short packet interrupt enable */\r
+\r
+/* Frame Number Register Offset 06-08h */\r
+#define USBFRNUM 6\r
+\r
+/* Frame List Base Address Register Offset 08-0Bh */\r
+#define USBFLBASEADD 8\r
+\r
+/* Start of Frame Modify Register Offset 0Ch */\r
+#define USBSOF 0x0c\r
+\r
+/* USB port status and control registers */\r
+#define USBPORTSC1 0x10 /*Port 1 offset 10-11h */\r
+#define USBPORTSC2 0x12 /*Port 2 offset 12-13h */\r
+\r
+#define USBPORTSC_CCS BIT0 /* Current Connect Status ("device present") */\r
+#define USBPORTSC_CSC BIT1 /* Connect Status Change */\r
+#define USBPORTSC_PED BIT2 /* Port Enable / Disable */\r
+#define USBPORTSC_PEDC BIT3 /* Port Enable / Disable Change */\r
+#define USBPORTSC_LSL BIT4 /* Line Status Low bit*/\r
+#define USBPORTSC_LSH BIT5 /* Line Status High bit*/\r
+#define USBPORTSC_RD BIT6 /* Resume Detect */\r
+#define USBPORTSC_LSDA BIT8 /* Low Speed Device Attached */\r
+#define USBPORTSC_PR BIT9 /* Port Reset */\r
+#define USBPORTSC_SUSP BIT12 /* Suspend */\r
+\r
+#define SETUP_PACKET_ID 0x2D\r
+#define INPUT_PACKET_ID 0x69\r
+#define OUTPUT_PACKET_ID 0xE1\r
+#define ERROR_PACKET_ID 0x55\r
+\r
+#define STALL_1_MILLI_SECOND 1000\r
+\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT32 FrameListPtrTerminate : 1;\r
+ UINT32 FrameListPtrQSelect : 1;\r
+ UINT32 FrameListRsvd : 2;\r
+ UINT32 FrameListPtr : 28;\r
+} FRAMELIST_ENTRY;\r
+\r
+typedef struct {\r
+ UINT32 QHHorizontalTerminate : 1;\r
+ UINT32 QHHorizontalQSelect : 1;\r
+ UINT32 QHHorizontalRsvd : 2;\r
+ UINT32 QHHorizontalPtr : 28;\r
+ UINT32 QHVerticalTerminate : 1;\r
+ UINT32 QHVerticalQSelect : 1;\r
+ UINT32 QHVerticalRsvd : 2;\r
+ UINT32 QHVerticalPtr : 28;\r
+} QUEUE_HEAD;\r
+\r
+typedef struct {\r
+ QUEUE_HEAD QueueHead;\r
+ UINT32 Reserved1;\r
+ UINT32 Reserved2;\r
+ VOID *PtrNext;\r
+ VOID *PtrDown;\r
+ VOID *Reserved3;\r
+ UINT32 Reserved4;\r
+} QH_STRUCT;\r
+\r
+typedef struct {\r
+ UINT32 TDLinkPtrTerminate : 1;\r
+ UINT32 TDLinkPtrQSelect : 1;\r
+ UINT32 TDLinkPtrDepthSelect : 1;\r
+ UINT32 TDLinkPtrRsvd : 1;\r
+ UINT32 TDLinkPtr : 28;\r
+ UINT32 TDStatusActualLength : 11;\r
+ UINT32 TDStatusRsvd : 5;\r
+ UINT32 TDStatus : 8;\r
+ UINT32 TDStatusIOC : 1;\r
+ UINT32 TDStatusIOS : 1;\r
+ UINT32 TDStatusLS : 1;\r
+ UINT32 TDStatusErr : 2;\r
+ UINT32 TDStatusSPD : 1;\r
+ UINT32 TDStatusRsvd2 : 2;\r
+ UINT32 TDTokenPID : 8;\r
+ UINT32 TDTokenDevAddr : 7;\r
+ UINT32 TDTokenEndPt : 4;\r
+ UINT32 TDTokenDataToggle : 1;\r
+ UINT32 TDTokenRsvd : 1;\r
+ UINT32 TDTokenMaxLen : 11;\r
+ UINT32 TDBufferPtr;\r
+} TD;\r
+\r
+typedef struct {\r
+ TD TDData;\r
+ UINT8 *PtrTDBuffer;\r
+ VOID *PtrNextTD;\r
+ VOID *PtrNextQH;\r
+ UINT16 TDBufferLength;\r
+ UINT16 Reserved;\r
+} TD_STRUCT;\r
+\r
+#pragma pack()\r
+\r
+typedef struct _MEMORY_MANAGE_HEADER MEMORY_MANAGE_HEADER;\r
+\r
+struct _MEMORY_MANAGE_HEADER {\r
+ UINT8 *BitArrayPtr;\r
+ UINTN BitArraySizeInBytes;\r
+ UINT8 *MemoryBlockPtr;\r
+ UINTN MemoryBlockSizeInBytes;\r
+ MEMORY_MANAGE_HEADER *Next;\r
+};\r
+\r
+#define USB_UHC_DEV_SIGNATURE SIGNATURE_32 ('p', 'u', 'h', 'c')\r
+typedef struct {\r
+ UINTN Signature;\r
+ PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+\r
+ UINT32 UsbHostControllerBaseAddress;\r
+ FRAMELIST_ENTRY *FrameListEntry;\r
+ QH_STRUCT *ConfigQH;\r
+ QH_STRUCT *BulkQH;\r
+ //\r
+ // Header1 used for QH,TD memory blocks management\r
+ //\r
+ MEMORY_MANAGE_HEADER *Header1;\r
+\r
+} USB_UHC_DEV;\r
+\r
+#define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a) CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE)\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer \r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI * This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST * Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN OUT UINTN *DataLength OPTIONAL,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param MaximumPacketLength Maximum packet size the endpoint is capable of \r
+ sending or receiving.\r
+ @param Data Array of pointers to the buffers of data to transmit \r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of \r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[out] PortNumber The pointer to the number of the root hub ports. \r
+ \r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortNumber (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *PortNumber\r
+ );\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber The root hub port to retrieve the state from. \r
+ @param PortStatus Variable to receive the port state.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified.\r
+ by PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcGetRootHubPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ );\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI\r
+ @param PortNumber Root hub port to set.\r
+ @param PortFeature Feature to set.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcSetRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared \r
+ for the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcClearRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+/**\r
+ Initialize UHCI.\r
+\r
+ @param UhcDev UHCI Device.\r
+\r
+ @retval EFI_SUCCESS UHCI successfully initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Resource can not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+ IN USB_UHC_DEV *UhcDev\r
+ );\r
+\r
+/**\r
+ Create Frame List Structure.\r
+\r
+ @param UhcDev UHCI device.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateFrameList (\r
+ USB_UHC_DEV *UhcDev\r
+ );\r
+\r
+/**\r
+ Read a 16bit width data from Uhc HC IO space register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param Port The IO space address of the register.\r
+\r
+ @retval the register content read.\r
+\r
+**/\r
+UINT16\r
+USBReadPortW (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Port\r
+ );\r
+\r
+/**\r
+ Write a 16bit width data into Uhc HC IO space register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param Port The IO space address of the register.\r
+ @param Data The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortW (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Port,\r
+ IN UINT16 Data\r
+ );\r
+\r
+/**\r
+ Write a 32bit width data into Uhc HC IO space register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param Port The IO space address of the register.\r
+ @param Data The data written into the register.\r
+\r
+**/\r
+VOID\r
+USBWritePortDW (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Port,\r
+ IN UINT32 Data\r
+ );\r
+\r
+/**\r
+ Clear the content of UHCI's Status Register.\r
+ \r
+ @param UhcDev The UHCI device.\r
+ @param StatusAddr The IO space address of the register.\r
+\r
+**/\r
+VOID\r
+ClearStatusReg (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 StatusAddr\r
+ );\r
+\r
+/**\r
+ Check whether the host controller operates well.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param StatusRegAddr The io address of status register.\r
+\r
+ @retval TRUE Host controller is working.\r
+ @retval FALSE Host controller is halted or system error.\r
+\r
+**/\r
+BOOLEAN\r
+IsStatusOK (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 StatusRegAddr\r
+ );\r
+\r
+/**\r
+ Get Current Frame Number.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param FrameNumberAddr The address of frame list register.\r
+\r
+ @retval The content of the frame list register.\r
+\r
+**/\r
+UINT16\r
+GetCurrentFrameNumber (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 FrameNumberAddr\r
+ );\r
+\r
+/**\r
+ Set Frame List Base Address.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param FrameListRegAddr The address of frame list register.\r
+ @param Addr The address of frame list table.\r
+\r
+**/\r
+VOID\r
+SetFrameListBaseAddress (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 FrameListRegAddr,\r
+ IN UINT32 Addr\r
+ );\r
+\r
+/**\r
+ Create QH and initialize.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateQH (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT QH_STRUCT **PtrQH\r
+ );\r
+\r
+/**\r
+ Set the horizontal link pointer in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param PtrNext Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalLinkPtr (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN VOID *PtrNext\r
+ );\r
+\r
+/**\r
+ Get the horizontal link pointer in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+\r
+ @retval The horizontal link pointer in QH.\r
+\r
+**/\r
+VOID *\r
+GetQHHorizontalLinkPtr (\r
+ IN QH_STRUCT *PtrQH\r
+ );\r
+\r
+/**\r
+ Set a QH or TD horizontally to be connected with a specific QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsQH Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalQHorTDSelect (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsQH\r
+ );\r
+\r
+/**\r
+ Set the horizontal validor bit in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsValid Specify the horizontal linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHHorizontalValidorInvalid (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsValid\r
+ );\r
+\r
+/**\r
+ Set the vertical link pointer in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param PtrNext Place to the next QH_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalLinkPtr (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN VOID *PtrNext\r
+ );\r
+\r
+/**\r
+ Set a QH or TD vertically to be connected with a specific QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsQH Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalQHorTDSelect (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsQH\r
+ );\r
+\r
+/**\r
+ Set the vertical validor bit in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param IsValid Specify the vertical linker is valid or not.\r
+\r
+**/\r
+VOID\r
+SetQHVerticalValidorInvalid (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN BOOLEAN IsValid\r
+ );\r
+\r
+/**\r
+ Get the vertical validor bit in QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+\r
+ @retval The vertical linker is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetQHHorizontalValidorInvalid (\r
+ IN QH_STRUCT *PtrQH\r
+ );\r
+\r
+/**\r
+ Allocate TD or QH Struct.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param Size The size of allocation.\r
+ @param PtrStruct Place to store TD_STRUCT pointer.\r
+\r
+ @return EFI_SUCCESS Allocate successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocateTDorQHStruct (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT32 Size,\r
+ OUT VOID **PtrStruct\r
+ );\r
+\r
+/**\r
+ Create a TD Struct.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param PtrTD Place to store TD_STRUCT pointer.\r
+\r
+ @return EFI_SUCCESS Allocate successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT TD_STRUCT **PtrTD\r
+ );\r
+\r
+/**\r
+ Generate Setup Stage TD.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param DevAddr Device address.\r
+ @param Endpoint Endpoint number.\r
+ @param DeviceSpeed Device Speed.\r
+ @param DevRequest Device reuquest.\r
+ @param RequestLen Request length.\r
+ @param PtrTD TD_STRUCT generated.\r
+\r
+ @return EFI_SUCCESS Generate setup stage TD successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenSetupStageTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 Endpoint,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 *DevRequest,\r
+ IN UINT8 RequestLen,\r
+ OUT TD_STRUCT **PtrTD\r
+ );\r
+\r
+/**\r
+ Generate Data Stage TD.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param DevAddr Device address.\r
+ @param Endpoint Endpoint number.\r
+ @param PtrData Data buffer.\r
+ @param Len Data length.\r
+ @param PktID PacketID.\r
+ @param Toggle Data toggle value.\r
+ @param DeviceSpeed Device Speed.\r
+ @param PtrTD TD_STRUCT generated.\r
+\r
+ @return EFI_SUCCESS Generate data stage TD successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GenDataTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 Endpoint,\r
+ IN UINT8 *PtrData,\r
+ IN UINT8 Len,\r
+ IN UINT8 PktID,\r
+ IN UINT8 Toggle,\r
+ IN UINT8 DeviceSpeed,\r
+ OUT TD_STRUCT **PtrTD\r
+ );\r
+\r
+/**\r
+ Generate Status Stage TD.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param DevAddr Device address.\r
+ @param Endpoint Endpoint number.\r
+ @param PktID PacketID.\r
+ @param DeviceSpeed Device Speed.\r
+ @param PtrTD TD_STRUCT generated.\r
+\r
+ @return EFI_SUCCESS Generate status stage TD successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateStatusTD (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 DevAddr,\r
+ IN UINT8 Endpoint,\r
+ IN UINT8 PktID,\r
+ IN UINT8 DeviceSpeed,\r
+ OUT TD_STRUCT **PtrTD\r
+ );\r
+\r
+/**\r
+ Set the link pointer validor bit in TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsValid Specify the linker pointer is valid or not.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrValidorInvalid (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsValid\r
+ );\r
+\r
+/**\r
+ Set the Link Pointer pointing to a QH or TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsQH Specify QH or TD is connected.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrQHorTDSelect (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsQH\r
+ );\r
+\r
+/**\r
+ Set the traverse is depth-first or breadth-first.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsDepth Specify the traverse is depth-first or breadth-first.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtrDepthorBreadth (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsDepth\r
+ );\r
+\r
+/**\r
+ Set TD Link Pointer in TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param PtrNext Place to the next TD_STRUCT.\r
+\r
+**/\r
+VOID\r
+SetTDLinkPtr (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN VOID *PtrNext\r
+ );\r
+\r
+/**\r
+ Get TD Link Pointer.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval Get TD Link Pointer in TD.\r
+\r
+**/\r
+VOID*\r
+GetTDLinkPtr (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Get the information about whether the Link Pointer field pointing to\r
+ a QH or a TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval whether the Link Pointer field pointing to a QH or a TD.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDLinkPtrQHOrTD (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Enable/Disable short packet detection mechanism.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsEnable Enable or disable short packet detection mechanism.\r
+\r
+**/\r
+VOID\r
+EnableorDisableTDShortPacket (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsEnable\r
+ );\r
+\r
+/**\r
+ Set the max error counter in TD.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param MaxErrors The number of allowable error.\r
+\r
+**/\r
+VOID\r
+SetTDControlErrorCounter (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINT8 MaxErrors\r
+ );\r
+\r
+/**\r
+ Set the TD is targeting a low-speed device or not.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsLowSpeedDevice Whether The device is low-speed.\r
+\r
+**/\r
+VOID\r
+SetTDLoworFullSpeedDevice (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsLowSpeedDevice\r
+ );\r
+\r
+/**\r
+ Set the TD is isochronous transfer type or not.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsIsochronous Whether the transaction isochronous transfer type.\r
+\r
+**/\r
+VOID\r
+SetTDControlIsochronousorNot (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsIsochronous\r
+ );\r
+\r
+/**\r
+ Set if UCHI should issue an interrupt on completion of the frame\r
+ in which this TD is executed\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsSet Whether HC should issue an interrupt on completion.\r
+\r
+**/\r
+VOID\r
+SetorClearTDControlIOC (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsSet\r
+ );\r
+\r
+/**\r
+ Set if the TD is active and can be executed.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param IsActive Whether the TD is active and can be executed.\r
+\r
+**/\r
+VOID\r
+SetTDStatusActiveorInactive (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN BOOLEAN IsActive\r
+ );\r
+\r
+/**\r
+ Specifies the maximum number of data bytes allowed for the transfer.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param MaxLen The maximum number of data bytes allowed.\r
+\r
+ @retval The allowed maximum number of data.\r
+**/\r
+UINT16\r
+SetTDTokenMaxLength (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINT16 MaxLen\r
+ );\r
+\r
+/**\r
+ Set the data toggle bit to DATA1.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle1 (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Set the data toggle bit to DATA0.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDataToggle0 (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Set EndPoint Number the TD is targeting at.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param EndPoint The Endport number of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenEndPoint (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINTN EndPoint\r
+ );\r
+\r
+/**\r
+ Set Device Address the TD is targeting at.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param DevAddr The Device Address of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenDeviceAddress (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINTN DevAddr\r
+ );\r
+\r
+/**\r
+ Set Packet Identification the TD is targeting at.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+ @param PacketID The Packet Identification of the target.\r
+\r
+**/\r
+VOID\r
+SetTDTokenPacketID (\r
+ IN TD_STRUCT *PtrTDStruct,\r
+ IN UINT8 PacketID\r
+ );\r
+\r
+/**\r
+ Set the beginning address of the data buffer that will be used\r
+ during the transaction.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+SetTDDataBuffer (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether the TD is active.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The TD is active or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusActive (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether the TD is stalled.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The TD is stalled or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusStalled (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether Data Buffer Error is happened.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The Data Buffer Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBufferError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether Babble Error is happened.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The Babble Error is happened or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBabbleError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether NAK is received.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The NAK is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusNAKReceived (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether CRC/Time Out Error is encountered.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The CRC/Time Out Error is encountered or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusCRCTimeOutError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Detect whether Bitstuff Error is received.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The Bitstuff Error is received or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsTDStatusBitStuffError (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Retrieve the actual number of bytes that were tansferred.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The actual number of bytes that were tansferred.\r
+\r
+**/\r
+UINT16\r
+GetTDStatusActualLength (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Retrieve the information of whether the Link Pointer field is valid or not.\r
+\r
+ @param PtrTDStruct Place to store TD_STRUCT pointer.\r
+\r
+ @retval The linker pointer field is valid or not.\r
+\r
+**/\r
+BOOLEAN\r
+GetTDLinkPtrValidorInvalid (\r
+ IN TD_STRUCT *PtrTDStruct\r
+ );\r
+\r
+/**\r
+ Count TD Number from PtrFirstTD.\r
+\r
+ @param PtrFirstTD Place to store TD_STRUCT pointer.\r
+\r
+ @retval The queued TDs number.\r
+\r
+**/\r
+UINTN\r
+CountTDsNumber (\r
+ IN TD_STRUCT *PtrFirstTD\r
+ );\r
+\r
+/**\r
+ Link TD To QH.\r
+\r
+ @param PtrQH Place to store QH_STRUCT pointer.\r
+ @param PtrTD Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToQH (\r
+ IN QH_STRUCT *PtrQH,\r
+ IN TD_STRUCT *PtrTD\r
+ );\r
+\r
+/**\r
+ Link TD To TD.\r
+\r
+ @param PtrPreTD Place to store TD_STRUCT pointer.\r
+ @param PtrTD Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+LinkTDToTD (\r
+ IN TD_STRUCT *PtrPreTD,\r
+ IN TD_STRUCT *PtrTD\r
+ );\r
+\r
+/**\r
+ Execute Control Transfer.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param PtrTD A pointer to TD_STRUCT data.\r
+ @param ActualLen Actual transfer Length.\r
+ @param TimeOut TimeOut value.\r
+ @param TransferResult Transfer Result.\r
+\r
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @return EFI_TIMEOUT The transfer failed due to time out.\r
+ @return EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecuteControlTransfer (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN TD_STRUCT *PtrTD,\r
+ OUT UINTN *ActualLen,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Execute Bulk Transfer.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param PtrTD A pointer to TD_STRUCT data.\r
+ @param ActualLen Actual transfer Length.\r
+ @param DataToggle DataToggle value.\r
+ @param TimeOut TimeOut value.\r
+ @param TransferResult Transfer Result.\r
+\r
+ @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
+ @return EFI_TIMEOUT The transfer failed due to time out.\r
+ @return EFI_SUCCESS The transfer finished OK.\r
+\r
+**/\r
+EFI_STATUS\r
+ExecBulkTransfer (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN TD_STRUCT *PtrTD,\r
+ IN OUT UINTN *ActualLen,\r
+ IN UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Delete Queued TDs.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param PtrFirstTD Place to store TD_STRUCT pointer.\r
+\r
+**/\r
+VOID\r
+DeleteQueuedTDs (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN TD_STRUCT *PtrFirstTD\r
+ );\r
+\r
+/**\r
+ Check TDs Results.\r
+\r
+ @param PtrTD A pointer to TD_STRUCT data.\r
+ @param Result The result to return.\r
+ @param ErrTDPos The Error TD position.\r
+ @param ActualTransferSize Actual transfer size.\r
+\r
+ @retval The TD is executed successfully or not.\r
+\r
+**/\r
+BOOLEAN\r
+CheckTDsResults (\r
+ IN TD_STRUCT *PtrTD,\r
+ OUT UINT32 *Result,\r
+ OUT UINTN *ErrTDPos,\r
+ OUT UINTN *ActualTransferSize\r
+ );\r
+\r
+/**\r
+ Create Memory Block.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param MemoryHeader The Pointer to allocated memory block.\r
+ @param MemoryBlockSizeInPages The page size of memory block to be allocated.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateMemoryBlock (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT MEMORY_MANAGE_HEADER **MemoryHeader,\r
+ IN UINTN MemoryBlockSizeInPages\r
+ );\r
+\r
+/**\r
+ Initialize UHCI memory management.\r
+\r
+ @param UhcDev The UCHI device.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeMemoryManagement (\r
+ IN USB_UHC_DEV *UhcDev\r
+ );\r
+\r
+/**\r
+ Initialize UHCI memory management.\r
+\r
+ @param UhcDev The UCHI device.\r
+ @param Pool Buffer pointer to store the buffer pointer.\r
+ @param AllocSize The size of the pool to be allocated.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+UhcAllocatePool (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ OUT UINT8 **Pool,\r
+ IN UINTN AllocSize\r
+ );\r
+\r
+/**\r
+ Alloc Memory In MemoryBlock.\r
+\r
+ @param MemoryHeader The pointer to memory manage header.\r
+ @param Pool Buffer pointer to store the buffer pointer.\r
+ @param NumberOfMemoryUnit The size of the pool to be allocated.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.\r
+ @retval EFI_SUCCESS Success.\r
+\r
+**/\r
+EFI_STATUS\r
+AllocMemInMemoryBlock (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
+ OUT VOID **Pool,\r
+ IN UINTN NumberOfMemoryUnit\r
+ );\r
+\r
+/**\r
+ Uhci Free Pool.\r
+\r
+ @param UhcDev The UHCI device.\r
+ @param Pool A pointer to store the buffer address.\r
+ @param AllocSize The size of the pool to be freed.\r
+\r
+**/\r
+VOID\r
+UhcFreePool (\r
+ IN USB_UHC_DEV *UhcDev,\r
+ IN UINT8 *Pool,\r
+ IN UINTN AllocSize\r
+ );\r
+\r
+/**\r
+ Insert a new memory header into list.\r
+\r
+ @param MemoryHeader A pointer to the memory header list.\r
+ @param NewMemoryHeader A new memory header to be inserted into the list.\r
+\r
+**/\r
+VOID\r
+InsertMemoryHeaderToList (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
+ IN MEMORY_MANAGE_HEADER *NewMemoryHeader\r
+ );\r
+\r
+/**\r
+ Judge the memory block in the memory header is empty or not.\r
+\r
+ @param MemoryHeaderPtr A pointer to the memory header list.\r
+\r
+ @retval Whether the memory block in the memory header is empty or not.\r
+\r
+**/\r
+BOOLEAN\r
+IsMemoryBlockEmptied (\r
+ IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr\r
+ );\r
+\r
+/**\r
+ remove a memory header from list.\r
+\r
+ @param FirstMemoryHeader A pointer to the memory header list.\r
+ @param FreeMemoryHeader A memory header to be removed into the list.\r
+\r
+**/\r
+VOID\r
+DelinkMemoryBlock (\r
+ IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,\r
+ IN MEMORY_MANAGE_HEADER *FreeMemoryHeader\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for UhcPeim PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
+# which is used to enable recovery function from USB Drivers.\r
+\r
+#\r
+# Usb Host Controller PEIM to support recovery from USB device.\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution. The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = UhciPei\r
+ FILE_GUID = C463CEAC-FC57-4f36-88B7-356C750C3BCA\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = UhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ UhcPeim.c\r
+ UhcPeim.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeiServicesLib\r
+ PeimEntryPoint\r
+ DebugLib\r
+\r
+\r
+[Ppis]\r
+ gPeiUsbHostControllerPpiGuid # PPI ALWAYS_PRODUCED\r
+ gPeiUsbControllerPpiGuid # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+\r
--- /dev/null
+/** @file\r
+BOT Transportation implementation.\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbBotPeim.h"\r
+#include "BotPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+/**\r
+ Reset the given usb device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Can not get usb io ppi.\r
+ @retval EFI_SUCCESS Failed to reset the given usb device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotRecoveryReset (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ UINT32 Timeout;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT8 EndpointAddr;\r
+ EFI_STATUS Status;\r
+\r
+ UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+ if (UsbIoPpi == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ DevReq.RequestType = 0x21;\r
+ DevReq.Request = 0xFF;\r
+ DevReq.Value = 0;\r
+ DevReq.Index = 0;\r
+ DevReq.Length = 0;\r
+\r
+ Timeout = 3000;\r
+\r
+ Status = UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ Timeout,\r
+ NULL,\r
+ 0\r
+ );\r
+\r
+ //\r
+ // clear bulk in endpoint stall feature\r
+ //\r
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;\r
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);\r
+\r
+ //\r
+ // clear bulk out endpoint stall feature\r
+ //\r
+ EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;\r
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send the command to the device using Bulk-Out endpoint.\r
+\r
+ This function sends the command to the device using Bulk-Out endpoint.\r
+ BOT transfer is composed of three phases: Command, Data, and Status.\r
+ This is the Command phase.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.\r
+ @param Command The command to transfer to device.\r
+ @param CommandSize The length of the command.\r
+ @param DataTransferLength The expected length of the data.\r
+ @param Direction The direction of the data.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_DEVICE_ERROR Successful to send the command to device.\r
+ @retval EFI_SUCCESS Failed to send the command to device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotCommandPhase (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev,\r
+ IN VOID *Command,\r
+ IN UINT8 CommandSize,\r
+ IN UINT32 DataTransferLength,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT16 Timeout\r
+ )\r
+{\r
+ CBW Cbw;\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINTN DataSize;\r
+\r
+ UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+ ZeroMem (&Cbw, sizeof (CBW));\r
+\r
+ //\r
+ // Fill the command block, detailed see BOT spec\r
+ //\r
+ Cbw.Signature = CBWSIG;\r
+ Cbw.Tag = 0x01;\r
+ Cbw.DataTransferLength = DataTransferLength;\r
+ Cbw.Flags = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0);\r
+ Cbw.Lun = 0;\r
+ Cbw.CmdLen = CommandSize;\r
+\r
+ CopyMem (Cbw.CmdBlock, Command, CommandSize);\r
+\r
+ DataSize = sizeof (CBW);\r
+\r
+ Status = UsbIoPpi->UsbBulkTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (PeiBotDev->BulkOutEndpoint)->EndpointAddress,\r
+ (UINT8 *) &Cbw,\r
+ &DataSize,\r
+ Timeout\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Command phase fail, we need to recovery reset this device\r
+ //\r
+ BotRecoveryReset (PeiServices, PeiBotDev);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Transfer the data between the device and host.\r
+\r
+ This function transfers the data between the device and host.\r
+ BOT transfer is composed of three phases: Command, Data, and Status.\r
+ This is the Data phase.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.\r
+ @param DataSize The length of the data.\r
+ @param DataBuffer The pointer to the data.\r
+ @param Direction The direction of the data.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_DEVICE_ERROR Successful to send the data to device.\r
+ @retval EFI_SUCCESS Failed to send the data to device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotDataPhase (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev,\r
+ IN UINT32 *DataSize,\r
+ IN OUT VOID *DataBuffer,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT16 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT8 EndpointAddr;\r
+ UINTN Remain;\r
+ UINTN Increment;\r
+ UINT32 MaxPacketLen;\r
+ UINT8 *BufferPtr;\r
+ UINTN TransferredSize;\r
+\r
+ UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+ Remain = *DataSize;\r
+ BufferPtr = (UINT8 *) DataBuffer;\r
+ TransferredSize = 0;\r
+\r
+ //\r
+ // retrieve the the max packet length of the given endpoint\r
+ //\r
+ if (Direction == EfiUsbDataIn) {\r
+ MaxPacketLen = (PeiBotDev->BulkInEndpoint)->MaxPacketSize;\r
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;\r
+ } else {\r
+ MaxPacketLen = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize;\r
+ EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;\r
+ }\r
+\r
+ while (Remain > 0) {\r
+ //\r
+ // Using 15 packets to avoid Bitstuff error\r
+ //\r
+ if (Remain > 16 * MaxPacketLen) {\r
+ Increment = 16 * MaxPacketLen;\r
+ } else {\r
+ Increment = Remain;\r
+ }\r
+\r
+ Status = UsbIoPpi->UsbBulkTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ EndpointAddr,\r
+ BufferPtr,\r
+ &Increment,\r
+ Timeout\r
+ );\r
+\r
+ TransferredSize += Increment;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);\r
+ return Status;\r
+ }\r
+\r
+ BufferPtr += Increment;\r
+ Remain -= Increment;\r
+ }\r
+\r
+ *DataSize = (UINT32) TransferredSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the command execution status from device.\r
+\r
+ This function gets the command execution status from device.\r
+ BOT transfer is composed of three phases: Command, Data, and Status.\r
+ This is the Status phase.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.\r
+ @param TransferStatus The status of the transaction.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.\r
+ @retval EFI_SUCCESS Failed to get the status of device.\r
+\r
+**/\r
+EFI_STATUS\r
+BotStatusPhase (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev,\r
+ OUT UINT8 *TransferStatus,\r
+ IN UINT16 Timeout\r
+ )\r
+{\r
+ CSW Csw;\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT8 EndpointAddr;\r
+ UINTN DataSize;\r
+\r
+ UsbIoPpi = PeiBotDev->UsbIoPpi;\r
+\r
+ ZeroMem (&Csw, sizeof (CSW));\r
+\r
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;\r
+\r
+ DataSize = sizeof (CSW);\r
+\r
+ //\r
+ // Get the status field from bulk transfer\r
+ //\r
+ Status = UsbIoPpi->UsbBulkTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ EndpointAddr,\r
+ &Csw,\r
+ &DataSize,\r
+ Timeout\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Csw.Signature == CSWSIG) {\r
+ *TransferStatus = Csw.Status;\r
+ } else {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send ATAPI command using BOT protocol.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.\r
+ @param Command The command to be sent to ATAPI device.\r
+ @param CommandSize The length of the data to be sent.\r
+ @param DataBuffer The pointer to the data.\r
+ @param BufferLength The length of the data.\r
+ @param Direction The direction of the data.\r
+ @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.\r
+ @retval EFI_SUCCESS Failed to get the status of device.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiAtapiCommand (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev,\r
+ IN VOID *Command,\r
+ IN UINT8 CommandSize,\r
+ IN VOID *DataBuffer,\r
+ IN UINT32 BufferLength,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT16 TimeOutInMilliSeconds\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS BotDataStatus;\r
+ UINT8 TransferStatus;\r
+ UINT32 BufferSize;\r
+\r
+ BotDataStatus = EFI_SUCCESS;\r
+ //\r
+ // First send ATAPI command through Bot\r
+ //\r
+ Status = BotCommandPhase (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ Command,\r
+ CommandSize,\r
+ BufferLength,\r
+ Direction,\r
+ TimeOutInMilliSeconds\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Send/Get Data if there is a Data Stage\r
+ //\r
+ switch (Direction) {\r
+ case EfiUsbDataIn:\r
+ case EfiUsbDataOut:\r
+ BufferSize = BufferLength;\r
+\r
+ BotDataStatus = BotDataPhase (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ &BufferSize,\r
+ DataBuffer,\r
+ Direction,\r
+ TimeOutInMilliSeconds\r
+ );\r
+ break;\r
+\r
+ case EfiUsbNoData:\r
+ break;\r
+ }\r
+ //\r
+ // Status Phase\r
+ //\r
+ Status = BotStatusPhase (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ &TransferStatus,\r
+ TimeOutInMilliSeconds\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ BotRecoveryReset (PeiServices, PeiBotDev);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (TransferStatus == 0x01) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return BotDataStatus;\r
+}\r
--- /dev/null
+/** @file\r
+BOT Transportation implementation.\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_BOT_PEIM_H_\r
+#define _PEI_BOT_PEIM_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbIo.h>\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+//#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#include <IndustryStandard/Atapi.h>\r
+\r
+#pragma pack(1)\r
+//\r
+// Bulk Only device protocol\r
+//\r
+typedef struct {\r
+ UINT32 Signature;\r
+ UINT32 Tag;\r
+ UINT32 DataTransferLength;\r
+ UINT8 Flags;\r
+ UINT8 Lun;\r
+ UINT8 CmdLen;\r
+ UINT8 CmdBlock[16];\r
+} CBW;\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ UINT32 Tag;\r
+ UINT32 DataResidue;\r
+ UINT8 Status;\r
+} CSW;\r
+\r
+#pragma pack()\r
+//\r
+// Status code, see Usb Bot device spec\r
+//\r
+#define CSWSIG 0x53425355\r
+#define CBWSIG 0x43425355\r
+\r
+/**\r
+ Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r
+ return INQUIRY data of the device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS Inquiry command completes successfully.\r
+ @retval EFI_DEVICE_ERROR Inquiry command failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbInquiry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ );\r
+\r
+/**\r
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+ to find out whether device is accessible.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS TestUnit command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbTestUnitReady (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ );\r
+\r
+/**\r
+ Sends out ATAPI Request Sense Packet Command to the specified device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+ @param SenseCounts Length of sense buffer.\r
+ @param SenseKeyBuffer Pointer to sense buffer.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRequestSense (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice,\r
+ OUT UINTN *SenseCounts,\r
+ IN UINT8 *SenseKeyBuffer\r
+ );\r
+\r
+/**\r
+ Sends out ATAPI Read Capacity Packet Command to the specified device.\r
+ This command will return the information regarding the capacity of the\r
+ media in the device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadCapacity (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ );\r
+\r
+/**\r
+ Sends out ATAPI Read Format Capacity Data Command to the specified device.\r
+ This command will return the information regarding the capacity of the\r
+ media in the device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadFormattedCapacity (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ );\r
+\r
+/**\r
+ Execute Read(10) ATAPI command on a specific SCSI target.\r
+\r
+ Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+ @param Buffer The pointer to data buffer.\r
+ @param Lba The start logic block address of reading.\r
+ @param NumberOfBlocks The block number of reading.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRead10 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice,\r
+ IN VOID *Buffer,\r
+ IN EFI_PEI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ );\r
+\r
+/** \r
+ Check if there is media according to sense data.\r
+\r
+ @param SenseData Pointer to sense data.\r
+ @param SenseCounts Count of sense data.\r
+\r
+ @retval TRUE No media\r
+ @retval FALSE Media exists\r
+\r
+**/\r
+BOOLEAN\r
+IsNoMedia (\r
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+ IN UINTN SenseCounts\r
+ );\r
+\r
+/** \r
+ Check if there is media error according to sense data.\r
+\r
+ @param SenseData Pointer to sense data.\r
+ @param SenseCounts Count of sense data.\r
+\r
+ @retval TRUE Media error\r
+ @retval FALSE No media error\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaError (\r
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+ IN UINTN SenseCounts\r
+ );\r
+\r
+/** \r
+ Check if media is changed according to sense data.\r
+\r
+ @param SenseData Pointer to sense data.\r
+ @param SenseCounts Count of sense data.\r
+\r
+ @retval TRUE There is media change event.\r
+ @retval FALSE media is NOT changed.\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaChange (\r
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+ IN UINTN SenseCounts\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Pei USB ATATPI command implementations.\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbBotPeim.h"\r
+#include "BotPeim.h"\r
+\r
+#define MAXSENSEKEY 5\r
+\r
+/**\r
+ Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r
+ return INQUIRY data of the device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS Inquiry command completes successfully.\r
+ @retval EFI_DEVICE_ERROR Inquiry command failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbInquiry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ )\r
+{\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ EFI_STATUS Status;\r
+ ATAPI_INQUIRY_DATA Idata;\r
+\r
+ //\r
+ // fill command packet\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));\r
+\r
+ Packet.Inquiry.opcode = ATA_CMD_INQUIRY;\r
+ Packet.Inquiry.page_code = 0;\r
+ Packet.Inquiry.allocation_length = 36;\r
+\r
+ //\r
+ // Send scsi INQUIRY command packet.\r
+ // According to SCSI Primary Commands-2 spec, host only needs to\r
+ // retrieve the first 36 bytes for standard INQUIRY data.\r
+ //\r
+ Status = PeiAtapiCommand (\r
+ PeiServices,\r
+ PeiBotDevice,\r
+ &Packet,\r
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+ &Idata,\r
+ 36,\r
+ EfiUsbDataIn,\r
+ 2000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if ((Idata.peripheral_type & 0x1f) == 0x05) {\r
+ PeiBotDevice->DeviceType = USBCDROM;\r
+ PeiBotDevice->Media.BlockSize = 0x800;\r
+ } else {\r
+ PeiBotDevice->DeviceType = USBFLOPPY;\r
+ PeiBotDevice->Media.BlockSize = 0x200;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+ to find out whether device is accessible.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS TestUnit command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbTestUnitReady (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ )\r
+{\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // fill command packet\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;\r
+\r
+ //\r
+ // send command packet\r
+ //\r
+ Status = PeiAtapiCommand (\r
+ PeiServices,\r
+ PeiBotDevice,\r
+ &Packet,\r
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+ NULL,\r
+ 0,\r
+ EfiUsbNoData,\r
+ 2000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Request Sense Packet Command to the specified device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+ @param SenseCounts Length of sense buffer.\r
+ @param SenseKeyBuffer Pointer to sense buffer.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRequestSense (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice,\r
+ OUT UINTN *SenseCounts,\r
+ IN UINT8 *SenseKeyBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ UINT8 *Ptr;\r
+ BOOLEAN SenseReq;\r
+ ATAPI_REQUEST_SENSE_DATA *Sense;\r
+\r
+ *SenseCounts = 0;\r
+\r
+ //\r
+ // fill command packet for Request Sense Packet Command\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;\r
+ Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);\r
+\r
+ Ptr = SenseKeyBuffer;\r
+\r
+ SenseReq = TRUE;\r
+\r
+ //\r
+ // request sense data from device continuously\r
+ // until no sense data exists in the device.\r
+ //\r
+ while (SenseReq) {\r
+ Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;\r
+\r
+ //\r
+ // send out Request Sense Packet Command and get one Sense\r
+ // data form device.\r
+ //\r
+ Status = PeiAtapiCommand (\r
+ PeiServices,\r
+ PeiBotDevice,\r
+ &Packet,\r
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+ (VOID *) Ptr,\r
+ sizeof (ATAPI_REQUEST_SENSE_DATA),\r
+ EfiUsbDataIn,\r
+ 2000\r
+ );\r
+\r
+ //\r
+ // failed to get Sense data\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ if (*SenseCounts == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ if (Sense->sense_key != ATA_SK_NO_SENSE) {\r
+\r
+ Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);\r
+ //\r
+ // Ptr is byte based pointer\r
+ //\r
+ (*SenseCounts)++;\r
+\r
+ if (*SenseCounts == MAXSENSEKEY) {\r
+ break;\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // when no sense key, skip out the loop\r
+ //\r
+ SenseReq = FALSE;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Read Capacity Packet Command to the specified device.\r
+ This command will return the information regarding the capacity of the\r
+ media in the device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadCapacity (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ ATAPI_READ_CAPACITY_DATA Data;\r
+\r
+ ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+\r
+ Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
+\r
+ //\r
+ // send command packet\r
+ //\r
+ Status = PeiAtapiCommand (\r
+ PeiServices,\r
+ PeiBotDevice,\r
+ &Packet,\r
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+ (VOID *) &Data,\r
+ sizeof (ATAPI_READ_CAPACITY_DATA),\r
+ EfiUsbDataIn,\r
+ 2000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ PeiBotDevice->Media.LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;\r
+\r
+ PeiBotDevice->Media.MediaPresent = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Read Format Capacity Data Command to the specified device.\r
+ This command will return the information regarding the capacity of the\r
+ media in the device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbReadFormattedCapacity (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
+\r
+ ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+\r
+ Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;\r
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
+\r
+ //\r
+ // send command packet\r
+ //\r
+ Status = PeiAtapiCommand (\r
+ PeiServices,\r
+ PeiBotDevice,\r
+ &Packet,\r
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+ (VOID *) &FormatData,\r
+ sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r
+ EfiUsbDataIn,\r
+ 2000\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (FormatData.DesCode == 3) {\r
+ //\r
+ // Media is not present\r
+ //\r
+ PeiBotDevice->Media.MediaPresent = FALSE;\r
+ PeiBotDevice->Media.LastBlock = 0;\r
+\r
+ } else {\r
+\r
+ PeiBotDevice->Media.LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;\r
+\r
+ PeiBotDevice->Media.LastBlock--;\r
+\r
+ PeiBotDevice->Media.MediaPresent = TRUE;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Execute Read(10) ATAPI command on a specific SCSI target.\r
+\r
+ Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
+ @param Buffer The pointer to data buffer.\r
+ @param Lba The start logic block address of reading.\r
+ @param NumberOfBlocks The block number of reading.\r
+\r
+ @retval EFI_SUCCESS Command executed successfully.\r
+ @retval EFI_DEVICE_ERROR Some device errors happen.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbRead10 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDevice,\r
+ IN VOID *Buffer,\r
+ IN EFI_PEI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ ATAPI_READ10_CMD *Read10Packet;\r
+ UINT16 MaxBlock;\r
+ UINT16 BlocksRemaining;\r
+ UINT16 SectorCount;\r
+ UINT32 Lba32;\r
+ UINT32 BlockSize;\r
+ UINT32 ByteCount;\r
+ VOID *PtrBuffer;\r
+ EFI_STATUS Status;\r
+ UINT16 TimeOut;\r
+\r
+ //\r
+ // prepare command packet for the Inquiry Packet Command.\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Read10Packet = &Packet.Read10;\r
+ Lba32 = (UINT32) Lba;\r
+ PtrBuffer = Buffer;\r
+\r
+ BlockSize = (UINT32) PeiBotDevice->Media.BlockSize;\r
+\r
+ MaxBlock = (UINT16) (65535 / BlockSize);\r
+ BlocksRemaining = (UINT16) NumberOfBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining <= MaxBlock) {\r
+\r
+ SectorCount = BlocksRemaining;\r
+\r
+ } else {\r
+\r
+ SectorCount = MaxBlock;\r
+ }\r
+ //\r
+ // fill the Packet data structure\r
+ //\r
+ Read10Packet->opcode = ATA_CMD_READ_10;\r
+\r
+ //\r
+ // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
+ // Lba0 is MSB, Lba3 is LSB\r
+ //\r
+ Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
+ Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
+ Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
+ Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
+\r
+ //\r
+ // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
+ // TranLen0 is MSB, TranLen is LSB\r
+ //\r
+ Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
+ Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
+\r
+ ByteCount = SectorCount * BlockSize;\r
+\r
+ TimeOut = (UINT16) (SectorCount * 2000);\r
+\r
+ //\r
+ // send command packet\r
+ //\r
+ Status = PeiAtapiCommand (\r
+ PeiServices,\r
+ PeiBotDevice,\r
+ &Packet,\r
+ (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
+ (VOID *) PtrBuffer,\r
+ ByteCount,\r
+ EfiUsbDataIn,\r
+ TimeOut\r
+ );\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ Lba32 += SectorCount;\r
+ PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
+ BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/** \r
+ Check if there is media according to sense data.\r
+\r
+ @param SenseData Pointer to sense data.\r
+ @param SenseCounts Count of sense data.\r
+\r
+ @retval TRUE No media\r
+ @retval FALSE Media exists\r
+\r
+**/\r
+BOOLEAN\r
+IsNoMedia (\r
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+ IN UINTN SenseCounts\r
+ )\r
+{\r
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
+ UINTN Index;\r
+ BOOLEAN NoMedia;\r
+\r
+ NoMedia = FALSE;\r
+ SensePtr = SenseData;\r
+\r
+ for (Index = 0; Index < SenseCounts; Index++) {\r
+\r
+ switch (SensePtr->sense_key) {\r
+\r
+ case ATA_SK_NOT_READY:\r
+ switch (SensePtr->addnl_sense_code) {\r
+ //\r
+ // if no media, fill IdeDev parameter with specific info.\r
+ //\r
+ case ATA_ASC_NO_MEDIA:\r
+ NoMedia = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ SensePtr++;\r
+ }\r
+\r
+ return NoMedia;\r
+}\r
+\r
+/** \r
+ Check if there is media error according to sense data.\r
+\r
+ @param SenseData Pointer to sense data.\r
+ @param SenseCounts Count of sense data.\r
+\r
+ @retval TRUE Media error\r
+ @retval FALSE No media error\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaError (\r
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+ IN UINTN SenseCounts\r
+ )\r
+{\r
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
+ UINTN Index;\r
+ BOOLEAN Error;\r
+\r
+ SensePtr = SenseData;\r
+ Error = FALSE;\r
+\r
+ for (Index = 0; Index < SenseCounts; Index++) {\r
+\r
+ switch (SensePtr->sense_key) {\r
+ //\r
+ // Medium error case\r
+ //\r
+ case ATA_SK_MEDIUM_ERROR:\r
+ switch (SensePtr->addnl_sense_code) {\r
+ case ATA_ASC_MEDIA_ERR1:\r
+ //\r
+ // fall through\r
+ //\r
+ case ATA_ASC_MEDIA_ERR2:\r
+ //\r
+ // fall through\r
+ //\r
+ case ATA_ASC_MEDIA_ERR3:\r
+ //\r
+ // fall through\r
+ //\r
+ case ATA_ASC_MEDIA_ERR4:\r
+ Error = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // Medium upside-down case\r
+ //\r
+ case ATA_SK_NOT_READY:\r
+ switch (SensePtr->addnl_sense_code) {\r
+ case ATA_ASC_MEDIA_UPSIDE_DOWN:\r
+ Error = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ SensePtr++;\r
+ }\r
+\r
+ return Error;\r
+}\r
+\r
+/** \r
+ Check if media is changed according to sense data.\r
+\r
+ @param SenseData Pointer to sense data.\r
+ @param SenseCounts Count of sense data.\r
+\r
+ @retval TRUE There is media change event.\r
+ @retval FALSE media is NOT changed.\r
+\r
+**/\r
+BOOLEAN\r
+IsMediaChange (\r
+ IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
+ IN UINTN SenseCounts\r
+ )\r
+{\r
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
+ UINTN Index;\r
+ BOOLEAN MediaChange;\r
+\r
+ MediaChange = FALSE;\r
+\r
+ SensePtr = SenseData;\r
+\r
+ for (Index = 0; Index < SenseCounts; Index++) {\r
+ //\r
+ // catch media change sense key and addition sense data\r
+ //\r
+ switch (SensePtr->sense_key) {\r
+ case ATA_SK_UNIT_ATTENTION:\r
+ switch (SensePtr->addnl_sense_code) {\r
+ case ATA_ASC_MEDIA_CHANGE:\r
+ MediaChange = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ SensePtr++;\r
+ }\r
+\r
+ return MediaChange;\r
+}\r
--- /dev/null
+/** @file\r
+Common Libarary for PEI USB.\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+/**\r
+ Get a given usb descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Request Value.\r
+ @param Index Request Index.\r
+ @param DescriptorLength Request descriptor Length.\r
+ @param Descriptor Request descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 Value,\r
+ IN UINT16 Index,\r
+ IN UINT16 DescriptorLength,\r
+ OUT VOID *Descriptor\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+\r
+ ASSERT (UsbIoPpi != NULL);\r
+\r
+ DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;\r
+ DevReq.Request = USB_DEV_GET_DESCRIPTOR;\r
+ DevReq.Value = Value;\r
+ DevReq.Index = Index;\r
+ DevReq.Length = DescriptorLength;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ Descriptor,\r
+ DescriptorLength\r
+ );\r
+}\r
+\r
+/**\r
+ Set a usb device with a specified address.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param AddressValue The address to assign.\r
+\r
+ @retval EFI_SUCCESS Usb device address is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 AddressValue\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+\r
+ ASSERT (UsbIoPpi != NULL);\r
+\r
+ DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE;\r
+ DevReq.Request = USB_DEV_SET_ADDRESS;\r
+ DevReq.Value = AddressValue;\r
+ DevReq.Index = 0;\r
+ DevReq.Length = 0;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear a given usb feature.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+ @param Value Request Value.\r
+ @param Target Request Index.\r
+\r
+ @retval EFI_SUCCESS Usb feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN EFI_USB_RECIPIENT Recipient,\r
+ IN UINT16 Value,\r
+ IN UINT16 Target\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+\r
+ ASSERT (UsbIoPpi != NULL);\r
+\r
+ switch (Recipient) {\r
+ case EfiUsbDevice:\r
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;\r
+ break;\r
+\r
+ case EfiUsbInterface:\r
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;\r
+ break;\r
+\r
+ case EfiUsbEndpoint:\r
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;\r
+ break;\r
+ }\r
+\r
+ DevReq.Request = USB_DEV_CLEAR_FEATURE;\r
+ DevReq.Value = Value;\r
+ DevReq.Index = Target;\r
+ DevReq.Length = 0;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Configure a usb device to Configuration 1.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE;\r
+ DevReq.Request = USB_DEV_SET_CONFIGURATION;\r
+ DevReq.Value = 1;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear Endpoint Halt.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointAddress The endpoint address.\r
+\r
+ @retval EFI_SUCCESS Endpoint halt is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 EndpointAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;\r
+ UINT8 EndpointIndex;\r
+\r
+ EndpointIndex = 0;\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (UsbIoPpi);\r
+\r
+ while (EndpointIndex < MAX_ENDPOINT) {\r
+ Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (EndpointDescriptor->EndpointAddress == EndpointAddress) {\r
+ break;\r
+ }\r
+\r
+ EndpointIndex++;\r
+ }\r
+\r
+ if (EndpointIndex == MAX_ENDPOINT) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = PeiUsbClearDeviceFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ EfiUsbEndpoint,\r
+ EfiUsbEndpointHalt,\r
+ EndpointAddress\r
+ );\r
+\r
+ //\r
+ // set data toggle to zero.\r
+ //\r
+ if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {\r
+ PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Judge if the port is connected with a usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A usb device is connected with the port.\r
+ @retval FALSE No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+ IN UINT16 PortStatus\r
+ )\r
+{\r
+ //\r
+ // return the bit 0 value of PortStatus\r
+ //\r
+ if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Judge if the port is connected with a low-speed usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A low-speed usb device is connected with the port.\r
+ @retval FALSE No low-speed usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortLowSpeedDeviceAttached (\r
+ IN UINT16 PortStatus\r
+ )\r
+{\r
+ //\r
+ // return the bit 9 value of PortStatus\r
+ //\r
+ if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Judge if the port is in "connection change" status or not.\r
+\r
+ @param PortChangeStatus The usb port change status gotten.\r
+\r
+ @retval TRUE The port is in "connection change" status.\r
+ @retval FALSE The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+ IN UINT16 PortChangeStatus\r
+ )\r
+{\r
+ //\r
+ // return the bit 0 value of PortChangeStatus\r
+ //\r
+ if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Common Libarary for PEI USB.\r
+\r
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_LIB_H_\r
+#define _PEI_USB_LIB_H_\r
+//\r
+// Standard device request and request type\r
+// By [Spec-USB20/Chapter-9.4]\r
+//\r
+#define USB_DEV_GET_STATUS 0x00\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_D 0x80 // Receiver : Device\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_I 0x81 // Receiver : Interface\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_E 0x82 // Receiver : Endpoint\r
+\r
+#define USB_DEV_CLEAR_FEATURE 0x01\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint\r
+\r
+#define USB_DEV_SET_FEATURE 0x03\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint\r
+ \r
+#define USB_DEV_SET_ADDRESS 0x05\r
+#define USB_DEV_SET_ADDRESS_REQ_TYPE 0x00\r
+\r
+#define USB_DEV_GET_DESCRIPTOR 0x06\r
+#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE 0x80\r
+\r
+#define USB_DEV_SET_DESCRIPTOR 0x07\r
+#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE 0x00\r
+\r
+#define USB_DEV_GET_CONFIGURATION 0x08\r
+#define USB_DEV_GET_CONFIGURATION_REQ_TYPE 0x80\r
+\r
+#define USB_DEV_SET_CONFIGURATION 0x09\r
+#define USB_DEV_SET_CONFIGURATION_REQ_TYPE 0x00\r
+\r
+#define USB_DEV_GET_INTERFACE 0x0A\r
+#define USB_DEV_GET_INTERFACE_REQ_TYPE 0x81\r
+\r
+#define USB_DEV_SET_INTERFACE 0x0B\r
+#define USB_DEV_SET_INTERFACE_REQ_TYPE 0x01\r
+\r
+#define USB_DEV_SYNCH_FRAME 0x0C\r
+#define USB_DEV_SYNCH_FRAME_REQ_TYPE 0x82\r
+\r
+//\r
+// USB Descriptor types\r
+//\r
+#define USB_DT_DEVICE 0x01\r
+#define USB_DT_CONFIG 0x02\r
+#define USB_DT_STRING 0x03\r
+#define USB_DT_INTERFACE 0x04\r
+#define USB_DT_ENDPOINT 0x05\r
+#define USB_DT_HUB 0x29\r
+#define USB_DT_HID 0x21\r
+\r
+//\r
+// USB request type\r
+//\r
+#define USB_TYPE_STANDARD (0x00 << 5)\r
+#define USB_TYPE_CLASS (0x01 << 5)\r
+#define USB_TYPE_VENDOR (0x02 << 5)\r
+#define USB_TYPE_RESERVED (0x03 << 5)\r
+\r
+//\r
+// USB request targer device\r
+//\r
+#define USB_RECIP_DEVICE 0x00\r
+#define USB_RECIP_INTERFACE 0x01\r
+#define USB_RECIP_ENDPOINT 0x02\r
+#define USB_RECIP_OTHER 0x03\r
+\r
+typedef enum {\r
+ EfiUsbEndpointHalt,\r
+ EfiUsbDeviceRemoteWakeup\r
+} EFI_USB_STANDARD_FEATURE_SELECTOR;\r
+\r
+//\r
+// Usb Data recipient type\r
+//\r
+typedef enum {\r
+ EfiUsbDevice,\r
+ EfiUsbInterface,\r
+ EfiUsbEndpoint\r
+} EFI_USB_RECIPIENT;\r
+\r
+/**\r
+ Get a given usb descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Request Value.\r
+ @param Index Request Index.\r
+ @param DescriptorLength Request descriptor Length.\r
+ @param Descriptor Request descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 Value,\r
+ IN UINT16 Index,\r
+ IN UINT16 DescriptorLength,\r
+ OUT VOID *Descriptor\r
+ );\r
+\r
+/**\r
+ Set a usb device with a specified address.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param AddressValue The address to assign.\r
+\r
+ @retval EFI_SUCCESS Usb device address is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 AddressValue\r
+ );\r
+\r
+/**\r
+ Clear a given usb feature.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+ @param Value Request Value.\r
+ @param Target Request Index.\r
+\r
+ @retval EFI_SUCCESS Usb feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN EFI_USB_RECIPIENT Recipient,\r
+ IN UINT16 Value,\r
+ IN UINT16 Target\r
+ );\r
+\r
+/**\r
+ Configure a usb device to Configuration 1.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ );\r
+\r
+/**\r
+ Clear Endpoint Halt.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointAddress The endpoint address.\r
+\r
+ @retval EFI_SUCCESS Endpoint halt is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 EndpointAddress\r
+ );\r
+\r
+/**\r
+ Judge if the port is connected with a usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A usb device is connected with the port.\r
+ @retval FALSE No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+ IN UINT16 PortStatus\r
+ );\r
+\r
+/**\r
+ Judge if the port is connected with a low-speed usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A low-speed usb device is connected with the port.\r
+ @retval FALSE No low-speed usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortLowSpeedDeviceAttached (\r
+ IN UINT16 PortStatus\r
+ );\r
+\r
+/**\r
+ Judge if the port is in "connection change" status or not.\r
+\r
+ @param PortChangeStatus The usb port change status gotten.\r
+\r
+ @retval TRUE The port is in "connection change" status.\r
+ @retval FALSE The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+ IN UINT16 PortChangeStatus\r
+ );\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for UsbBotPei module.\r
+#\r
+# Usb mass storage device Peim driver to support recovery from USB device.\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution. The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = UsbBotPei\r
+ FILE_GUID = 8401A046-6F70-4505-8471-7015B40355E3\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = PeimInitializeUsbBot\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ PeiUsbLib.c\r
+ PeiAtapi.c\r
+ BotPeim.c\r
+ UsbBotPeim.c\r
+ UsbPeim.h\r
+ UsbBotPeim.h\r
+ PeiUsbLib.h\r
+ BotPeim.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ BaseMemoryLib\r
+ PeiServicesLib\r
+ PeimEntryPoint\r
+ DebugLib\r
+ PcdLib\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue\r
+\r
+[Ppis]\r
+ gEfiPeiVirtualBlockIoPpiGuid # PPI ALWAYS_PRODUCED\r
+ gPeiUsbIoPpiGuid # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbIoPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbBotPeim.h"\r
+#include "BotPeim.h"\r
+\r
+//\r
+// Global function\r
+//\r
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {\r
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+ &gPeiUsbIoPpiGuid,\r
+ NotifyOnUsbIoPpi\r
+};\r
+\r
+EFI_PEI_RECOVERY_BLOCK_IO_PPI mRecoveryBlkIoPpi = {\r
+ BotGetNumberOfBlockDevices,\r
+ BotGetMediaInfo,\r
+ BotReadBlocks\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ NULL\r
+};\r
+\r
+/**\r
+ Detect whether the removable media is present and whether it has changed.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM.\r
+ @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS The media status is successfully checked.\r
+ @retval Other Failed to detect media.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiBotDetectMedia (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev\r
+ );\r
+\r
+/**\r
+ Initializes the Usb Bot. \r
+ \r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeUsbBot (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN UsbIoPpiInstance;\r
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // locate all usb io PPIs\r
+ //\r
+ for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) {\r
+\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbIoPpiGuid,\r
+ UsbIoPpiInstance,\r
+ &TempPpiDescriptor,\r
+ (VOID **) &UsbIoPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Register a notify function\r
+ //\r
+ return PeiServicesNotifyPpi (&mNotifyList);\r
+}\r
+\r
+/**\r
+ UsbIo installation notification function. \r
+ \r
+ This function finds out all the current USB IO PPIs in the system and add them\r
+ into private data.\r
+\r
+ @param PeiServices Indirect reference to the PEI Services Table.\r
+ @param NotifyDesc Address of the notification descriptor data structure.\r
+ @param InvokePpi Address of the PPI that was invoked.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnUsbIoPpi (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
+ IN VOID *InvokePpi\r
+ )\r
+{\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+\r
+ UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi;\r
+\r
+ InitUsbBot (PeiServices, UsbIoPpi);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize the usb bot device.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM.\r
+ @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS The usb bot device is initialized successfully.\r
+ @retval Other Failed to initialize media.\r
+\r
+**/\r
+EFI_STATUS\r
+InitUsbBot (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ )\r
+{\r
+ PEI_BOT_DEVICE *PeiBotDevice;\r
+ EFI_STATUS Status;\r
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc;\r
+ UINTN MemPages;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc;\r
+ UINT8 Index;\r
+\r
+ //\r
+ // Check its interface\r
+ //\r
+ Status = UsbIoPpi->UsbGetInterfaceDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &InterfaceDesc\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Check if it is the BOT device we support\r
+ //\r
+ if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) {\r
+\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiBotDevice = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress);\r
+\r
+ PeiBotDevice->Signature = PEI_BOT_DEVICE_SIGNATURE;\r
+ PeiBotDevice->UsbIoPpi = UsbIoPpi;\r
+ PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress;\r
+ PeiBotDevice->BotInterface = InterfaceDesc;\r
+\r
+ //\r
+ // Default value\r
+ //\r
+ PeiBotDevice->Media.DeviceType = UsbMassStorage;\r
+ PeiBotDevice->Media.BlockSize = 0x200;\r
+\r
+ //\r
+ // Check its Bulk-in/Bulk-out endpoint\r
+ //\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = UsbIoPpi->UsbGetEndpointDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ Index,\r
+ &EndpointDesc\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((EndpointDesc->EndpointAddress & 0x80) != 0) {\r
+ PeiBotDevice->BulkInEndpoint = EndpointDesc;\r
+ } else {\r
+ PeiBotDevice->BulkOutEndpoint = EndpointDesc;\r
+ }\r
+ }\r
+\r
+ CopyMem (\r
+ &(PeiBotDevice->BlkIoPpi),\r
+ &mRecoveryBlkIoPpi,\r
+ sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI)\r
+ );\r
+ CopyMem (\r
+ &(PeiBotDevice->BlkIoPpiList),\r
+ &mPpiList,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ PeiBotDevice->BlkIoPpiList.Ppi = &PeiBotDevice->BlkIoPpi;\r
+\r
+ Status = PeiUsbInquiry (PeiServices, PeiBotDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ 1,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress);\r
+\r
+ Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one \r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process. \r
+ To the PEI legacy floppy driver, it returns the number of all the legacy \r
+ devices it finds during its enumeration process. If no device is detected, \r
+ then the function will return zero. \r
+ \r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI \r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS Operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetNumberOfBlockDevices (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ //\r
+ // For Usb devices, this value should be always 1\r
+ //\r
+ *NumberBlockDevices = 1;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media \r
+ information. If the media changes, calling this function will update the media \r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants \r
+ to talk. Because the driver that implements Block I/O \r
+ PPIs will manage multiple block devices, the PPIs that \r
+ want to talk to a single device must specify the \r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to \r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media. \r
+ The caller is responsible for the ownership of this \r
+ data structure.\r
+ \r
+ @retval EFI_SUCCESS Media information about the specified block device \r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware \r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ )\r
+{\r
+ PEI_BOT_DEVICE *PeiBotDev;\r
+ EFI_STATUS Status;\r
+\r
+ PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);\r
+\r
+ //\r
+ // First test unit ready\r
+ //\r
+ PeiUsbTestUnitReady (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+\r
+ Status = PeiBotDetectMedia (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (\r
+ MediaInfo,\r
+ &(PeiBotDev->Media),\r
+ sizeof (EFI_PEI_BLOCK_IO_MEDIA)\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the \r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to \r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants \r
+ to talk. Because the driver that implements Block I/O \r
+ PPIs will manage multiple block devices, the PPIs that \r
+ want to talk to a single device must specify the device \r
+ index that was assigned during the enumeration process. \r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the \r
+ buffer.\r
+ \r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting \r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not \r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ PEI_BOT_DEVICE *PeiBotDev;\r
+ EFI_STATUS Status;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+ PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);\r
+\r
+ //\r
+ // Check parameters\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!PeiBotDev->Media.MediaPresent) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ BlockSize = PeiBotDev->Media.BlockSize;\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (StartLBA > PeiBotDev->Media.LastBlock) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+\r
+ Status = PeiUsbTestUnitReady (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ Status = PeiUsbRead10 (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ Buffer,\r
+ StartLBA,\r
+ 1\r
+ );\r
+ }\r
+ } else {\r
+ //\r
+ // To generate sense data for DetectMedia use.\r
+ //\r
+ PeiUsbTestUnitReady (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // if any error encountered, detect what happened to the media and\r
+ // update the media info accordingly.\r
+ //\r
+ Status = PeiBotDetectMedia (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+ if (Status != EFI_SUCCESS) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize;\r
+\r
+ if (!(PeiBotDev->Media.MediaPresent)) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (StartLBA > PeiBotDev->Media.LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media.LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = PeiUsbRead10 (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ Buffer,\r
+ StartLBA,\r
+ NumberOfBlocks\r
+ );\r
+\r
+ switch (Status) {\r
+\r
+ case EFI_SUCCESS:\r
+ return EFI_SUCCESS;\r
+\r
+ default:\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ } else {\r
+ StartLBA += 1;\r
+ NumberOfBlocks -= 1;\r
+ Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize;\r
+\r
+ if (NumberOfBlocks == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = PeiUsbRead10 (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ Buffer,\r
+ StartLBA,\r
+ NumberOfBlocks\r
+ );\r
+ switch (Status) {\r
+\r
+ case EFI_SUCCESS:\r
+ return EFI_SUCCESS;\r
+\r
+ default:\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Detect whether the removable media is present and whether it has changed.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM.\r
+ @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS The media status is successfully checked.\r
+ @retval Other Failed to detect media.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiBotDetectMedia (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS FloppyStatus;\r
+ UINTN SenseCounts;\r
+ BOOLEAN NeedReadCapacity;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
+ UINTN Retry;\r
+\r
+ //\r
+ // if there is no media present,or media not changed,\r
+ // the request sense command will detect faster than read capacity command.\r
+ // read capacity command can be bypassed, thus improve performance.\r
+ //\r
+ SenseCounts = 0;\r
+ NeedReadCapacity = TRUE;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ 1,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SensePtr = PeiBotDev->SensePtr;\r
+ ZeroMem (SensePtr, EFI_PAGE_SIZE);\r
+\r
+ Status = PeiUsbRequestSense (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ &SenseCounts,\r
+ (UINT8 *) SensePtr\r
+ );\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // No Media\r
+ //\r
+ if (IsNoMedia (SensePtr, SenseCounts)) {\r
+ NeedReadCapacity = FALSE;\r
+ PeiBotDev->Media.MediaPresent = FALSE;\r
+ PeiBotDev->Media.LastBlock = 0;\r
+ } else {\r
+ //\r
+ // Media Changed\r
+ //\r
+ if (IsMediaChange (SensePtr, SenseCounts)) {\r
+ PeiBotDev->Media.MediaPresent = TRUE;\r
+ }\r
+ //\r
+ // Media Error\r
+ //\r
+ if (IsMediaError (SensePtr, SenseCounts)) {\r
+ //\r
+ // if media error encountered, make it look like no media present.\r
+ //\r
+ PeiBotDev->Media.MediaPresent = FALSE;\r
+ PeiBotDev->Media.LastBlock = 0;\r
+ }\r
+\r
+ }\r
+\r
+ }\r
+\r
+ if (NeedReadCapacity) {\r
+ //\r
+ // Retry at most 4 times to detect media info\r
+ //\r
+ for (Retry = 0; Retry < 4; Retry++) {\r
+ switch (PeiBotDev->DeviceType) {\r
+ case USBCDROM:\r
+ Status = PeiUsbReadCapacity (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+ break;\r
+\r
+ case USBFLOPPY2:\r
+ Status = PeiUsbReadFormattedCapacity (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+ if (EFI_ERROR(Status)||\r
+ !PeiBotDev->Media.MediaPresent) {\r
+ //\r
+ // retry the ReadCapacity command\r
+ //\r
+ PeiBotDev->DeviceType = USBFLOPPY;\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case USBFLOPPY:\r
+ Status = PeiUsbReadCapacity (\r
+ PeiServices,\r
+ PeiBotDev\r
+ );\r
+ //\r
+ // retry the ReadFormatCapacity command\r
+ //\r
+ PeiBotDev->DeviceType = USBFLOPPY2;\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SenseCounts = 0;\r
+ ZeroMem (SensePtr, EFI_PAGE_SIZE);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ break;\r
+ }\r
+\r
+ FloppyStatus = PeiUsbRequestSense (\r
+ PeiServices,\r
+ PeiBotDev,\r
+ &SenseCounts,\r
+ (UINT8 *) SensePtr\r
+ );\r
+\r
+ //\r
+ // If Request Sense data failed,retry.\r
+ //\r
+ if (EFI_ERROR (FloppyStatus)) {\r
+ continue;\r
+ }\r
+ //\r
+ // No Media\r
+ //\r
+ if (IsNoMedia (SensePtr, SenseCounts)) {\r
+ PeiBotDev->Media.MediaPresent = FALSE;\r
+ PeiBotDev->Media.LastBlock = 0;\r
+ break;\r
+ }\r
+\r
+ if (IsMediaError (SensePtr, SenseCounts)) {\r
+ //\r
+ // if media error encountered, make it look like no media present.\r
+ //\r
+ PeiBotDev->Media.MediaPresent = FALSE;\r
+ PeiBotDev->Media.LastBlock = 0;\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // ENDFOR\r
+ //\r
+ // tell whether the readcapacity process is successful or not\r
+ // ("Status" variable record the latest status returned\r
+ // by ReadCapacity )\r
+ //\r
+ if (Status != EFI_SUCCESS) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+Usb BOT Peim definition.\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_BOT_PEIM_H_\r
+#define _PEI_USB_BOT_PEIM_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbIo.h>\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+\r
+#include <IndustryStandard/Usb.h>\r
+#include <IndustryStandard/Atapi.h>\r
+\r
+#define PEI_FAT_MAX_USB_IO_PPI 127\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one \r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process. \r
+ To the PEI legacy floppy driver, it returns the number of all the legacy \r
+ devices it finds during its enumeration process. If no device is detected, \r
+ then the function will return zero. \r
+ \r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI \r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS Operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetNumberOfBlockDevices (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media \r
+ information. If the media changes, calling this function will update the media \r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants \r
+ to talk. Because the driver that implements Block I/O \r
+ PPIs will manage multiple block devices, the PPIs that \r
+ want to talk to a single device must specify the \r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to \r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media. \r
+ The caller is responsible for the ownership of this \r
+ data structure.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device \r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware \r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the \r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to \r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants \r
+ to talk. Because the driver that implements Block I/O \r
+ PPIs will manage multiple block devices, the PPIs that \r
+ want to talk to a single device must specify the device \r
+ index that was assigned during the enumeration process. \r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the \r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting \r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not \r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BotReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ UsbIo installation notification function. \r
+ \r
+ This function finds out all the current USB IO PPIs in the system and add them\r
+ into private data.\r
+\r
+ @param PeiServices Indirect reference to the PEI Services Table.\r
+ @param NotifyDesc Address of the notification descriptor data structure.\r
+ @param InvokePpi Address of the PPI that was invoked.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnUsbIoPpi (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
+ IN VOID *InvokePpi\r
+ );\r
+\r
+/**\r
+ Initialize the usb bot device.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM.\r
+ @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS The usb bot device is initialized successfully.\r
+ @retval Other Failed to initialize media.\r
+\r
+**/\r
+EFI_STATUS\r
+InitUsbBot (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ );\r
+\r
+#define USBCDROM 1 // let the device type value equal to USBCDROM, which is defined by PI spec.\r
+ // Therefore the CdExpressPei module can do recovery on UsbCdrom.\r
+#define USBFLOPPY 2 // for those that use ReadCapacity(0x25) command to retrieve media capacity\r
+#define USBFLOPPY2 3 // for those that use ReadFormatCapacity(0x23) command to retrieve media capacity\r
+\r
+//\r
+// Bot device structure\r
+//\r
+#define PEI_BOT_DEVICE_SIGNATURE SIGNATURE_32 ('U', 'B', 'O', 'T')\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ EFI_USB_INTERFACE_DESCRIPTOR *BotInterface;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;\r
+ UINTN AllocateAddress;\r
+ UINTN DeviceType;\r
+ ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
+} PEI_BOT_DEVICE;\r
+\r
+#define PEI_BOT_DEVICE_FROM_THIS(a) CR (a, PEI_BOT_DEVICE, BlkIoPpi, PEI_BOT_DEVICE_SIGNATURE)\r
+\r
+/**\r
+ Send ATAPI command using BOT protocol.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.\r
+ @param Command The command to be sent to ATAPI device.\r
+ @param CommandSize The length of the data to be sent.\r
+ @param DataBuffer The pointer to the data.\r
+ @param BufferLength The length of the data.\r
+ @param Direction The direction of the data.\r
+ @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.\r
+ @retval EFI_SUCCESS Failed to get the status of device.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiAtapiCommand (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_BOT_DEVICE *PeiBotDev,\r
+ IN VOID *Command,\r
+ IN UINT8 CommandSize,\r
+ IN VOID *DataBuffer,\r
+ IN UINT32 BufferLength,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT16 TimeOutInMilliSeconds\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Usb Peim definition.\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_PEIM_H_\r
+#define _PEI_USB_PEIM_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbIo.h>\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <IndustryStandard/Usb.h>\r
+\r
+#define MAX_ROOT_PORT 2\r
+#define MAX_ENDPOINT 16\r
+\r
+#define USB_SLOW_SPEED_DEVICE 0x01\r
+#define USB_FULL_SPEED_DEVICE 0x02\r
+\r
+#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D')\r
+typedef struct {\r
+ UINTN Signature;\r
+ PEI_USB_IO_PPI UsbIoPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList;\r
+ UINT8 DeviceAddress;\r
+ UINT8 MaxPacketSize0;\r
+ UINT8 DeviceSpeed;\r
+ UINT8 DataToggle;\r
+ UINT8 IsHub;\r
+ UINT8 DownStreamPortNo;\r
+ UINT8 Reserved[2]; // Padding for IPF\r
+ UINTN AllocateAddress;\r
+ PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;\r
+ UINT8 ConfigurationData[1024];\r
+ EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;\r
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT];\r
+} PEI_USB_DEVICE;\r
+\r
+#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)\r
+\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_IO_PPI.\r
+ @param Request USB device request to send.\r
+ @param Direction Specifies the data direction for the data stage.\r
+ @param Timeout Indicates the maximum timeout, in millisecond.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT32 Timeout,\r
+ IN OUT VOID *Data, OPTIONAL\r
+ IN UINTN DataLength OPTIONAL\r
+ );\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_IO_PPI.\r
+ @param DeviceEndpoint Endpoint number and its direction in bit 7.\r
+ @param Data A pointer to the buffer of data to transmit \r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 DeviceEndpoint,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN Timeout\r
+ );\r
+\r
+/**\r
+ Get the usb interface descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+ @param InterfaceDescriptor Request interface descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb interface descriptor is obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetInterfaceDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor\r
+ );\r
+\r
+/**\r
+ Get the usb endpoint descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointIndex The valid index of the specified endpoint.\r
+ @param EndpointDescriptor Request endpoint descriptor.\r
+\r
+ @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully.\r
+ @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetEndpointDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 EndpointIndex,\r
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor\r
+ );\r
+\r
+/**\r
+ Reset the port and re-configure the usb device.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is reset and configured successfully.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbPortReset (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Usb Hub Request Support In PEI Phase\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbPeim.h"\r
+#include "HubPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+/**\r
+ Get a given hub port status.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param PortStatus Current Hub port status and change status.\r
+\r
+ @retval EFI_SUCCESS Port status is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ OUT UINT32 *PortStatus\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_GET_PORT_STATUS;\r
+ DeviceRequest.Index = Port;\r
+ DeviceRequest.Length = (UINT16) sizeof (UINT32);\r
+\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ PortStatus,\r
+ sizeof (UINT32)\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Set specified feature to a given hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param Value New feature value.\r
+\r
+ @retval EFI_SUCCESS Port feature is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE;\r
+ DeviceRequest.Value = Value;\r
+ DeviceRequest.Index = Port;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear specified feature on a given hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param Value Feature value that will be cleared from the hub port.\r
+\r
+ @retval EFI_SUCCESS Port feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT;\r
+ DeviceRequest.Value = Value;\r
+ DeviceRequest.Index = Port;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Get a given hub status.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param HubStatus Current Hub status and change status.\r
+\r
+ @retval EFI_SUCCESS Hub status is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetHubStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ OUT UINT32 *HubStatus\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_GET_HUB_STATUS;\r
+ DeviceRequest.Length = (UINT16) sizeof (UINT32);\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ HubStatus,\r
+ sizeof (UINT32)\r
+ );\r
+}\r
+\r
+/**\r
+ Set specified feature to a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value New feature value.\r
+\r
+ @retval EFI_SUCCESS Port feature is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetHubFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_SET_HUB_FEATURE;\r
+ DeviceRequest.Value = Value;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear specified feature on a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Feature value that will be cleared from the hub port.\r
+\r
+ @retval EFI_SUCCESS Hub feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearHubFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_CLEAR_FEATURE;\r
+ DeviceRequest.Value = Value;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Get a given hub descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param DescriptorSize The length of Hub Descriptor buffer.\r
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
+ successfully returned.\r
+\r
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetHubDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINTN DescriptorSize,\r
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DevReq.RequestType = USB_RT_HUB | 0x80;\r
+ DevReq.Request = USB_HUB_GET_DESCRIPTOR;\r
+ DevReq.Value = USB_DT_HUB << 8;\r
+ DevReq.Length = (UINT16)DescriptorSize;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ HubDescriptor,\r
+ (UINT16)DescriptorSize\r
+ );\r
+}\r
+\r
+/**\r
+ Configure a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicating the hub controller device that will be configured\r
+\r
+ @retval EFI_SUCCESS Hub configuration is done successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiDoHubConfig (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ )\r
+{\r
+ EFI_USB_HUB_DESCRIPTOR HubDescriptor;\r
+ EFI_STATUS Status;\r
+ EFI_USB_HUB_STATUS HubStatus;\r
+ UINTN Index;\r
+ UINT32 PortStatus;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+\r
+ ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+ //\r
+ // First get the hub descriptor length\r
+ //\r
+ Status = PeiGetHubDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ 2,\r
+ &HubDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // First get the whole descriptor, then\r
+ // get the number of hub ports\r
+ //\r
+ Status = PeiGetHubDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ HubDescriptor.Length,\r
+ &HubDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
+\r
+ Status = PeiHubGetHubStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT32 *) &HubStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Get all hub ports status\r
+ //\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+\r
+ Status = PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ &PortStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Power all the hub ports\r
+ //\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+ Status = PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortPower\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Clear Hub Status Change\r
+ //\r
+ Status = PeiHubGetHubStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT32 *) &HubStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // Hub power supply change happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_LOCAL_POWER\r
+ );\r
+ }\r
+ //\r
+ // Hub change overcurrent happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_OVER_CURRENT\r
+ );\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send reset signal over the given root hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param PortNum Usb hub port number (starting from 1).\r
+\r
+**/\r
+VOID\r
+PeiResetHubPort (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 PortNum\r
+ )\r
+{\r
+ UINT8 Try;\r
+ EFI_USB_PORT_STATUS HubPortStatus;\r
+\r
+\r
+ MicroSecondDelay (100 * 1000);\r
+\r
+ //\r
+ // reset root port\r
+ //\r
+ PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+\r
+ Try = 10;\r
+ do {\r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ (UINT32 *) &HubPortStatus\r
+ );\r
+\r
+ MicroSecondDelay (2 * 1000);\r
+ Try -= 1;\r
+ } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+\r
+ //\r
+ // clear reset root port\r
+ //\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+\r
+ MicroSecondDelay (1 * 1000);\r
+\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortConnectChange\r
+ );\r
+\r
+ //\r
+ // Set port enable\r
+ //\r
+ PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortEnable\r
+ );\r
+\r
+ //\r
+ // Clear any change status\r
+ //\r
+\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortEnableChange\r
+ );\r
+\r
+ MicroSecondDelay (10 * 1000);\r
+\r
+ return;\r
+}\r
--- /dev/null
+/** @file\r
+Constants definitions for Usb Hub Peim\r
+\r
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_HUB_PEIM_H_\r
+#define _PEI_HUB_PEIM_H_\r
+\r
+\r
+//\r
+// Hub feature numbers\r
+//\r
+#define C_HUB_LOCAL_POWER 0\r
+#define C_HUB_OVER_CURRENT 1\r
+\r
+//\r
+// Hub class code & sub class code\r
+//\r
+#define CLASS_CODE_HUB 0x09\r
+#define SUB_CLASS_CODE_HUB 0\r
+\r
+//\r
+// Hub Status & Hub Change bit masks\r
+//\r
+#define HUB_STATUS_LOCAL_POWER 0x0001\r
+#define HUB_STATUS_OVERCURRENT 0x0002\r
+\r
+#define HUB_CHANGE_LOCAL_POWER 0x0001\r
+#define HUB_CHANGE_OVERCURRENT 0x0002\r
+\r
+//\r
+// Hub Characteristics\r
+//\r
+#define HUB_CHAR_LPSM 0x0003\r
+#define HUB_CHAR_COMPOUND 0x0004\r
+#define HUB_CHAR_OCPM 0x0018\r
+\r
+//\r
+// Standard hub request and request type\r
+// By [Spec-USB20/Chapter-11.24]\r
+//\r
+#define USB_HUB_CLEAR_FEATURE 0x01\r
+#define USB_HUB_CLEAR_FEATURE_REQ_TYPE 0x20\r
+\r
+#define USB_HUB_CLEAR_FEATURE_PORT 0x01\r
+#define USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23\r
+\r
+#define USB_HUB_GET_BUS_STATE 0x02\r
+#define USB_HUB_GET_BUS_STATE_REQ_TYPE 0xA3\r
+\r
+#define USB_HUB_GET_DESCRIPTOR 0x06\r
+#define USB_HUB_GET_DESCRIPTOR_REQ_TYPE 0xA0\r
+\r
+#define USB_HUB_GET_HUB_STATUS 0x00\r
+#define USB_HUB_GET_HUB_STATUS_REQ_TYPE 0xA0\r
+\r
+#define USB_HUB_GET_PORT_STATUS 0x00\r
+#define USB_HUB_GET_PORT_STATUS_REQ_TYPE 0xA3\r
+\r
+#define USB_HUB_SET_DESCRIPTOR 0x07\r
+#define USB_HUB_SET_DESCRIPTOR_REQ_TYPE 0x20\r
+\r
+#define USB_HUB_SET_HUB_FEATURE 0x03\r
+#define USB_HUB_SET_HUB_FEATURE_REQ_TYPE 0x20\r
+\r
+#define USB_HUB_SET_PORT_FEATURE 0x03\r
+#define USB_HUB_SET_PORT_FEATURE_REQ_TYPE 0x23\r
+\r
+#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE)\r
+#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)\r
+\r
+#define MAXBYTES 8\r
+#pragma pack(1)\r
+//\r
+// Hub descriptor, the last two fields are of variable lenght.\r
+//\r
+typedef struct {\r
+ UINT8 Length;\r
+ UINT8 DescriptorType;\r
+ UINT8 NbrPorts;\r
+ UINT8 HubCharacteristics[2];\r
+ UINT8 PwrOn2PwrGood;\r
+ UINT8 HubContrCurrent;\r
+ UINT8 Filler[MAXBYTES];\r
+} EFI_USB_HUB_DESCRIPTOR;\r
+\r
+typedef struct {\r
+ UINT16 HubStatus;\r
+ UINT16 HubChangeStatus;\r
+} EFI_USB_HUB_STATUS;\r
+\r
+#pragma pack()\r
+/**\r
+ Get a given hub port status.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param PortStatus Current Hub port status and change status.\r
+\r
+ @retval EFI_SUCCESS Port status is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ OUT UINT32 *PortStatus\r
+ );\r
+\r
+/**\r
+ Set specified feature to a given hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param Value New feature value.\r
+\r
+ @retval EFI_SUCCESS Port feature is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ IN UINT8 Value\r
+ );\r
+\r
+/**\r
+ Set specified feature to a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value New feature value.\r
+\r
+ @retval EFI_SUCCESS Port feature is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetHubFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Value\r
+ );\r
+\r
+/**\r
+ Get a given hub status.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param HubStatus Current Hub status and change status.\r
+\r
+ @retval EFI_SUCCESS Hub status is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetHubStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ OUT UINT32 *HubStatus\r
+ );\r
+\r
+/**\r
+ Clear specified feature on a given hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param Value Feature value that will be cleared from the hub port.\r
+\r
+ @retval EFI_SUCCESS Port feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ IN UINT8 Value\r
+ );\r
+\r
+/**\r
+ Clear specified feature on a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Feature value that will be cleared from the hub port.\r
+\r
+ @retval EFI_SUCCESS Hub feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearHubFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Value\r
+ );\r
+\r
+/**\r
+ Get a given hub descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param DescriptorSize The length of Hub Descriptor buffer.\r
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
+ successfully returned.\r
+\r
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetHubDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINTN DescriptorSize,\r
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
+ );\r
+\r
+/**\r
+ Configure a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicating the hub controller device that will be configured\r
+\r
+ @retval EFI_SUCCESS Hub configuration is done successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiDoHubConfig (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ );\r
+\r
+/**\r
+ Send reset signal over the given root hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param PortNum Usb hub port number (starting from 1).\r
+\r
+**/\r
+VOID\r
+PeiResetHubPort (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 PortNum\r
+ );\r
+\r
+#endif\r
+\r
+\r
--- /dev/null
+/** @file\r
+Common Libarary for PEI USB\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. <BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+/**\r
+ Get a given usb descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Request Value.\r
+ @param Index Request Index.\r
+ @param DescriptorLength Request descriptor Length.\r
+ @param Descriptor Request descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 Value,\r
+ IN UINT16 Index,\r
+ IN UINT16 DescriptorLength,\r
+ OUT VOID *Descriptor\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+\r
+ ASSERT (UsbIoPpi != NULL);\r
+\r
+ DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE;\r
+ DevReq.Request = USB_DEV_GET_DESCRIPTOR;\r
+ DevReq.Value = Value;\r
+ DevReq.Index = Index;\r
+ DevReq.Length = DescriptorLength;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ Descriptor,\r
+ DescriptorLength\r
+ );\r
+}\r
+\r
+/**\r
+ Set a usb device with a specified address.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param AddressValue The address to assign.\r
+\r
+ @retval EFI_SUCCESS Usb device address is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 AddressValue\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+\r
+ ASSERT (UsbIoPpi != NULL);\r
+\r
+ DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE;\r
+ DevReq.Request = USB_DEV_SET_ADDRESS;\r
+ DevReq.Value = AddressValue;\r
+ DevReq.Index = 0;\r
+ DevReq.Length = 0;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear a given usb feature.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+ @param Value Request Value.\r
+ @param Target Request Index.\r
+\r
+ @retval EFI_SUCCESS Usb feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN EFI_USB_RECIPIENT Recipient,\r
+ IN UINT16 Value,\r
+ IN UINT16 Target\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+\r
+ ASSERT (UsbIoPpi != NULL);\r
+\r
+ switch (Recipient) {\r
+ case EfiUsbDevice:\r
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D;\r
+ break;\r
+\r
+ case EfiUsbInterface:\r
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I;\r
+ break;\r
+\r
+ case EfiUsbEndpoint:\r
+ DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E;\r
+ break;\r
+ }\r
+\r
+ DevReq.Request = USB_DEV_CLEAR_FEATURE;\r
+ DevReq.Value = Value;\r
+ DevReq.Index = Target;\r
+ DevReq.Length = 0;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Configure a usb device to Configuration 1.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE;\r
+ DevReq.Request = USB_DEV_SET_CONFIGURATION;\r
+ DevReq.Value = 1;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear Endpoint Halt.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointAddress The endpoint address.\r
+\r
+ @retval EFI_SUCCESS Endpoint halt is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 EndpointAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;\r
+ UINT8 EndpointIndex;\r
+\r
+ EndpointIndex = 0;\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (UsbIoPpi);\r
+\r
+ while (EndpointIndex < MAX_ENDPOINT) {\r
+ Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (EndpointDescriptor->EndpointAddress == EndpointAddress) {\r
+ break;\r
+ }\r
+\r
+ EndpointIndex++;\r
+ }\r
+\r
+ if (EndpointIndex == MAX_ENDPOINT) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = PeiUsbClearDeviceFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ EfiUsbEndpoint,\r
+ EfiUsbEndpointHalt,\r
+ EndpointAddress\r
+ );\r
+\r
+ //\r
+ // set data toggle to zero.\r
+ //\r
+ if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {\r
+ PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Judge if the port is connected with a usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A usb device is connected with the port.\r
+ @retval FALSE No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+ IN UINT16 PortStatus\r
+ )\r
+{\r
+ //\r
+ // return the bit 0 value of PortStatus\r
+ //\r
+ if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Judge if the port is connected with a low-speed usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A low-speed usb device is connected with the port.\r
+ @retval FALSE No low-speed usb device is connected with the port.\r
+\r
+**/\r
+UINTN\r
+IsPortLowSpeedDeviceAttached (\r
+ IN UINT16 PortStatus\r
+ )\r
+{\r
+ //\r
+ // return the bit 9 value of PortStatus\r
+ //\r
+ if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
+ return EFI_USB_SPEED_LOW;\r
+ } else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){\r
+ return EFI_USB_SPEED_HIGH;\r
+ } else {\r
+ return EFI_USB_SPEED_FULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Judge if the port is in "connection change" status or not.\r
+\r
+ @param PortChangeStatus The usb port change status gotten.\r
+\r
+ @retval TRUE The port is in "connection change" status.\r
+ @retval FALSE The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+ IN UINT16 PortChangeStatus\r
+ )\r
+{\r
+ //\r
+ // return the bit 0 value of PortChangeStatus\r
+ //\r
+ if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Common Libarary for PEI USB\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. <BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_LIB_H_\r
+#define _PEI_USB_LIB_H_\r
+\r
+\r
+//\r
+// Standard device request and request type\r
+// By [Spec-USB20/Chapter-9.4]\r
+//\r
+#define USB_DEV_GET_STATUS 0x00\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_D 0x80 // Receiver : Device\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_I 0x81 // Receiver : Interface\r
+#define USB_DEV_GET_STATUS_REQ_TYPE_E 0x82 // Receiver : Endpoint\r
+\r
+#define USB_DEV_CLEAR_FEATURE 0x01\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface\r
+#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint\r
+\r
+#define USB_DEV_SET_FEATURE 0x03\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface\r
+#define USB_DEV_SET_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint\r
+\r
+#define USB_DEV_SET_ADDRESS 0x05\r
+#define USB_DEV_SET_ADDRESS_REQ_TYPE 0x00\r
+\r
+#define USB_DEV_GET_DESCRIPTOR 0x06\r
+#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE 0x80\r
+\r
+#define USB_DEV_SET_DESCRIPTOR 0x07\r
+#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE 0x00\r
+\r
+#define USB_DEV_GET_CONFIGURATION 0x08\r
+#define USB_DEV_GET_CONFIGURATION_REQ_TYPE 0x80\r
+\r
+#define USB_DEV_SET_CONFIGURATION 0x09\r
+#define USB_DEV_SET_CONFIGURATION_REQ_TYPE 0x00\r
+\r
+#define USB_DEV_GET_INTERFACE 0x0A\r
+#define USB_DEV_GET_INTERFACE_REQ_TYPE 0x81\r
+\r
+#define USB_DEV_SET_INTERFACE 0x0B\r
+#define USB_DEV_SET_INTERFACE_REQ_TYPE 0x01\r
+\r
+#define USB_DEV_SYNCH_FRAME 0x0C\r
+#define USB_DEV_SYNCH_FRAME_REQ_TYPE 0x82\r
+\r
+//\r
+// USB Descriptor types\r
+//\r
+#define USB_DT_DEVICE 0x01\r
+#define USB_DT_CONFIG 0x02\r
+#define USB_DT_STRING 0x03\r
+#define USB_DT_INTERFACE 0x04\r
+#define USB_DT_ENDPOINT 0x05\r
+#define USB_DT_HUB 0x29\r
+#define USB_DT_HID 0x21\r
+\r
+//\r
+// USB request type\r
+//\r
+#define USB_TYPE_STANDARD (0x00 << 5)\r
+#define USB_TYPE_CLASS (0x01 << 5)\r
+#define USB_TYPE_VENDOR (0x02 << 5)\r
+#define USB_TYPE_RESERVED (0x03 << 5)\r
+\r
+//\r
+// USB request targer device\r
+//\r
+#define USB_RECIP_DEVICE 0x00\r
+#define USB_RECIP_INTERFACE 0x01\r
+#define USB_RECIP_ENDPOINT 0x02\r
+#define USB_RECIP_OTHER 0x03\r
+\r
+typedef enum {\r
+ EfiUsbEndpointHalt,\r
+ EfiUsbDeviceRemoteWakeup\r
+} EFI_USB_STANDARD_FEATURE_SELECTOR;\r
+\r
+//\r
+// Usb Data recipient type\r
+//\r
+typedef enum {\r
+ EfiUsbDevice,\r
+ EfiUsbInterface,\r
+ EfiUsbEndpoint\r
+} EFI_USB_RECIPIENT;\r
+\r
+/**\r
+ Get a given usb descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Request Value.\r
+ @param Index Request Index.\r
+ @param DescriptorLength Request descriptor Length.\r
+ @param Descriptor Request descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 Value,\r
+ IN UINT16 Index,\r
+ IN UINT16 DescriptorLength,\r
+ OUT VOID *Descriptor\r
+ );\r
+\r
+/**\r
+ Set a usb device with a specified address.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param AddressValue The address to assign.\r
+\r
+ @retval EFI_SUCCESS Usb device address is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetDeviceAddress (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT16 AddressValue\r
+ );\r
+\r
+/**\r
+ Clear a given usb feature.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint.\r
+ @param Value Request Value.\r
+ @param Target Request Index.\r
+\r
+ @retval EFI_SUCCESS Usb feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearDeviceFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN EFI_USB_RECIPIENT Recipient,\r
+ IN UINT16 Value,\r
+ IN UINT16 Target\r
+ );\r
+\r
+/**\r
+ Configure a usb device to Configuration 1.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbSetConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi\r
+ );\r
+\r
+/**\r
+ Clear Endpoint Halt.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointAddress The endpoint address.\r
+\r
+ @retval EFI_SUCCESS Endpoint halt is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbClearEndpointHalt (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 EndpointAddress\r
+ );\r
+\r
+/**\r
+ Judge if the port is connected with a usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A usb device is connected with the port.\r
+ @retval FALSE No usb device is connected with the port.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnect (\r
+ IN UINT16 PortStatus\r
+ );\r
+\r
+/**\r
+ Judge if the port is connected with a low-speed usb device or not.\r
+\r
+ @param PortStatus The usb port status gotten.\r
+\r
+ @retval TRUE A low-speed usb device is connected with the port.\r
+ @retval FALSE No low-speed usb device is connected with the port.\r
+\r
+**/\r
+UINTN\r
+IsPortLowSpeedDeviceAttached (\r
+ IN UINT16 PortStatus\r
+ );\r
+\r
+/**\r
+ Judge if the port is in "connection change" status or not.\r
+\r
+ @param PortChangeStatus The usb port change status gotten.\r
+\r
+ @retval TRUE The port is in "connection change" status.\r
+ @retval FALSE The port is NOT in "connection change" status.\r
+\r
+**/\r
+BOOLEAN\r
+IsPortConnectChange (\r
+ IN UINT16 PortChangeStatus\r
+ );\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for UsbPeim module.\r
+#\r
+# Usb Bus Peim driver to support recovery from usb device.\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions\r
+# of the BSD License which accompanies this distribution. The\r
+# full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = UsbBusPei\r
+ FILE_GUID = 8401A045-6F70-4505-8471-7015B40355E3\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = PeimInitializeUsb\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ PeiUsbLib.c\r
+ HubPeim.c\r
+ UsbIoPeim.c\r
+ UsbPeim.c\r
+ UsbPeim.h\r
+ PeiUsbLib.h\r
+ HubPeim.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeiServicesLib\r
+ PeimEntryPoint\r
+ DebugLib\r
+ PcdLib\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue\r
+ \r
+[Ppis]\r
+ gPeiUsbIoPpiGuid # PPI ALWAYS_PRODUCED\r
+ gPeiUsbHostControllerPpiGuid # PPI ALWAYS_CONSUMED\r
+ gPeiUsb2HostControllerPpiGuid # PPI ALWAYS_CONSUMED\r
+\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid AND gPeiUsb2HostControllerPpiGuid OR gPeiUsbHostControllerPpiGuid\r
+\r
--- /dev/null
+/** @file\r
+The module is used to implement Usb Io PPI interfaces.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. <BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_IO_PPI.\r
+ @param Request USB device request to send.\r
+ @param Direction Specifies the data direction for the data stage.\r
+ @param Timeout Indicates the maximum timeout, in millisecond.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT32 Timeout,\r
+ IN OUT VOID *Data, OPTIONAL\r
+ IN UINTN DataLength OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+ UINT32 TransferResult;\r
+\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+ if (PeiUsbDev->Usb2HcPpi != NULL) {\r
+ Status = PeiUsbDev->Usb2HcPpi->ControlTransfer (\r
+ PeiServices,\r
+ PeiUsbDev->Usb2HcPpi,\r
+ PeiUsbDev->DeviceAddress,\r
+ PeiUsbDev->DeviceSpeed,\r
+ PeiUsbDev->MaxPacketSize0,\r
+ Request,\r
+ Direction,\r
+ Data,\r
+ &DataLength,\r
+ Timeout,\r
+ &(PeiUsbDev->Translator),\r
+ &TransferResult\r
+ );\r
+ } else {\r
+ Status = PeiUsbDev->UsbHcPpi->ControlTransfer (\r
+ PeiServices,\r
+ PeiUsbDev->UsbHcPpi,\r
+ PeiUsbDev->DeviceAddress,\r
+ PeiUsbDev->DeviceSpeed,\r
+ PeiUsbDev->MaxPacketSize0,\r
+ Request,\r
+ Direction,\r
+ Data,\r
+ &DataLength,\r
+ Timeout,\r
+ &TransferResult\r
+ );\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_IO_PPI.\r
+ @param DeviceEndpoint Endpoint number and its direction in bit 7.\r
+ @param Data A pointer to the buffer of data to transmit \r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 DeviceEndpoint,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+ UINT32 TransferResult;\r
+ UINTN MaxPacketLength;\r
+ UINT8 DataToggle;\r
+ UINT8 OldToggle;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;\r
+ UINT8 EndpointIndex;\r
+ VOID *Data2[EFI_USB_MAX_BULK_BUFFER_NUM];\r
+\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+ EndpointDescriptor = NULL;\r
+ EndpointIndex = 0;\r
+ Data2[0] = Data;\r
+ Data2[1] = NULL;\r
+\r
+ while (EndpointIndex < MAX_ENDPOINT) {\r
+ Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) {\r
+ break;\r
+ }\r
+\r
+ EndpointIndex++;\r
+ }\r
+\r
+ if (EndpointIndex == MAX_ENDPOINT) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize;\r
+ if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {\r
+ DataToggle = 1;\r
+ } else {\r
+ DataToggle = 0;\r
+ }\r
+\r
+ OldToggle = DataToggle;\r
+\r
+ if (PeiUsbDev->Usb2HcPpi != NULL) {\r
+ Status = PeiUsbDev->Usb2HcPpi->BulkTransfer (\r
+ PeiServices,\r
+ PeiUsbDev->Usb2HcPpi,\r
+ PeiUsbDev->DeviceAddress,\r
+ DeviceEndpoint,\r
+ PeiUsbDev->DeviceSpeed,\r
+ MaxPacketLength,\r
+ Data2,\r
+ DataLength,\r
+ &DataToggle,\r
+ Timeout,\r
+ &(PeiUsbDev->Translator),\r
+ &TransferResult\r
+ );\r
+ } else {\r
+ Status = PeiUsbDev->UsbHcPpi->BulkTransfer (\r
+ PeiServices,\r
+ PeiUsbDev->UsbHcPpi,\r
+ PeiUsbDev->DeviceAddress,\r
+ DeviceEndpoint,\r
+ (UINT8) MaxPacketLength,\r
+ Data,\r
+ DataLength,\r
+ &DataToggle,\r
+ Timeout,\r
+ &TransferResult\r
+ );\r
+ }\r
+\r
+ if (OldToggle != DataToggle) {\r
+ PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the usb interface descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+ @param InterfaceDescriptor Request interface descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb interface descriptor is obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetInterfaceDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor\r
+ )\r
+{\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+ *InterfaceDescriptor = PeiUsbDev->InterfaceDesc;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the usb endpoint descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointIndex The valid index of the specified endpoint.\r
+ @param EndpointDescriptor Request endpoint descriptor.\r
+\r
+ @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully.\r
+ @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetEndpointDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 EndpointIndex,\r
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor\r
+ )\r
+{\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+ ASSERT (EndpointDescriptor != NULL);\r
+\r
+ //\r
+ // The valid range of EndpointIndex is 0..15\r
+ // If EndpointIndex is lesser than 15 but larger than the number of interfaces,\r
+ // a EFI_NOT_FOUND should be returned\r
+ //\r
+ ASSERT (EndpointIndex <= 15);\r
+\r
+ if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex];\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reset the port and re-configure the usb device.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is reset and configured successfully.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbPortReset (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This\r
+ )\r
+{\r
+ PEI_USB_DEVICE *PeiUsbDev;\r
+ EFI_STATUS Status;\r
+ UINT8 Address;\r
+\r
+ PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);\r
+\r
+ ResetRootPort (\r
+ PeiServices,\r
+ PeiUsbDev->UsbHcPpi,\r
+ PeiUsbDev->Usb2HcPpi,\r
+ PeiUsbDev->DeviceAddress,\r
+ 0\r
+ );\r
+\r
+ //\r
+ // Set address\r
+ //\r
+ Address = PeiUsbDev->DeviceAddress;\r
+ PeiUsbDev->DeviceAddress = 0;\r
+\r
+ Status = PeiUsbSetDeviceAddress (\r
+ PeiServices,\r
+ This,\r
+ Address\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiUsbDev->DeviceAddress = Address;\r
+\r
+ //\r
+ // Set default configuration\r
+ //\r
+ Status = PeiUsbSetConfiguration (\r
+ PeiServices,\r
+ This\r
+ );\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+The module to produce Usb Bus PPI.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbPeim.h"\r
+#include "HubPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+//\r
+// UsbIo PPI interface function\r
+//\r
+PEI_USB_IO_PPI mUsbIoPpi = {\r
+ PeiUsbControlTransfer,\r
+ PeiUsbBulkTransfer,\r
+ PeiUsbGetInterfaceDescriptor,\r
+ PeiUsbGetEndpointDescriptor,\r
+ PeiUsbPortReset\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gPeiUsbIoPpiGuid,\r
+ NULL\r
+};\r
+\r
+/**\r
+ The enumeration routine to detect device change.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+\r
+ @retval EFI_SUCCESS The usb is enumerated successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbEnumeration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi\r
+ );\r
+\r
+/**\r
+ Configure new detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+ @param Port The port to be configured.\r
+ @param DeviceAddress The device address to be configured.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiConfigureUsbDevice (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN UINT8 Port,\r
+ IN OUT UINT8 *DeviceAddress\r
+ );\r
+\r
+/**\r
+ Get all configurations from a detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetAllConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ );\r
+\r
+/**\r
+ Get the start position of next wanted descriptor.\r
+ \r
+ @param Buffer Buffer containing data to parse.\r
+ @param Length Buffer length.\r
+ @param DescType Descriptor type.\r
+ @param DescLength Descriptor length.\r
+ @param ParsedBytes Bytes has been parsed.\r
+\r
+ @retval EFI_SUCCESS Get wanted descriptor successfully.\r
+ @retval EFI_DEVICE_ERROR Error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExpectedDescriptor (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN Length,\r
+ IN UINT8 DescType,\r
+ IN UINT8 DescLength,\r
+ OUT UINTN *ParsedBytes\r
+ );\r
+\r
+/**\r
+ The entrypoint of the module, it will enumerate all HCs.\r
+ \r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS Usb initialization is done successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval EFI_UNSUPPORTED Can't find required PPI.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeUsb (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;\r
+ PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;\r
+\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not \r
+ // be produced at the same time\r
+ //\r
+ Index = 0;\r
+ while (TRUE) {\r
+ //\r
+ // Get UsbHcPpi at first.\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbHostControllerPpiGuid,\r
+ Index,\r
+ NULL,\r
+ (VOID **) &UsbHcPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more host controller, break out\r
+ //\r
+ break;\r
+ }\r
+ PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL);\r
+ Index++;\r
+ }\r
+\r
+ if (Index == 0) {\r
+ //\r
+ // Then try to get Usb2HcPpi.\r
+ //\r
+ while (TRUE) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsb2HostControllerPpiGuid,\r
+ Index,\r
+ NULL,\r
+ (VOID **) &Usb2HcPpi\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more host controller, break out\r
+ //\r
+ break;\r
+ } \r
+ PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi); \r
+ Index++;\r
+ }\r
+ }\r
+ \r
+ if (Index == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The Hub Enumeration just scans the hub ports one time. It also\r
+ doesn't support hot-plug.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+ @param CurrentAddress The DeviceAddress of usb device.\r
+\r
+ @retval EFI_SUCCESS The usb hub is enumerated successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubEnumeration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN UINT8 *CurrentAddress\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ EFI_USB_PORT_STATUS PortStatus;\r
+ UINTN MemPages;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ PEI_USB_DEVICE *NewPeiUsbDevice;\r
+\r
+\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+\r
+ Status = PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortConnectChange\r
+ );\r
+\r
+ MicroSecondDelay (100 * 1000);\r
+\r
+ if (IsPortConnect (PortStatus.PortStatus)) {\r
+\r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+\r
+ //\r
+ // Begin to deal with the new device\r
+ //\r
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);\r
+ ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
+\r
+ NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;\r
+ NewPeiUsbDevice->DeviceAddress = 0;\r
+ NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+ NewPeiUsbDevice->DataToggle = 0;\r
+ CopyMem (\r
+ &(NewPeiUsbDevice->UsbIoPpi),\r
+ &mUsbIoPpi,\r
+ sizeof (PEI_USB_IO_PPI)\r
+ );\r
+ CopyMem (\r
+ &(NewPeiUsbDevice->UsbIoPpiList),\r
+ &mUsbIoPpiList,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;\r
+ NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;\r
+ NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;\r
+ NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;\r
+ NewPeiUsbDevice->IsHub = 0x0;\r
+ NewPeiUsbDevice->DownStreamPortNo = 0x0;\r
+\r
+ PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+\r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+\r
+ NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+\r
+ if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {\r
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;\r
+ NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;\r
+ } else {\r
+ CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Configure that Usb Device\r
+ //\r
+ Status = PeiConfigureUsbDevice (\r
+ PeiServices,\r
+ NewPeiUsbDevice,\r
+ (UINT8) (Index + 1),\r
+ CurrentAddress\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);\r
+\r
+ if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
+ NewPeiUsbDevice->IsHub = 0x1;\r
+\r
+ Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);\r
+ }\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The enumeration routine to detect device change.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+\r
+ @retval EFI_SUCCESS The usb is enumerated successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbEnumeration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi\r
+ )\r
+{\r
+ UINT8 NumOfRootPort;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ EFI_USB_PORT_STATUS PortStatus;\r
+ PEI_USB_DEVICE *PeiUsbDevice;\r
+ UINTN MemPages;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ UINT8 CurrentAddress;\r
+\r
+\r
+ CurrentAddress = 0;\r
+ if (Usb2HcPpi != NULL){\r
+ Usb2HcPpi->GetRootHubPortNumber (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8 *) &NumOfRootPort\r
+ ); \r
+ } else {\r
+ UsbHcPpi->GetRootHubPortNumber (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8 *) &NumOfRootPort\r
+ );\r
+ }\r
+\r
+ for (Index = 0; Index < NumOfRootPort; Index++) {\r
+ //\r
+ // First get root port status to detect changes happen\r
+ //\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ ); \r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
+ DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+ if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
+ //\r
+ // Changes happen, first clear this change status\r
+ //\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ EfiUsbPortConnectChange\r
+ ); \r
+ } else {\r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ EfiUsbPortConnectChange\r
+ );\r
+ }\r
+ MicroSecondDelay (100 * 1000);\r
+\r
+ if (IsPortConnect (PortStatus.PortStatus)) {\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
+\r
+ //\r
+ // Connect change happen\r
+ //\r
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);\r
+ ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
+\r
+ PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;\r
+ PeiUsbDevice->DeviceAddress = 0;\r
+ PeiUsbDevice->MaxPacketSize0 = 8;\r
+ PeiUsbDevice->DataToggle = 0;\r
+ CopyMem (\r
+ &(PeiUsbDevice->UsbIoPpi),\r
+ &mUsbIoPpi,\r
+ sizeof (PEI_USB_IO_PPI)\r
+ );\r
+ CopyMem (\r
+ &(PeiUsbDevice->UsbIoPpiList),\r
+ &mUsbIoPpiList,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;\r
+ PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;\r
+ PeiUsbDevice->UsbHcPpi = UsbHcPpi;\r
+ PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;\r
+ PeiUsbDevice->IsHub = 0x0;\r
+ PeiUsbDevice->DownStreamPortNo = 0x0;\r
+\r
+ ResetRootPort (\r
+ PeiServices,\r
+ PeiUsbDevice->UsbHcPpi,\r
+ PeiUsbDevice->Usb2HcPpi,\r
+ Index,\r
+ 0\r
+ );\r
+\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
+\r
+ PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+ DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
+\r
+ //\r
+ // Configure that Usb Device\r
+ //\r
+ Status = PeiConfigureUsbDevice (\r
+ PeiServices,\r
+ PeiUsbDevice,\r
+ Index,\r
+ &CurrentAddress\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));\r
+\r
+ Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);\r
+\r
+ if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
+ PeiUsbDevice->IsHub = 0x1;\r
+\r
+ Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);\r
+ }\r
+ } else {\r
+ //\r
+ // Disconnect change happen, currently we don't support\r
+ //\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Configure new detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+ @param Port The port to be configured.\r
+ @param DeviceAddress The device address to be configured.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiConfigureUsbDevice (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN UINT8 Port,\r
+ IN OUT UINT8 *DeviceAddress\r
+ )\r
+{\r
+ EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT8 Retry;\r
+\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+ Status = EFI_SUCCESS;\r
+ ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
+ //\r
+ // Get USB device descriptor\r
+ //\r
+\r
+ for (Retry = 0; Retry < 3; Retry ++) {\r
+\r
+ PeiUsbDevice->MaxPacketSize0 = 8;\r
+\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_DEVICE << 8),\r
+ 0,\r
+ 8,\r
+ &DeviceDescriptor\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Retry == 3) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));\r
+ return Status;\r
+ }\r
+\r
+ PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+\r
+ (*DeviceAddress) ++;\r
+\r
+ Status = PeiUsbSetDeviceAddress (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ *DeviceAddress\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));\r
+ return Status;\r
+ }\r
+\r
+ PeiUsbDevice->DeviceAddress = *DeviceAddress;\r
+\r
+ //\r
+ // Get whole USB device descriptor\r
+ //\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_DEVICE << 8),\r
+ 0,\r
+ (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR),\r
+ &DeviceDescriptor\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));\r
+ return Status;\r
+ }\r
+ //\r
+ // Get its default configuration and its first interface\r
+ //\r
+ Status = PeiUsbGetAllConfiguration (\r
+ PeiServices,\r
+ PeiUsbDevice\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PeiUsbSetConfiguration (\r
+ PeiServices,\r
+ UsbIoPpi\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get all configurations from a detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetAllConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT16 ConfigDescLength;\r
+ UINT8 *Ptr;\r
+ UINTN SkipBytes;\r
+ UINTN LengthLeft;\r
+ UINTN Index;\r
+ UINTN NumOfEndpoint;\r
+\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+ //\r
+ // First get its 4-byte configuration descriptor\r
+ //\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_CONFIG << 8), // Value\r
+ 0, // Index\r
+ 4, // Length\r
+ PeiUsbDevice->ConfigurationData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));\r
+ return Status;\r
+ }\r
+\r
+ ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;\r
+ ConfigDescLength = ConfigDesc->TotalLength;\r
+\r
+ //\r
+ // Then we get the total descriptors for this configuration\r
+ //\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_CONFIG << 8),\r
+ 0,\r
+ ConfigDescLength,\r
+ PeiUsbDevice->ConfigurationData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));\r
+ return Status;\r
+ }\r
+ //\r
+ // Parse this configuration descriptor\r
+ // First get the current config descriptor;\r
+ //\r
+ Status = GetExpectedDescriptor (\r
+ PeiUsbDevice->ConfigurationData,\r
+ ConfigDescLength,\r
+ USB_DT_CONFIG,\r
+ (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),\r
+ &SkipBytes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;\r
+ PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;\r
+\r
+ Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
+ LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
+\r
+ //\r
+ // Get the first interface descriptor\r
+ //\r
+ Status = GetExpectedDescriptor (\r
+ Ptr,\r
+ LengthLeft,\r
+ USB_DT_INTERFACE,\r
+ (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),\r
+ &SkipBytes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr += SkipBytes;\r
+ PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;\r
+\r
+ Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
+ LengthLeft -= SkipBytes;\r
+ LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
+\r
+ //\r
+ // Parse all the endpoint descriptor within this interface\r
+ //\r
+ NumOfEndpoint = PeiUsbDevice->InterfaceDesc->NumEndpoints;\r
+ ASSERT (NumOfEndpoint <= MAX_ENDPOINT);\r
+\r
+ for (Index = 0; Index < NumOfEndpoint; Index++) {\r
+ //\r
+ // Get the endpoint descriptor\r
+ //\r
+ Status = GetExpectedDescriptor (\r
+ Ptr,\r
+ LengthLeft,\r
+ USB_DT_ENDPOINT,\r
+ (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),\r
+ &SkipBytes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr += SkipBytes;\r
+ PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;\r
+\r
+ Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+ LengthLeft -= SkipBytes;\r
+ LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the start position of next wanted descriptor.\r
+ \r
+ @param Buffer Buffer containing data to parse.\r
+ @param Length Buffer length.\r
+ @param DescType Descriptor type.\r
+ @param DescLength Descriptor length.\r
+ @param ParsedBytes Bytes has been parsed.\r
+\r
+ @retval EFI_SUCCESS Get wanted descriptor successfully.\r
+ @retval EFI_DEVICE_ERROR Error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExpectedDescriptor (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN Length,\r
+ IN UINT8 DescType,\r
+ IN UINT8 DescLength,\r
+ OUT UINTN *ParsedBytes\r
+ )\r
+{\r
+ UINT16 DescriptorHeader;\r
+ UINT8 Len;\r
+ UINT8 *Ptr;\r
+ UINTN Parsed;\r
+\r
+ Parsed = 0;\r
+ Ptr = Buffer;\r
+\r
+ while (TRUE) {\r
+ //\r
+ // Buffer length should not less than Desc length\r
+ //\r
+ if (Length < DescLength) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));\r
+\r
+ Len = Buffer[0];\r
+\r
+ //\r
+ // Check to see if it is a start of expected descriptor\r
+ //\r
+ if (DescriptorHeader == ((DescType << 8) | DescLength)) {\r
+ break;\r
+ }\r
+\r
+ if ((UINT8) (DescriptorHeader >> 8) == DescType) {\r
+ if (Len > DescLength) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // Descriptor length should be at least 2\r
+ // and should not exceed the buffer length\r
+ //\r
+ if (Len < 2) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (Len > Length) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Skip this mismatch descriptor\r
+ //\r
+ Length -= Len;\r
+ Ptr += Len;\r
+ Parsed += Len;\r
+ }\r
+\r
+ *ParsedBytes = Parsed;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send reset signal over the given root hub port.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+ @param PortNum The port to be reset.\r
+ @param RetryIndex The retry times.\r
+\r
+**/\r
+VOID\r
+ResetRootPort (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 RetryIndex\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ if (Usb2HcPpi != NULL) {\r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // reset root port\r
+ //\r
+ Status = Usb2HcPpi->SetRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // clear reset root port\r
+ //\r
+ Status = Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (1 * 1000);\r
+ \r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortConnectChange\r
+ );\r
+ \r
+ //\r
+ // Set port enable\r
+ //\r
+ Usb2HcPpi->SetRootHubPortFeature(\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnable\r
+ );\r
+ \r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnableChange\r
+ );\r
+ \r
+ MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
+ } else {\r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // reset root port\r
+ //\r
+ Status = UsbHcPpi->SetRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // clear reset root port\r
+ //\r
+ Status = UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (1 * 1000);\r
+ \r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortConnectChange\r
+ );\r
+ \r
+ //\r
+ // Set port enable\r
+ //\r
+ UsbHcPpi->SetRootHubPortFeature(\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnable\r
+ );\r
+ \r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnableChange\r
+ );\r
+ \r
+ MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
+ }\r
+ return;\r
+}\r
+\r
+\r
--- /dev/null
+/** @file\r
+Usb Peim definition.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. <BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_PEIM_H_\r
+#define _PEI_USB_PEIM_H_\r
+\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbHostController.h>\r
+#include <Ppi/Usb2HostController.h>\r
+#include <Ppi/UsbIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <IndustryStandard/Usb.h>\r
+\r
+#define MAX_ROOT_PORT 2\r
+#define MAX_ENDPOINT 16\r
+\r
+#define USB_SLOW_SPEED_DEVICE 0x01\r
+#define USB_FULL_SPEED_DEVICE 0x02\r
+\r
+#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D')\r
+typedef struct {\r
+ UINTN Signature;\r
+ PEI_USB_IO_PPI UsbIoPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList;\r
+ UINT8 DeviceAddress;\r
+ UINT8 MaxPacketSize0;\r
+ UINT8 DeviceSpeed;\r
+ UINT8 DataToggle;\r
+ UINT8 IsHub;\r
+ UINT8 DownStreamPortNo;\r
+ UINT8 Reserved[2]; // Padding for IPF\r
+ UINTN AllocateAddress;\r
+ PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;\r
+ PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;\r
+ UINT8 ConfigurationData[1024];\r
+ EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;\r
+ EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc;\r
+ EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT];\r
+ EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator; \r
+} PEI_USB_DEVICE;\r
+\r
+#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE)\r
+\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_IO_PPI.\r
+ @param Request USB device request to send.\r
+ @param Direction Specifies the data direction for the data stage.\r
+ @param Timeout Indicates the maximum timeout, in millisecond.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT32 Timeout,\r
+ IN OUT VOID *Data, OPTIONAL\r
+ IN UINTN DataLength OPTIONAL\r
+ );\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+ \r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_IO_PPI.\r
+ @param DeviceEndpoint Endpoint number and its direction in bit 7.\r
+ @param Data A pointer to the buffer of data to transmit \r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param Timeout Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 DeviceEndpoint,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN Timeout\r
+ );\r
+\r
+/**\r
+ Get the usb interface descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+ @param InterfaceDescriptor Request interface descriptor.\r
+\r
+\r
+ @retval EFI_SUCCESS Usb interface descriptor is obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetInterfaceDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor\r
+ );\r
+\r
+/**\r
+ Get the usb endpoint descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+ @param EndpointIndex The valid index of the specified endpoint.\r
+ @param EndpointDescriptor Request endpoint descriptor.\r
+\r
+ @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully.\r
+ @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbGetEndpointDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 EndpointIndex,\r
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor\r
+ );\r
+\r
+/**\r
+ Reset the port and re-configure the usb device.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param This Indicates the PEI_USB_IO_PPI instance.\r
+\r
+ @retval EFI_SUCCESS Usb device is reset and configured successfully.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiUsbPortReset (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This\r
+ );\r
+\r
+/**\r
+ Send reset signal over the given root hub port.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+ @param PortNum The port to be reset.\r
+ @param RetryIndex The retry times.\r
+\r
+**/\r
+VOID\r
+ResetRootPort (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 RetryIndex\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Defines the USB Host Controller PPI that provides I/O services for a USB Host \r
+ Controller that may be used to access recovery devices. These interfaces are \r
+ modeled on the UEFI 2.3 specification EFI_USB2_HOST_CONTROLLER_PROTOCOL.\r
+ Refer to section 16.1 of the UEFI 2.3 Specification for more information on \r
+ these interfaces.\r
+ \r
+Copyright (c) 2010, Intel Corporation. All rights reserved. <BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB2_HOST_CONTROLLER_PPI_H_\r
+#define _PEI_USB2_HOST_CONTROLLER_PPI_H_\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+\r
+///\r
+/// Global ID for the PEI_USB2_HOST_CONTROLLER_PPI.\r
+///\r
+#define PEI_USB2_HOST_CONTROLLER_PPI_GUID \\r
+ { \\r
+ 0xa7d09fe1, 0x74d4, 0x4ba5, { 0x84, 0x7c, 0x12, 0xed, 0x5b, 0x19, 0xad, 0xe4 } \\r
+ }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB2_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _PEI_USB2_HOST_CONTROLLER_PPI PEI_USB2_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+ Initiate a USB control transfer using a specific USB Host controller on the USB bus. \r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[in] DeviceAddress Represents the address of the target device \r
+ on the USB.\r
+ @param[in] DeviceSpeed Indicates device speed.\r
+ @param[in] MaximumPacketLength Indicates the maximum packet size that the \r
+ default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param[in] Request A pointer to the USB device request that \r
+ will be sent to the USB device.\r
+ @param[in] TransferDirection Specifies the data direction for the transfer. \r
+ There are three values available: \r
+ EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.\r
+ @param[in,out] Data A pointer to the buffer of data that will \r
+ be transmitted to USB device or\r
+ received from USB device.\r
+ @param[in,out] DataLength On input, indicates the size, in bytes, of \r
+ the data buffer specified by Data.\r
+ On output, indicates the amount of data \r
+ actually transferred.\r
+ @param[in] TimeOut Indicates the maximum time, in milliseconds, \r
+ that the transfer is allowed to complete.\r
+ @param[in] Translator A pointer to the transaction translator data.\r
+ @param[out] TransferResult A pointer to the detailed result information \r
+ generated by this control transfer.\r
+\r
+ @retval EFI_SUCCESS The control transfer was completed successfully.\r
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller \r
+ or device error.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.\r
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.\r
+ \r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_CONTROL_TRANSFER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN OUT UINTN *DataLength OPTIONAL,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Initiate a USB bulk transfer using a specific USB Host controller on the USB bus. \r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[in] DeviceAddress Represents the address of the target device \r
+ on the USB.\r
+ @param[in] EndPointAddress The combination of an endpoint number and \r
+ an endpoint direction of the target USB device.\r
+ @param[in] DeviceSpeed Indicates device speed.\r
+ @param[in] MaximumPacketLength Indicates the maximum packet size the target \r
+ endpoint is capable of sending or receiving.\r
+ @param[in,out] Data Array of pointers to the buffers of data \r
+ that will be transmitted to USB device or \r
+ received from USB device.\r
+ @param[in,out] DataLength When input, indicates the size, in bytes, of \r
+ the data buffers specified by Data. When output,\r
+ indicates the data size actually transferred.\r
+ @param[in,out] DataToggle A pointer to the data toggle value.\r
+ @param[in] TimeOut Indicates the maximum time, in milliseconds,\r
+ in which the transfer is allowed to complete.\r
+ @param[in] Translator A pointer to the transaction translator data.\r
+ @param[out] TransferResult A pointer to the detailed result information \r
+ of the bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.\r
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.\r
+ Caller should check TransferResult for detailed error information.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to a lack of resources.\r
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout. \r
+ \r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_BULK_TRANSFER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed, \r
+ IN UINTN MaximumPacketLength,\r
+ IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[out] PortNumber The pointer to the number of the root hub ports. \r
+ \r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *PortNumber\r
+ );\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[in] PortNumber Specifies the root hub port from which the status is \r
+ to be retrieved.\r
+ This value is zero based.\r
+ @param[out] PortStatus A pointer to the current port status bits and port \r
+ status change bits.\r
+ \r
+ @retval EFI_SUCCESS The status of the USB root hub port specified by \r
+ PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ );\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[in] PortNumber Specifies the root hub port whose feature is requested \r
+ to be set. This value is zero based.\r
+ @param[in] PortFeature Indicates the feature selector associated with the feature \r
+ set request.\r
+ \r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for \r
+ the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid \r
+ for this function.\r
+ @retval EFI_TIMEOUT The time out occurred \r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB2_HOST_CONTROLLER_PPI.\r
+ @param[in] PortNumber Specifies the root hub port whose feature is\r
+ requested to be cleared.\r
+ @param[in] PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @return EFI_SUCCESS The feature specified by PortFeature was cleared\r
+ for the USB root hub port specified by PortNumber.\r
+ @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB2_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the USB host controller.\r
+/// These interfaces are modeled on the UEFI 2.3 specification protocol\r
+/// EFI_USB2_HOST_CONTROLLER_PROTOCOL. Refer to section 16.1 of the UEFI 2.3 \r
+/// Specification for more information on these interfaces.\r
+///\r
+struct _PEI_USB2_HOST_CONTROLLER_PPI {\r
+ PEI_USB2_HOST_CONTROLLER_CONTROL_TRANSFER ControlTransfer;\r
+ PEI_USB2_HOST_CONTROLLER_BULK_TRANSFER BulkTransfer;\r
+ PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER GetRootHubPortNumber;\r
+ PEI_USB2_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS GetRootHubPortStatus;\r
+ PEI_USB2_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE SetRootHubPortFeature;\r
+ PEI_USB2_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE ClearRootHubPortFeature;\r
+};\r
+\r
+extern EFI_GUID gPeiUsb2HostControllerPpiGuid;\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ Define APIs to retrieve USB Host Controller Info such as controller type and \r
+ I/O Port Base Address.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_CONTROLLER_PPI_H_\r
+#define _PEI_USB_CONTROLLER_PPI_H_\r
+\r
+///\r
+/// Global ID for the PEI_USB_CONTROLLER_PPI.\r
+///\r
+#define PEI_USB_CONTROLLER_PPI_GUID \\r
+ { \\r
+ 0x3bc1f6de, 0x693e, 0x4547,{ 0xa3, 0x0, 0x21, 0x82, 0x3c, 0xa4, 0x20, 0xb2} \\r
+ }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB_CONTROLLER_PPI.\r
+///\r
+typedef struct _PEI_USB_CONTROLLER_PPI PEI_USB_CONTROLLER_PPI;\r
+\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as UHCI\r
+///\r
+#define PEI_UHCI_CONTROLLER 0x01\r
+\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as OHCI\r
+///\r
+#define PEI_OHCI_CONTROLLER 0x02\r
+\r
+///\r
+/// This bit is used in the ControllerType return parameter of GetUsbController()\r
+/// to identify the USB Host Controller type as EHCI\r
+///\r
+#define PEI_EHCI_CONTROLLER 0x03\r
+\r
+/**\r
+ Retrieve USB Host Controller Info such as controller type and I/O Base Address.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the PEI_USB_CONTROLLER_PPI.\r
+ @param[in] ControllerId The ID of the USB controller.\r
+ @param[out] ControllerType On output, returns the type of the USB controller.\r
+ @param[out] BaseAddress On output, returns the base address of UHCI's I/O ports\r
+ if UHCI is enabled or the base address of EHCI's MMIO \r
+ if EHCI is enabled.\r
+\r
+ @retval EFI_SUCCESS USB controller attributes were returned successfully.\r
+ @retval EFI_INVALID_PARAMETER ControllerId is greater than the maximum number \r
+ of USB controller supported by this platform.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_GET_USB_CONTROLLER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_CONTROLLER_PPI *This,\r
+ IN UINT8 UsbControllerId,\r
+ OUT UINTN *ControllerType,\r
+ OUT UINTN *BaseAddress\r
+ );\r
+\r
+///\r
+/// This PPI contains a single service to retrieve the USB Host Controller type\r
+/// and the base address of the I/O ports used to access the USB Host Controller.\r
+///\r
+struct _PEI_USB_CONTROLLER_PPI {\r
+ PEI_GET_USB_CONTROLLER GetUsbController;\r
+};\r
+\r
+extern EFI_GUID gPeiUsbControllerPpiGuid;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Defines the USB Host Controller PPI that provides I/O services for a USB Host \r
+ Controller that may be used to access recovery devices. These interfaces are \r
+ modeled on the UEFI 2.3 specification EFI_USB2_HOST_CONTROLLER_PROTOCOL.\r
+ Refer to section 16.1 of the UEFI 2.3 Specification for more information on \r
+ these interfaces.\r
+ \r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_HOST_CONTROLLER_PPI_H_\r
+#define _PEI_USB_HOST_CONTROLLER_PPI_H_\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+\r
+///\r
+/// Global ID for the PEI_USB_HOST_CONTROLLER_PPI.\r
+///\r
+#define PEI_USB_HOST_CONTROLLER_PPI_GUID \\r
+ { \\r
+ 0x652b38a9, 0x77f4, 0x453f, { 0x89, 0xd5, 0xe7, 0xbd, 0xc3, 0x52, 0xfc, 0x53} \\r
+ }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _PEI_USB_HOST_CONTROLLER_PPI PEI_USB_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+ Initiate a USB control transfer using a specific USB Host controller on the USB bus. \r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[in] DeviceAddress Represents the address of the target device \r
+ on the USB.\r
+ @param[in] DeviceSpeed Indicates device speed.\r
+ @param[in] MaximumPacketLength Indicates the maximum packet size that the \r
+ default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param[in] Request A pointer to the USB device request that \r
+ will be sent to the USB device.\r
+ @param[in] TransferDirection Specifies the data direction for the transfer. \r
+ There are three values available: \r
+ EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.\r
+ @param[in,out] Data A pointer to the buffer of data that will \r
+ be transmitted to USB device or\r
+ received from USB device.\r
+ @param[in,out] DataLength On input, indicates the size, in bytes, of \r
+ the data buffer specified by Data.\r
+ On output, indicates the amount of data \r
+ actually transferred.\r
+ @param[in] TimeOut Indicates the maximum time, in milliseconds, \r
+ that the transfer is allowed to complete.\r
+ @param[out] TransferResult A pointer to the detailed result information \r
+ generated by this control transfer.\r
+\r
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller \r
+ or device error.\r
+ @retval EFI_SUCCESS The control transfer was completed successfully.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_CONTROL_TRANSFER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN OUT UINTN *DataLength OPTIONAL,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Initiate a USB bulk transfer using a specific USB Host controller on the USB bus. \r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[in] DeviceAddress Represents the address of the target device \r
+ on the USB.\r
+ @param[in] EndPointAddress The combination of an endpoint number and \r
+ an endpoint direction of the target USB device.\r
+ @param[in] MaximumPacketLength Indicates the maximum packet size the target \r
+ endpoint is capable of sending or receiving.\r
+ @param[in,out] Data Array of pointers to the buffers of data \r
+ that will be transmitted to USB device or \r
+ received from USB device.\r
+ @param[in,out] DataLength When input, indicates the size, in bytes, of \r
+ the data buffers specified by Data. When output,\r
+ indicates the data size actually transferred.\r
+ @param[in,out] DataToggle A pointer to the data toggle value.\r
+ @param[in] TimeOut Indicates the maximum time, in milliseconds,\r
+ in which the transfer is allowed to complete.\r
+ @param[out] TransferResult A pointer to the detailed result information \r
+ of the bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.\r
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.\r
+ Caller should check TransferResult for detailed error information.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_BULK_TRANSFER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[out] PortNumber The pointer to the number of the root hub ports. \r
+ \r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to retrieve \r
+ the port number.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *PortNumber\r
+ );\r
+\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[in] PortNumber Specifies the root hub port from which the status is \r
+ to be retrieved.\r
+ This value is zero based.\r
+ @param[out] PortStatus A pointer to the current port status bits and port \r
+ status change bits.\r
+ \r
+ @retval EFI_SUCCESS The status of the USB root hub port specified by \r
+ PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ );\r
+\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[in] PortNumber Specifies the root hub port whose feature is requested \r
+ to be set. This value is zero based.\r
+ @param[in] PortFeature Indicates the feature selector associated with the feature \r
+ set request.\r
+ \r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for \r
+ the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid \r
+ for this function.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the \r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[in] PortNumber Specifies the root hub port whose feature is\r
+ requested to be cleared.\r
+ @param[in] PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @return EFI_SUCCESS The feature specified by PortFeature was cleared\r
+ for the USB root hub port specified by PortNumber.\r
+ @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @return EFI_DEVICE_ERROR Can't read the register.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the USB host controller.\r
+/// These interfaces are modeled on the UEFI 2.3 specification protocol\r
+/// EFI_USB2_HOST_CONTROLLER_PROTOCOL. Refer to section 16.1 of the UEFI 2.3 \r
+/// Specification for more information on these interfaces.\r
+///\r
+struct _PEI_USB_HOST_CONTROLLER_PPI {\r
+ PEI_USB_HOST_CONTROLLER_CONTROL_TRANSFER ControlTransfer;\r
+ PEI_USB_HOST_CONTROLLER_BULK_TRANSFER BulkTransfer;\r
+ PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_NUMBER GetRootHubPortNumber;\r
+ PEI_USB_HOST_CONTROLLER_GET_ROOTHUB_PORT_STATUS GetRootHubPortStatus;\r
+ PEI_USB_HOST_CONTROLLER_SET_ROOTHUB_PORT_FEATURE SetRootHubPortFeature;\r
+ PEI_USB_HOST_CONTROLLER_CLEAR_ROOTHUB_PORT_FEATURE ClearRootHubPortFeature;\r
+};\r
+\r
+extern EFI_GUID gPeiUsbHostControllerPpiGuid;\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ Defines the PEI_USB_IO_PPI that the USB-related PEIM can use for I/O operations \r
+ on the USB BUS. This interface enables recovery from a \r
+ USB-class storage device, such as USB CD/DVD, USB hard drive, or USB FLASH \r
+ drive. These interfaces are modeled on the UEFI 2.3 specification EFI_USB_IO_PROTOCOL.\r
+ Refer to section 16.2.4 of the UEFI 2.3 Specification for more information on \r
+ these interfaces.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_USB_IO_PPI_H_\r
+#define _PEI_USB_IO_PPI_H_\r
+\r
+#include <Protocol/Usb2HostController.h>\r
+\r
+///\r
+/// Global ID for the PEI_USB_IO_PPI.\r
+///\r
+#define PEI_USB_IO_PPI_GUID \\r
+ { \\r
+ 0x7c29785c, 0x66b9, 0x49fc, { 0xb7, 0x97, 0x1c, 0xa5, 0x55, 0xe, 0xf2, 0x83} \\r
+ }\r
+\r
+///\r
+/// Forward declaration for the PEI_USB_IO_PPI.\r
+///\r
+typedef struct _PEI_USB_IO_PPI PEI_USB_IO_PPI;\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.\r
+ @param[in] Request A pointer to the USB device request that will be \r
+ sent to the USB device.\r
+ @param[in] Direction Specifies the data direction for the transfer. There \r
+ are three values available: \r
+ EfiUsbDataIn, EfiUsbDataOut and EfiUsbNoData.\r
+ @param[in] TimeOut Indicates the maximum time, in milliseconds, that \r
+ the transfer is allowed to complete.\r
+ @param[in,out] Data A pointer to the buffer of data that will be \r
+ transmitted to or received from the USB device.\r
+ @param[in] DataLength On input, indicates the size, in bytes, of the data \r
+ buffer specified by Data.\r
+ \r
+ @retval EFI_SUCCESS The control transfer was completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due \r
+ to a lack of resources.\r
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller \r
+ or device error.\r
+ Caller should check TransferResult for detailed \r
+ error information.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_CONTROL_TRANSFER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN UINT32 Timeout,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN UINTN DataLength OPTIONAL\r
+ );\r
+\r
+/**\r
+ Submits bulk transfer to a target USB device.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.\r
+ @param[in] EndPointAddress The endpoint address.\r
+ @param[in] Data The data buffer to be transfered.\r
+ @param[in] DataLength The length of data buffer.\r
+ @param[in] TimeOut The timeout for the transfer, in milliseconds.\r
+\r
+ @retval EFI_SUCCESS The bulk transfer completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be completed due to \r
+ a lack of resources.\r
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller \r
+ or device error.\r
+ Caller should check TransferResult for detailed \r
+ error information.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_BULK_TRANSFER)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 DeviceEndpoint,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN Timeout\r
+ );\r
+\r
+/**\r
+ Get interface descriptor from a USB device.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.\r
+ @param[in] InterfaceDescriptor The interface descriptor.\r
+\r
+ @retval EFI_SUCCESS The interface descriptor was returned.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_DEVICE_ERROR A device error occurred, the function failed to \r
+ get the interface descriptor.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_GET_INTERFACE_DESCRIPTOR)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor\r
+ );\r
+\r
+/**\r
+ Get endpoint descriptor from a USB device.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.\r
+ @param[in] EndPointIndex The index of the end point.\r
+ @param[in] EndpointDescriptor The endpoint descriptor.\r
+\r
+ @retval EFI_SUCCESS The endpoint descriptor was returned.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_DEVICE_ERROR A device error occurred, the function failed to \r
+ get the endpoint descriptor.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_GET_ENDPOINT_DESCRIPTOR)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This,\r
+ IN UINT8 EndpointIndex,\r
+ IN EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor\r
+ );\r
+\r
+/**\r
+ Issue a port reset to the device.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the PEI_USB_IO_PPI.\r
+\r
+ @retval EFI_SUCCESS The port reset was issued successfully.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_DEVICE_ERROR Device error occurred.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PEI_USB_PORT_RESET)(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *This\r
+ );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the USB host controller.\r
+/// These interfaces are modeled on the UEFI 2.3 specification EFI_USB_IO_PROTOCOL.\r
+/// Refer to section 16.2.4 of the UEFI 2.3 Specification for more information on \r
+/// these interfaces.\r
+///\r
+struct _PEI_USB_IO_PPI {\r
+ PEI_USB_CONTROL_TRANSFER UsbControlTransfer;\r
+ PEI_USB_BULK_TRANSFER UsbBulkTransfer;\r
+ PEI_USB_GET_INTERFACE_DESCRIPTOR UsbGetInterfaceDescriptor;\r
+ PEI_USB_GET_ENDPOINT_DESCRIPTOR UsbGetEndpointDescriptor;\r
+ PEI_USB_PORT_RESET UsbPortReset;\r
+};\r
+\r
+extern EFI_GUID gPeiUsbIoPpiGuid;\r
+\r
+#endif\r
# Include/Guid/EventIdle.h\r
gIdleLoopEventGuid = { 0x3c8d294c, 0x5fc3, 0x4451, { 0xbb, 0x31, 0xc4, 0xc0, 0x32, 0x29, 0x5e, 0x6c } }\r
\r
+[Ppis]\r
+ ## Include/Ppi/UsbHostController.h\r
+ gPeiUsbHostControllerPpiGuid = { 0x652B38A9, 0x77F4, 0x453F, { 0x89, 0xD5, 0xE7, 0xBD, 0xC3, 0x52, 0xFC, 0x53 }}\r
+\r
+ ## Include/Ppi/Usb2HostController.h\r
+ gPeiUsb2HostControllerPpiGuid = { 0xfedd6305, 0xe2d7, 0x4ed5, { 0x9f, 0xaa, 0xda, 0x8, 0xe, 0x33, 0x6c, 0x22 }}\r
+\r
+ ## Include/Ppi/UsbController.h\r
+ gPeiUsbControllerPpiGuid = { 0x3BC1F6DE, 0x693E, 0x4547, { 0xA3, 0x00, 0x21, 0x82, 0x3C, 0xA4, 0x20, 0xB2 }}\r
+\r
+ ## Include/Ppi/UsbIo.h\r
+ gPeiUsbIoPpiGuid = { 0x7C29785C, 0x66B9, 0x49FC, { 0xB7, 0x97, 0x1C, 0xA5, 0x55, 0x0E, 0xF2, 0x83 }}\r
+\r
[Protocols]\r
## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
# Include/Protocol/LoadPe32Image.h\r
MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf\r
MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r
+ MdeModulePkg/Bus/Pci/UhciPei/UhciPei.inf\r
+ MdeModulePkg/Bus/Pci/EhciPei/EhciPei.inf\r
+ MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf\r
+ MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf\r
MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf\r
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf\r
MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf\r