mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-30 23:50:23 +00:00 
			
		
		
		
	 1825c24fd8
			
		
	
	
		1825c24fd8
		
	
	
	
	
		
			
			Fix various typos in comments and documentation. Cc: Hao A Wu <hao.a.wu@intel.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-73-philmd@redhat.com>
		
			
				
	
	
		
			1141 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1141 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Debug Port Library implementation based on usb3 debug port.
 | |
| 
 | |
|   Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "DebugCommunicationLibUsb3Internal.h"
 | |
| 
 | |
| UINT16   mString0Desc[] = {
 | |
|   //  String Descriptor Type + Length
 | |
|   ( USB_DESC_TYPE_STRING << 8 ) + STRING0_DESC_LEN,
 | |
|   0x0409
 | |
| };
 | |
| 
 | |
| UINT16   mManufacturerStrDesc[] = {
 | |
|   //  String Descriptor Type + Length
 | |
|   ( USB_DESC_TYPE_STRING << 8 ) + MANU_DESC_LEN,
 | |
|   'I', 'n', 't', 'e', 'l'
 | |
| };
 | |
| 
 | |
| UINT16   mProductStrDesc[] = {
 | |
|   //  String Descriptor Type + Length
 | |
|   ( USB_DESC_TYPE_STRING << 8 ) +  PRODUCT_DESC_LEN,
 | |
|   'U', 'S', 'B', ' ', '3', '.', '0', ' ', 'D', 'e', 'b', 'u', 'g', ' ', 'C', 'a', 'b', 'l', 'e'
 | |
| };
 | |
| 
 | |
| UINT16   mSerialNumberStrDesc[] = {
 | |
|   //  String Descriptor Type + Length
 | |
|   ( USB_DESC_TYPE_STRING << 8 ) +  SERIAL_DESC_LEN,
 | |
|   '1'
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Sets bits as per the enabled bit positions in the mask.
 | |
| 
 | |
|   @param[in, out] Register    UINTN register
 | |
|   @param[in]      BitMask     32-bit mask
 | |
| **/
 | |
| VOID
 | |
| XhcSetR32Bit(
 | |
|   IN OUT  UINTN  Register,
 | |
|   IN      UINT32 BitMask
 | |
|   )
 | |
| {
 | |
|   UINT32    RegisterValue;
 | |
| 
 | |
|   RegisterValue = MmioRead32 (Register);
 | |
|   RegisterValue |= (UINT32)(BitMask);
 | |
|   MmioWrite32 (Register, RegisterValue);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Clears bits as per the enabled bit positions in the mask.
 | |
| 
 | |
|   @param[in, out] Register    UINTN register
 | |
|   @param[in]      BitMask     32-bit mask
 | |
| **/
 | |
| VOID
 | |
| XhcClearR32Bit(
 | |
|   IN OUT  UINTN  Register,
 | |
|   IN      UINT32 BitMask
 | |
|   )
 | |
| {
 | |
|   UINT32    RegisterValue;
 | |
| 
 | |
|   RegisterValue = MmioRead32 (Register);
 | |
|   RegisterValue &= ~BitMask;
 | |
|   MmioWrite32 (Register, RegisterValue);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write the data to the XHCI debug register.
 | |
| 
 | |
|   @param  Handle       Debug port handle.
 | |
|   @param  Offset       The offset of the debug register.
 | |
|   @param  Data         The data to write.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| XhcWriteDebugReg (
 | |
|   IN USB3_DEBUG_PORT_HANDLE  *Handle,
 | |
|   IN UINT32                  Offset,
 | |
|   IN UINT32                  Data
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS  DebugCapabilityBase;
 | |
| 
 | |
|   DebugCapabilityBase = Handle->DebugCapabilityBase;
 | |
|   MmioWrite32 ((UINTN)(DebugCapabilityBase + Offset), Data);
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read XHCI debug register.
 | |
| 
 | |
|   @param  Handle       Debug port handle.
 | |
|   @param  Offset       The offset of the runtime register.
 | |
| 
 | |
|   @return The register content read
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| XhcReadDebugReg (
 | |
|   IN  USB3_DEBUG_PORT_HANDLE *Handle,
 | |
|   IN  UINT32                 Offset
 | |
|   )
 | |
| {
 | |
|   UINT32                  Data;
 | |
|   EFI_PHYSICAL_ADDRESS    DebugCapabilityBase;
 | |
| 
 | |
|   DebugCapabilityBase = Handle->DebugCapabilityBase;
 | |
|   Data = MmioRead32 ((UINTN)(DebugCapabilityBase + Offset));
 | |
| 
 | |
|   return Data;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set one bit of the debug register while keeping other bits.
 | |
| 
 | |
|   @param  Handle       Debug port handle.
 | |
|   @param  Offset       The offset of the debug register.
 | |
|   @param  Bit          The bit mask of the register to set.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| XhcSetDebugRegBit (
 | |
|   IN USB3_DEBUG_PORT_HANDLE   *Handle,
 | |
|   IN UINT32                   Offset,
 | |
|   IN UINT32                   Bit
 | |
|   )
 | |
| {
 | |
|   UINT32                  Data;
 | |
| 
 | |
|   Data  = XhcReadDebugReg (Handle, Offset);
 | |
|   Data |= Bit;
 | |
|   XhcWriteDebugReg (Handle, Offset, Data);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Clear one bit of the debug register while keeping other bits.
 | |
| 
 | |
|   @param  Handle       Debug port handle.
 | |
|   @param  Offset       The offset of the debug register.
 | |
|   @param  Bit          The bit mask of the register to clear.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| XhcClearDebugRegBit (
 | |
|   IN USB3_DEBUG_PORT_HANDLE   *Handle,
 | |
|   IN UINT32                   Offset,
 | |
|   IN UINT32                   Bit
 | |
|   )
 | |
| {
 | |
|   UINT32                  Data;
 | |
| 
 | |
|   Data  = XhcReadDebugReg (Handle, Offset);
 | |
|   Data  &= ~Bit;
 | |
|   XhcWriteDebugReg (Handle, Offset, Data);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Program and enable XHCI MMIO base address.
 | |
| 
 | |
|   @return XHCI MMIO base address.
 | |
| 
 | |
| **/
 | |
| EFI_PHYSICAL_ADDRESS
 | |
| ProgramXhciBaseAddress (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT16                      PciCmd;
 | |
|   UINT32                      Low;
 | |
|   UINT32                      High;
 | |
|   EFI_PHYSICAL_ADDRESS        XhciMmioBase;
 | |
| 
 | |
|   Low = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET);
 | |
|   High = PciRead32 (PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4);
 | |
|   XhciMmioBase = (EFI_PHYSICAL_ADDRESS) (LShiftU64 ((UINT64) High, 32) | Low);
 | |
|   XhciMmioBase &= XHCI_BASE_ADDRESS_64_BIT_MASK;
 | |
| 
 | |
|   if ((XhciMmioBase == 0) || (XhciMmioBase == XHCI_BASE_ADDRESS_64_BIT_MASK)) {
 | |
|     XhciMmioBase = PcdGet64(PcdUsbXhciMemorySpaceBase);
 | |
|     PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET, XhciMmioBase & 0xFFFFFFFF);
 | |
|     PciWrite32(PcdGet32(PcdUsbXhciPciAddress) + PCI_BASE_ADDRESSREG_OFFSET + 4, (RShiftU64 (XhciMmioBase, 32) & 0xFFFFFFFF));
 | |
|   }
 | |
| 
 | |
|   PciCmd = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET);
 | |
|   if (((PciCmd & EFI_PCI_COMMAND_MEMORY_SPACE) == 0) || ((PciCmd & EFI_PCI_COMMAND_BUS_MASTER) == 0)) {
 | |
|     PciCmd |= EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER;
 | |
|     PciWrite16(PcdGet32(PcdUsbXhciPciAddress) + PCI_COMMAND_OFFSET, PciCmd);
 | |
|   }
 | |
| 
 | |
|   return XhciMmioBase;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update XHC MMIO base address when MMIO base address is changed.
 | |
| 
 | |
|   @param  Handle          Debug port handle.
 | |
|   @param  XhciMmioBase    XHCI MMIO base address.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| UpdateXhcResource (
 | |
|   IN OUT USB3_DEBUG_PORT_HANDLE            *Handle,
 | |
|   IN EFI_PHYSICAL_ADDRESS                   XhciMmioBase
 | |
|   )
 | |
| {
 | |
|   if (Handle == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Need fix Handle data according to new XHCI MMIO base address.
 | |
|   //
 | |
|   Handle->XhciMmioBase        = XhciMmioBase;
 | |
|   Handle->DebugCapabilityBase = XhciMmioBase + Handle->DebugCapabilityOffset;
 | |
|   Handle->XhciOpRegister      = XhciMmioBase + MmioRead8 ((UINTN)XhciMmioBase);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Calculate the usb debug port bar address.
 | |
| 
 | |
|   @param  Handle             Debug port handle.
 | |
| 
 | |
|   @retval RETURN_UNSUPPORTED The usb host controller does not support usb debug port capability.
 | |
|   @retval RETURN_SUCCESS     Get bar and offset successfully.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| CalculateUsbDebugPortMmioBase (
 | |
|   USB3_DEBUG_PORT_HANDLE          *Handle
 | |
|  )
 | |
| {
 | |
|   UINT16                          VendorId;
 | |
|   UINT16                          DeviceId;
 | |
|   UINT8                           ProgInterface;
 | |
|   UINT8                           SubClassCode;
 | |
|   UINT8                           BaseCode;
 | |
|   BOOLEAN                         Flag;
 | |
|   UINT32                          Capability;
 | |
|   EFI_PHYSICAL_ADDRESS            CapabilityPointer;
 | |
|   UINT8                           CapLength;
 | |
| 
 | |
|   if (Handle->Initialized != USB3DBG_UNINITIALIZED) {
 | |
|     if (Handle->Initialized == USB3DBG_NO_DBG_CAB) {
 | |
|       return RETURN_UNSUPPORTED;
 | |
|     } else {
 | |
|       return RETURN_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   VendorId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_VENDOR_ID_OFFSET);
 | |
|   DeviceId = PciRead16 (PcdGet32(PcdUsbXhciPciAddress) + PCI_DEVICE_ID_OFFSET);
 | |
| 
 | |
|   if ((VendorId == 0xFFFF) || (DeviceId == 0xFFFF)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   ProgInterface = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET);
 | |
|   SubClassCode  = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 1);
 | |
|   BaseCode      = PciRead8 (PcdGet32(PcdUsbXhciPciAddress) + PCI_CLASSCODE_OFFSET + 2);
 | |
| 
 | |
|   if ((ProgInterface != PCI_IF_XHCI) || (SubClassCode != PCI_CLASS_SERIAL_USB) || (BaseCode != PCI_CLASS_SERIAL)) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   CapLength = MmioRead8 ((UINTN) Handle->XhciMmioBase);
 | |
| 
 | |
|   //
 | |
|   // Get capability pointer from HCCPARAMS at offset 0x10
 | |
|   //
 | |
|   CapabilityPointer = Handle->XhciMmioBase + (MmioRead32 ((UINTN)(Handle->XhciMmioBase + XHC_HCCPARAMS_OFFSET)) >> 16) * 4;
 | |
| 
 | |
|   //
 | |
|   // Search XHCI debug capability
 | |
|   //
 | |
|   Flag = FALSE;
 | |
|   Capability = MmioRead32 ((UINTN)CapabilityPointer);
 | |
|   while (TRUE) {
 | |
|     if ((Capability & XHC_CAPABILITY_ID_MASK) == PCI_CAPABILITY_ID_DEBUG_PORT) {
 | |
|       Flag = TRUE;
 | |
|       break;
 | |
|     }
 | |
|     if ((((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) & XHC_CAPABILITY_ID_MASK) == 0) {
 | |
|       //
 | |
|       // Reach the end of capability list, quit
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
|     CapabilityPointer += ((Capability & XHC_NEXT_CAPABILITY_MASK) >> 8) * 4;
 | |
|     Capability = MmioRead32 ((UINTN)CapabilityPointer);
 | |
|   }
 | |
| 
 | |
|   if (!Flag) {
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // USB3 debug capability is supported.
 | |
|   //
 | |
|   Handle->DebugCapabilityBase   = CapabilityPointer;
 | |
|   Handle->DebugCapabilityOffset = CapabilityPointer - Handle->XhciMmioBase;
 | |
|   Handle->XhciOpRegister        = Handle->XhciMmioBase + CapLength;
 | |
|   Handle->DebugSupport = TRUE;
 | |
|   Handle->Initialized = USB3DBG_DBG_CAB;
 | |
|   return RETURN_SUCCESS;
 | |
| 
 | |
| Done:
 | |
|   Handle->Initialized = USB3DBG_NO_DBG_CAB;
 | |
|   return RETURN_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if it needs to re-initialize usb debug port hardware.
 | |
| 
 | |
|   During different phases switch, such as SEC to PEI or PEI to DXE or DXE to SMM, we should check
 | |
|   whether the usb debug port hardware configuration is changed. Such case can be triggered by
 | |
|   Pci bus resource allocation and so on.
 | |
| 
 | |
|   @param  Handle           Debug port handle.
 | |
| 
 | |
|   @retval TRUE             The usb debug port hardware configuration is changed.
 | |
|   @retval FALSE            The usb debug port hardware configuration is not changed.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| NeedReinitializeHardware(
 | |
|   IN USB3_DEBUG_PORT_HANDLE *Handle
 | |
|   )
 | |
| {
 | |
|   BOOLEAN                 Result;
 | |
|   volatile UINT32         Dcctrl;
 | |
| 
 | |
|   Result = FALSE;
 | |
| 
 | |
|   //
 | |
|   // If DCE bit, it means USB3 debug is not enabled.
 | |
|   //
 | |
|   Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
 | |
|   if ((Dcctrl & BIT0) == 0) {
 | |
|     Result = TRUE;
 | |
|   } else if (!Handle->Ready) {
 | |
|     Handle->Ready = TRUE;
 | |
|     Handle->Initialized = USB3DBG_ENABLED;
 | |
|   }
 | |
| 
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create XHCI event ring.
 | |
| 
 | |
|   @param  Handle              Debug port handle.
 | |
|   @param  EventRing           The created event ring.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CreateEventRing (
 | |
|   IN  USB3_DEBUG_PORT_HANDLE     *Handle,
 | |
|   OUT EVENT_RING                 *EventRing
 | |
|   )
 | |
| {
 | |
|   VOID                        *Buf;
 | |
|   EVENT_RING_SEG_TABLE_ENTRY  *ERSTBase;
 | |
| 
 | |
|   ASSERT (EventRing != NULL);
 | |
| 
 | |
|   //
 | |
|   // Allocate Event Ring
 | |
|   //
 | |
|   Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
 | |
|   ASSERT (Buf != NULL);
 | |
|   ASSERT (((UINTN) Buf & 0x3F) == 0);
 | |
|   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);
 | |
| 
 | |
|   EventRing->EventRingSeg0    = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
 | |
|   EventRing->TrbNumber        = EVENT_RING_TRB_NUMBER;
 | |
|   EventRing->EventRingDequeue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
 | |
|   EventRing->EventRingEnqueue = (EFI_PHYSICAL_ADDRESS)(UINTN) EventRing->EventRingSeg0;
 | |
| 
 | |
|   //
 | |
|   // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'
 | |
|   // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.
 | |
|   //
 | |
|   EventRing->EventRingCCS = 1;
 | |
| 
 | |
|   //
 | |
|   // Allocate Event Ring Segment Table Entry 0 in Event Ring Segment Table
 | |
|   //
 | |
|   Buf = AllocateAlignBuffer (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
 | |
|   ASSERT (Buf != NULL);
 | |
|   ASSERT (((UINTN) Buf & 0x3F) == 0);
 | |
|   ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);
 | |
| 
 | |
|   ERSTBase              = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;
 | |
|   EventRing->ERSTBase   = (EFI_PHYSICAL_ADDRESS)(UINTN) ERSTBase;
 | |
| 
 | |
|   //
 | |
|   // Fill Event Segment address
 | |
|   //
 | |
|   ERSTBase->PtrLo       = XHC_LOW_32BIT (EventRing->EventRingSeg0);
 | |
|   ERSTBase->PtrHi       = XHC_HIGH_32BIT (EventRing->EventRingSeg0);
 | |
|   ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;
 | |
| 
 | |
|   //
 | |
|   // Program the Interrupter Event Ring Dequeue Pointer (DCERDP) register (7.6.4.1)
 | |
|   //
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCERDP,
 | |
|     XHC_LOW_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
 | |
|     );
 | |
| 
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCERDP + 4,
 | |
|     XHC_HIGH_32BIT((UINT64)(UINTN)EventRing->EventRingDequeue)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Program the Debug Capability Event Ring Segment Table Base Address (DCERSTBA) register(7.6.4.1)
 | |
|   //
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCERSTBA,
 | |
|     XHC_LOW_32BIT((UINT64)(UINTN)ERSTBase)
 | |
|     );
 | |
| 
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCERSTBA + 4,
 | |
|     XHC_HIGH_32BIT((UINT64)(UINTN)ERSTBase)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Program the Debug Capability Event Ring Segment Table Size (DCERSTSZ) register(7.6.4.1)
 | |
|   //
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCERSTSZ,
 | |
|     ERST_NUMBER
 | |
|     );
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create XHCI transfer ring.
 | |
| 
 | |
|   @param  Handle            Debug port handle.
 | |
|   @param  TrbNum            The number of TRB in the ring.
 | |
|   @param  TransferRing      The created transfer ring.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CreateTransferRing (
 | |
|   IN  USB3_DEBUG_PORT_HANDLE      *Handle,
 | |
|   IN  UINT32                      TrbNum,
 | |
|   OUT TRANSFER_RING               *TransferRing
 | |
|   )
 | |
| {
 | |
|   VOID                  *Buf;
 | |
|   LINK_TRB              *EndTrb;
 | |
| 
 | |
|   Buf = AllocateAlignBuffer (sizeof (TRB_TEMPLATE) * TrbNum);
 | |
|   ASSERT (Buf != NULL);
 | |
|   ASSERT (((UINTN) Buf & 0xF) == 0);
 | |
|   ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
 | |
| 
 | |
|   TransferRing->RingSeg0     = (EFI_PHYSICAL_ADDRESS)(UINTN) Buf;
 | |
|   TransferRing->TrbNumber    = TrbNum;
 | |
|   TransferRing->RingEnqueue  = TransferRing->RingSeg0;
 | |
|   TransferRing->RingDequeue  = TransferRing->RingSeg0;
 | |
|   TransferRing->RingPCS      = 1;
 | |
|   //
 | |
|   // 4.9.2 Transfer Ring Management
 | |
|   // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to
 | |
|   // point to the first TRB in the ring.
 | |
|   //
 | |
|   EndTrb        = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));
 | |
|   EndTrb->Type  = TRB_TYPE_LINK;
 | |
|   EndTrb->PtrLo = XHC_LOW_32BIT (Buf);
 | |
|   EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);
 | |
|   //
 | |
|   // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.
 | |
|   //
 | |
|   EndTrb->TC    = 1;
 | |
|   //
 | |
|   // Set Cycle bit as other TRB PCS init value
 | |
|   //
 | |
|   EndTrb->CycleBit = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create debug capability context for XHC debug device.
 | |
| 
 | |
|   @param  Handle       Debug port handle.
 | |
| 
 | |
|   @retval EFI_SUCCESS  The bit successfully changed by host controller.
 | |
|   @retval EFI_TIMEOUT  The time out occurred.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CreateDebugCapabilityContext (
 | |
|   IN  USB3_DEBUG_PORT_HANDLE   *Handle
 | |
|   )
 | |
| {
 | |
|   VOID                        *Buf;
 | |
|   XHC_DC_CONTEXT              *DebugCapabilityContext;
 | |
|   UINT8                       *String0Desc;
 | |
|   UINT8                       *ManufacturerStrDesc;
 | |
|   UINT8                       *ProductStrDesc;
 | |
|   UINT8                       *SerialNumberStrDesc;
 | |
| 
 | |
|   //
 | |
|   // Allocate debug device context
 | |
|   //
 | |
|   Buf = AllocateAlignBuffer (sizeof (XHC_DC_CONTEXT));
 | |
|   ASSERT (Buf != NULL);
 | |
|   ASSERT (((UINTN) Buf & 0xF) == 0);
 | |
|   ZeroMem (Buf, sizeof (XHC_DC_CONTEXT));
 | |
| 
 | |
|   DebugCapabilityContext = (XHC_DC_CONTEXT *)(UINTN) Buf;
 | |
|   Handle->DebugCapabilityContext = (EFI_PHYSICAL_ADDRESS)(UINTN) DebugCapabilityContext;
 | |
| 
 | |
|   //
 | |
|   // Initialize DbcInfoContext.
 | |
|   //
 | |
|   DebugCapabilityContext->DbcInfoContext.String0Length         = STRING0_DESC_LEN;
 | |
|   DebugCapabilityContext->DbcInfoContext.ManufacturerStrLength = MANU_DESC_LEN;
 | |
|   DebugCapabilityContext->DbcInfoContext.ProductStrLength      = PRODUCT_DESC_LEN;
 | |
|   DebugCapabilityContext->DbcInfoContext.SerialNumberStrLength = SERIAL_DESC_LEN;
 | |
| 
 | |
|   //
 | |
|   // Initialize EpOutContext.
 | |
|   //
 | |
|   DebugCapabilityContext->EpOutContext.CErr             = 0x3;
 | |
|   DebugCapabilityContext->EpOutContext.EPType           = ED_BULK_OUT;
 | |
|   DebugCapabilityContext->EpOutContext.MaxPacketSize    = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
 | |
|   DebugCapabilityContext->EpOutContext.AverageTRBLength = 0x1000;
 | |
| 
 | |
|   //
 | |
|   // Initialize EpInContext.
 | |
|   //
 | |
|   DebugCapabilityContext->EpInContext.CErr             = 0x3;
 | |
|   DebugCapabilityContext->EpInContext.EPType           = ED_BULK_IN;
 | |
|   DebugCapabilityContext->EpInContext.MaxPacketSize    = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
 | |
|   DebugCapabilityContext->EpInContext.AverageTRBLength = 0x1000;
 | |
| 
 | |
|   //
 | |
|   // Update string descriptor address
 | |
|   //
 | |
|   String0Desc = (UINT8 *) AllocateAlignBuffer (STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
 | |
|   ASSERT (String0Desc != NULL);
 | |
|   ZeroMem (String0Desc, STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN);
 | |
|   CopyMem (String0Desc, mString0Desc, STRING0_DESC_LEN);
 | |
|   DebugCapabilityContext->DbcInfoContext.String0DescAddress = (UINT64)(UINTN)String0Desc;
 | |
| 
 | |
|   ManufacturerStrDesc = String0Desc + STRING0_DESC_LEN;
 | |
|   CopyMem (ManufacturerStrDesc, mManufacturerStrDesc, MANU_DESC_LEN);
 | |
|   DebugCapabilityContext->DbcInfoContext.ManufacturerStrDescAddress = (UINT64)(UINTN)ManufacturerStrDesc;
 | |
| 
 | |
|   ProductStrDesc = ManufacturerStrDesc + MANU_DESC_LEN;
 | |
|   CopyMem (ProductStrDesc, mProductStrDesc, PRODUCT_DESC_LEN);
 | |
|   DebugCapabilityContext->DbcInfoContext.ProductStrDescAddress = (UINT64)(UINTN)ProductStrDesc;
 | |
| 
 | |
|   SerialNumberStrDesc = ProductStrDesc + PRODUCT_DESC_LEN;
 | |
|   CopyMem (SerialNumberStrDesc, mSerialNumberStrDesc, SERIAL_DESC_LEN);
 | |
|   DebugCapabilityContext->DbcInfoContext.SerialNumberStrDescAddress = (UINT64)(UINTN)SerialNumberStrDesc;
 | |
| 
 | |
|   //
 | |
|   // Allocate and initialize the Transfer Ring for the Input Endpoint Context.
 | |
|   //
 | |
|   ZeroMem (&Handle->TransferRingIn, sizeof (TRANSFER_RING));
 | |
|   CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingIn);
 | |
|   DebugCapabilityContext->EpInContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingIn.RingSeg0) | BIT0;
 | |
|   DebugCapabilityContext->EpInContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingIn.RingSeg0);
 | |
| 
 | |
|   //
 | |
|   // Allocate and initialize the Transfer Ring for the Output Endpoint Context.
 | |
|   //
 | |
|   ZeroMem (&Handle->TransferRingOut, sizeof (TRANSFER_RING));
 | |
|   CreateTransferRing (Handle, TR_RING_TRB_NUMBER, &Handle->TransferRingOut);
 | |
|   DebugCapabilityContext->EpOutContext.PtrLo = XHC_LOW_32BIT (Handle->TransferRingOut.RingSeg0) | BIT0;
 | |
|   DebugCapabilityContext->EpOutContext.PtrHi = XHC_HIGH_32BIT (Handle->TransferRingOut.RingSeg0);
 | |
| 
 | |
|   //
 | |
|   // Program the Debug Capability Context Pointer (DCCP) register(7.6.8.7)
 | |
|   //
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCCP,
 | |
|     XHC_LOW_32BIT((UINT64)(UINTN)DebugCapabilityContext)
 | |
|     );
 | |
|   XhcWriteDebugReg (
 | |
|     Handle,
 | |
|     XHC_DC_DCCP + 4,
 | |
|     XHC_HIGH_32BIT((UINT64)(UINTN)DebugCapabilityContext)
 | |
|     );
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if debug device is running.
 | |
| 
 | |
|   @param  Handle       Debug port handle.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| XhcDetectDebugCapabilityReady (
 | |
|   IN USB3_DEBUG_PORT_HANDLE *Handle
 | |
|   )
 | |
| {
 | |
|   UINT64                          TimeOut;
 | |
|   volatile UINT32                 Dcctrl;
 | |
| 
 | |
|   TimeOut = 1;
 | |
|   if (Handle->Initialized == USB3DBG_DBG_CAB) {
 | |
|     //
 | |
|     // As detection is slow in seconds, wait for longer timeout for the first time.
 | |
|     // If first initialization is failed, we will try to enable debug device in the
 | |
|     // Poll function invoked by timer.
 | |
|     //
 | |
|     TimeOut = DivU64x32 (PcdGet64 (PcdUsbXhciDebugDetectTimeout), XHC_POLL_DELAY) + 1;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     //
 | |
|     // Check if debug device is in configured state
 | |
|     //
 | |
|     Dcctrl = XhcReadDebugReg (Handle, XHC_DC_DCCTRL);
 | |
|     if ((Dcctrl & BIT0) != 0) {
 | |
|       //
 | |
|       // Set the flag to indicate debug device is in configured state
 | |
|       //
 | |
|       Handle->Ready = TRUE;
 | |
|       break;
 | |
|     }
 | |
|     MicroSecondDelay (XHC_POLL_DELAY);
 | |
|     TimeOut--;
 | |
|   } while (TimeOut != 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize usb debug port hardware.
 | |
| 
 | |
|   @param  Handle           Debug port handle.
 | |
| 
 | |
|   @retval TRUE             The usb debug port hardware configuration is changed.
 | |
|   @retval FALSE            The usb debug port hardware configuration is not changed.
 | |
| 
 | |
| **/
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| InitializeUsbDebugHardware (
 | |
|   IN USB3_DEBUG_PORT_HANDLE *Handle
 | |
|   )
 | |
| {
 | |
|   RETURN_STATUS                   Status;
 | |
|   UINT8                           *Buffer;
 | |
|   UINTN                           Index;
 | |
|   UINT8                           TotalUsb3Port;
 | |
|   EFI_PHYSICAL_ADDRESS            XhciOpRegister;
 | |
|   UINT32                          Dcddi1;
 | |
| 
 | |
|   XhciOpRegister = Handle->XhciOpRegister;
 | |
|   TotalUsb3Port = MmioRead32 (((UINTN) Handle->XhciMmioBase + XHC_HCSPARAMS1_OFFSET)) >> 24;
 | |
| 
 | |
|   if (Handle->Initialized == USB3DBG_NOT_ENABLED) {
 | |
|     Dcddi1 = XhcReadDebugReg (Handle,XHC_DC_DCDDI1);
 | |
|     if (Dcddi1 != (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)) {
 | |
|       //
 | |
|       // The debug capability has been reset by other code, return device error.
 | |
|       //
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
|     //
 | |
|     // If XHCI supports debug capability, hardware resource has been allocated,
 | |
|     // but it has not been enabled, try to enable again.
 | |
|     //
 | |
|     goto Enable;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize for PEI phase when AllocatePages can work.
 | |
|   // Allocate data buffer with max packet size for data read and data poll.
 | |
|   // Allocate data buffer for data write.
 | |
|   //
 | |
|   Buffer = AllocateAlignBuffer (XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE);
 | |
|   if (Buffer == NULL) {
 | |
|     //
 | |
|     // AllocatePages can not still work now, return fail and do not initialize now.
 | |
|     //
 | |
|     return RETURN_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Reset port to get debug device discovered
 | |
|   //
 | |
|   for (Index = 0; Index < TotalUsb3Port; Index++) {
 | |
|     XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT4);
 | |
|     MicroSecondDelay (10 * 1000);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Clear DCE bit and LSE bit in DCCTRL
 | |
|   //
 | |
|   if ((XhcReadDebugReg (Handle, XHC_DC_DCCTRL) & (BIT1|BIT31)) == (BIT1|BIT31)) {
 | |
|     XhcClearDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Construct the buffer for read, poll and write.
 | |
|   //
 | |
|   Handle->UrbIn.Data  = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer;
 | |
|   Handle->Data        = (EFI_PHYSICAL_ADDRESS)(UINTN) Buffer + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
 | |
|   Handle->UrbOut.Data = Handle->UrbIn.Data + XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2;
 | |
| 
 | |
|   //
 | |
|   // Initialize event ring
 | |
|   //
 | |
|   ZeroMem (&Handle->EventRing, sizeof (EVENT_RING));
 | |
|   Status = CreateEventRing (Handle, &Handle->EventRing);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Init IN and OUT endpoint context
 | |
|   //
 | |
|   Status = CreateDebugCapabilityContext (Handle);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Init DCDDI1 and DCDDI2
 | |
|   //
 | |
|   XhcWriteDebugReg (
 | |
|    Handle,
 | |
|    XHC_DC_DCDDI1,
 | |
|    (UINT32)((XHCI_DEBUG_DEVICE_VENDOR_ID << 16) | XHCI_DEBUG_DEVICE_PROTOCOL)
 | |
|    );
 | |
| 
 | |
|   XhcWriteDebugReg (
 | |
|    Handle,
 | |
|    XHC_DC_DCDDI2,
 | |
|    (UINT32)((XHCI_DEBUG_DEVICE_REVISION << 16) | XHCI_DEBUG_DEVICE_PRODUCT_ID)
 | |
|    );
 | |
| 
 | |
| Enable:
 | |
|   if ((Handle->Initialized == USB3DBG_NOT_ENABLED) && (!Handle->ChangePortPower)) {
 | |
|     //
 | |
|     // If the first time detection is failed, turn port power off and on in order to
 | |
|     // reset port status this time, then try to check if debug device is ready again.
 | |
|     //
 | |
|     for (Index = 0; Index < TotalUsb3Port; Index++) {
 | |
|       XhcClearR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
 | |
|       MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
 | |
|       XhcSetR32Bit ((UINTN)XhciOpRegister + XHC_PORTSC_OFFSET + Index * 0x10, BIT9);
 | |
|       MicroSecondDelay (XHC_DEBUG_PORT_ON_OFF_DELAY);
 | |
|       Handle->ChangePortPower = TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set DCE bit and LSE bit to "1" in DCCTRL in first initialization
 | |
|   //
 | |
|   XhcSetDebugRegBit (Handle, XHC_DC_DCCTRL, BIT1|BIT31);
 | |
| 
 | |
|   XhcDetectDebugCapabilityReady (Handle);
 | |
| 
 | |
|   Status = RETURN_SUCCESS;
 | |
|   if (!Handle->Ready) {
 | |
|     Handle->Initialized = USB3DBG_NOT_ENABLED;
 | |
|     Status = RETURN_NOT_READY;
 | |
|   } else {
 | |
|     Handle->Initialized = USB3DBG_ENABLED;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Discover and initialize usb debug port.
 | |
| 
 | |
|   @param Handle                 Debug port handle.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| DiscoverInitializeUsbDebugPort (
 | |
|   IN USB3_DEBUG_PORT_HANDLE     *Handle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_PHYSICAL_ADDRESS          XhciMmioBase;
 | |
| 
 | |
|   //
 | |
|   // Read 64-bit MMIO base address
 | |
|   //
 | |
|   XhciMmioBase = ProgramXhciBaseAddress ();
 | |
|   Handle->XhciMmioBase = XhciMmioBase;
 | |
| 
 | |
|   Status = CalculateUsbDebugPortMmioBase (Handle);
 | |
|   if (!RETURN_ERROR (Status)) {
 | |
|     UpdateXhcResource (Handle, XhciMmioBase);
 | |
|     if (NeedReinitializeHardware (Handle)) {
 | |
|       InitializeUsbDebugHardware (Handle);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set USB3 debug instance address.
 | |
| 
 | |
|   @param[in] Instance           Debug port instance.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SetUsb3DebugPortInstance (
 | |
|   IN USB3_DEBUG_PORT_HANDLE     *Instance
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS          *AddrPtr;
 | |
| 
 | |
|   AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
 | |
|   ASSERT (AddrPtr != NULL);
 | |
|   *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return USB3 debug instance address.
 | |
| 
 | |
| **/
 | |
| USB3_DEBUG_PORT_HANDLE *
 | |
| GetUsb3DebugPortInstance (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_PHYSICAL_ADDRESS          *AddrPtr;
 | |
|   USB3_DEBUG_PORT_HANDLE        *Instance;
 | |
| 
 | |
|   AddrPtr = GetUsb3DebugPortInstanceAddrPtr ();
 | |
|   ASSERT (AddrPtr != NULL);
 | |
| 
 | |
|   Instance = (USB3_DEBUG_PORT_HANDLE *) (UINTN) *AddrPtr;
 | |
| 
 | |
|   return Instance;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read data from debug device and save the data in buffer.
 | |
| 
 | |
|   Reads NumberOfBytes data bytes from a debug device into the buffer
 | |
|   specified by Buffer. The number of bytes actually read is returned.
 | |
|   If the return value is less than NumberOfBytes, then the rest operation failed.
 | |
|   If NumberOfBytes is zero, then return 0.
 | |
| 
 | |
|   @param  Handle           Debug port handle.
 | |
|   @param  Buffer           Pointer to the data buffer to store the data read from the debug device.
 | |
|   @param  NumberOfBytes    Number of bytes which will be read.
 | |
|   @param  Timeout          Timeout value for reading from debug device. Its unit is Microsecond.
 | |
| 
 | |
|   @retval 0                Read data failed, no data is to be read.
 | |
|   @retval >0               Actual number of bytes read from debug device.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| EFIAPI
 | |
| DebugPortReadBuffer (
 | |
|   IN   DEBUG_PORT_HANDLE        Handle,
 | |
|   IN   UINT8                    *Buffer,
 | |
|   IN   UINTN                    NumberOfBytes,
 | |
|   IN   UINTN                    Timeout
 | |
|   )
 | |
| {
 | |
|   USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;
 | |
|   UINT8                     Index;
 | |
|   UINT8                     *Data;
 | |
| 
 | |
|   if (NumberOfBytes != 1 || Buffer == NULL || Timeout != 0) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If Handle is NULL, get own instance.
 | |
|   // If Handle is not NULL, use it and set the instance.
 | |
|   //
 | |
|   if (Handle != NULL) {
 | |
|     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *) Handle;
 | |
|     SetUsb3DebugPortInstance (UsbDebugPortHandle);
 | |
|   } else {
 | |
|     UsbDebugPortHandle = GetUsb3DebugPortInstance ();
 | |
|   }
 | |
|   if (UsbDebugPortHandle == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (UsbDebugPortHandle->InNotify) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
 | |
| 
 | |
|   if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   Data = (UINT8 *)(UINTN)UsbDebugPortHandle->Data;
 | |
| 
 | |
|   //
 | |
|   // Read data from buffer
 | |
|   //
 | |
|   if (UsbDebugPortHandle->DataCount < 1) {
 | |
|     return 0;
 | |
|   } else {
 | |
|     *Buffer = Data[0];
 | |
| 
 | |
|     for (Index = 0; Index < UsbDebugPortHandle->DataCount - 1; Index++) {
 | |
|       if ((Index + 1) >= XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
 | |
|         return 0;
 | |
|       }
 | |
|       Data[Index] = Data[Index + 1];
 | |
|     }
 | |
|     UsbDebugPortHandle->DataCount = (UINT8)(UsbDebugPortHandle->DataCount - 1);
 | |
|     return 1;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write data from buffer to debug device.
 | |
| 
 | |
|   Writes NumberOfBytes data bytes from Buffer to the debug device.
 | |
|   The number of bytes actually written to the debug device is returned.
 | |
|   If the return value is less than NumberOfBytes, then the write operation failed.
 | |
|   If NumberOfBytes is zero, then return 0.
 | |
| 
 | |
|   @param  Handle           Debug port handle.
 | |
|   @param  Buffer           Pointer to the data buffer to be written.
 | |
|   @param  NumberOfBytes    Number of bytes to written to the debug device.
 | |
| 
 | |
|   @retval 0                NumberOfBytes is 0.
 | |
|   @retval >0               The number of bytes written to the debug device.
 | |
|                            If this value is less than NumberOfBytes, then the write operation failed.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| EFIAPI
 | |
| DebugPortWriteBuffer (
 | |
|   IN   DEBUG_PORT_HANDLE    Handle,
 | |
|   IN   UINT8                *Buffer,
 | |
|   IN   UINTN                NumberOfBytes
 | |
|   )
 | |
| {
 | |
|   USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;
 | |
|   UINTN                     Sent;
 | |
|   UINTN                     Total;
 | |
| 
 | |
|   if (NumberOfBytes == 0 || Buffer == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   Sent  = 0;
 | |
|   Total = 0;
 | |
| 
 | |
|   //
 | |
|   // If Handle is NULL, get own instance.
 | |
|   // If Handle is not NULL, use it and set the instance.
 | |
|   //
 | |
|   if (Handle != NULL) {
 | |
|     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *) Handle;
 | |
|     SetUsb3DebugPortInstance (UsbDebugPortHandle);
 | |
|   } else {
 | |
|     UsbDebugPortHandle = GetUsb3DebugPortInstance ();
 | |
|   }
 | |
|   if (UsbDebugPortHandle == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (UsbDebugPortHandle->InNotify) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
 | |
| 
 | |
|   if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // When host is trying to send data, write will be blocked.
 | |
|   // Poll to see if there is any data sent by host at first.
 | |
|   //
 | |
|   DebugPortPollBuffer (UsbDebugPortHandle);
 | |
| 
 | |
|   while ((Total < NumberOfBytes)) {
 | |
|     if (NumberOfBytes - Total > USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE) {
 | |
|       Sent = USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE;
 | |
|     } else {
 | |
|       Sent = (UINT8)(NumberOfBytes - Total);
 | |
|     }
 | |
|     XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataOut, Buffer + Total, &Sent, DATA_TRANSFER_WRITE_TIMEOUT);
 | |
|     Total += Sent;
 | |
|   }
 | |
| 
 | |
|   return Total;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Polls a debug device to see if there is any data waiting to be read.
 | |
| 
 | |
|   Polls a debug device to see if there is any data waiting to be read.
 | |
|   If there is data waiting to be read from the debug device, then TRUE is returned.
 | |
|   If there is no data waiting to be read from the debug device, then FALSE is returned.
 | |
| 
 | |
|   @param  Handle           Debug port handle.
 | |
| 
 | |
|   @retval TRUE             Data is waiting to be read from the debug device.
 | |
|   @retval FALSE            There is no data waiting to be read from the debug device.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| DebugPortPollBuffer (
 | |
|   IN DEBUG_PORT_HANDLE      Handle
 | |
|   )
 | |
| {
 | |
|   USB3_DEBUG_PORT_HANDLE     *UsbDebugPortHandle;
 | |
|   UINTN                     Length;
 | |
| 
 | |
|   //
 | |
|   // If Handle is NULL, get own instance.
 | |
|   // If Handle is not NULL, use it and set the instance.
 | |
|   //
 | |
|   if (Handle != NULL) {
 | |
|     UsbDebugPortHandle = (USB3_DEBUG_PORT_HANDLE *) Handle;
 | |
|     SetUsb3DebugPortInstance (UsbDebugPortHandle);
 | |
|   } else {
 | |
|     UsbDebugPortHandle = GetUsb3DebugPortInstance ();
 | |
|   }
 | |
|   if (UsbDebugPortHandle == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (UsbDebugPortHandle->InNotify) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
 | |
| 
 | |
|   if (UsbDebugPortHandle->Initialized != USB3DBG_ENABLED) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If the data buffer is not empty, then return TRUE directly.
 | |
|   // Otherwise initialize a usb read transaction and read data to internal data buffer.
 | |
|   //
 | |
|   if (UsbDebugPortHandle->DataCount != 0) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Read data as much as we can
 | |
|   //
 | |
|   Length = XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE;
 | |
|   XhcDataTransfer (UsbDebugPortHandle, EfiUsbDataIn, (VOID *)(UINTN)UsbDebugPortHandle->Data, &Length, DATA_TRANSFER_POLL_TIMEOUT);
 | |
| 
 | |
|   if (Length > XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (Length == 0) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Store data into internal buffer for use later
 | |
|   //
 | |
|   UsbDebugPortHandle->DataCount = (UINT8) Length;
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize the debug port.
 | |
| 
 | |
|   If Function is not NULL, Debug Communication Library will call this function
 | |
|   by passing in the Context to be the first parameter. If needed, Debug Communication
 | |
|   Library will create one debug port handle to be the second argument passing in
 | |
|   calling the Function, otherwise it will pass NULL to be the second argument of
 | |
|   Function.
 | |
| 
 | |
|   If Function is NULL, and Context is not NULL, the Debug Communication Library could
 | |
|     a) Return the same handle as passed in (as Context parameter).
 | |
|     b) Ignore the input Context parameter and create new handle to be returned.
 | |
| 
 | |
|   If parameter Function is NULL and Context is NULL, Debug Communication Library could
 | |
|   created a new handle if needed and return it, otherwise it will return NULL.
 | |
| 
 | |
|   @param[in] Context      Context needed by callback function; it was optional.
 | |
|   @param[in] Function     Continue function called by Debug Communication library;
 | |
|                           it was optional.
 | |
| 
 | |
|   @return  The debug port handle created by Debug Communication Library if Function
 | |
|            is not NULL.
 | |
| 
 | |
| **/
 | |
| DEBUG_PORT_HANDLE
 | |
| EFIAPI
 | |
| DebugPortInitialize (
 | |
|   IN VOID                 *Context,
 | |
|   IN DEBUG_PORT_CONTINUE  Function
 | |
|   )
 | |
| {
 | |
|   USB3_DEBUG_PORT_HANDLE    *UsbDebugPortHandle;
 | |
| 
 | |
|   //
 | |
|   // Validate the PCD PcdDebugPortHandleBufferSize value
 | |
|   //
 | |
|   ASSERT (PcdGet16 (PcdDebugPortHandleBufferSize) == sizeof (USB3_DEBUG_PORT_HANDLE));
 | |
| 
 | |
|   if (Function == NULL && Context != NULL) {
 | |
|     SetUsb3DebugPortInstance ((USB3_DEBUG_PORT_HANDLE *) Context);
 | |
|     return (DEBUG_PORT_HANDLE) Context;
 | |
|   }
 | |
|   UsbDebugPortHandle = GetUsb3DebugPortInstance ();
 | |
|   if (UsbDebugPortHandle == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   DiscoverInitializeUsbDebugPort (UsbDebugPortHandle);
 | |
| 
 | |
|   if (Function != NULL) {
 | |
|     Function (Context, (DEBUG_PORT_HANDLE) UsbDebugPortHandle);
 | |
|   }
 | |
| 
 | |
|   return (DEBUG_PORT_HANDLE) UsbDebugPortHandle;
 | |
| }
 |