<commit_before>/** @file  
  The Ehci controller driver.

  EhciDxe driver is responsible for managing the behavior of EHCI controller. 
  It implements the interfaces of monitoring the status of all ports and transferring 
  Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.

  Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
  to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or 
  OHCI controller.  This way avoids the control transfer on a shared port between EHCI 
  and companion host controller when UHCI or OHCI gets attached earlier than EHCI and a 
  USB 2.0 device inserts.

Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

Based on the files under MdeModulePkg/Bus/Pci/EhciDxe/

**/


#include "Ehci.h"

//
// Two arrays used to translate the EHCI port state (change)
// to the UEFI protocol's port state (change).
//
USB_PORT_STATE_MAP  mUsbPortStateMap[] = {
  {PORTSC_CONN,     USB_PORT_STAT_CONNECTION},
  {PORTSC_ENABLED,  USB_PORT_STAT_ENABLE},
  {PORTSC_SUSPEND,  USB_PORT_STAT_SUSPEND},
  {PORTSC_OVERCUR,  USB_PORT_STAT_OVERCURRENT},
  {PORTSC_RESET,    USB_PORT_STAT_RESET},
  {PORTSC_POWER,    USB_PORT_STAT_POWER},
  {PORTSC_OWNER,    USB_PORT_STAT_OWNER}
};

USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
  {PORTSC_CONN_CHANGE,    USB_PORT_STAT_C_CONNECTION},
  {PORTSC_ENABLE_CHANGE,  USB_PORT_STAT_C_ENABLE},
  {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
};

EFI_DRIVER_BINDING_PROTOCOL
gEhciDriverBinding = {
  EhcDriverBindingSupported,
  EhcDriverBindingStart,
  EhcDriverBindingStop,
  0x30,
  NULL,
  NULL
};

EFI_HANDLE      gGlobalController = NULL;
BOOLEAN         gEhciAleadyInit = FALSE;

EFI_CPU_ARCH_PROTOCOL      *gCpu;

typedef struct {
  EFI_PHYSICAL_ADDRESS              HostAddress;
  EFI_PHYSICAL_ADDRESS              DeviceAddress;
  UINTN                             NumberOfBytes;
  EFI_PCI_IO_PROTOCOL_OPERATION     Operation;
  BOOLEAN                           DoubleBuffer;
} MEM_MAP_INFO_INSTANCE;

VOID *
UncachedAllocatePagesBelow4G(
  IN UINTN  Pages
  ) 
{
  // Work around
#if 0
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;

  if (Pages == 0) {
    return NULL;
  }

  PhysicalAddress = 0xffffffff;
  Status = gBS->AllocatePages (
                  AllocateMaxAddress,
                  EfiBootServicesData,
                  Pages,
                  &PhysicalAddress
                  );
  
  if (EFI_ERROR (Status)) {    
    return NULL;
  }
  
  Status = gDS->GetMemorySpaceDescriptor (PhysicalAddress, &Descriptor);
  if (!EFI_ERROR (Status)) {
    // We are making an assumption that all of memory has the same default attributes
    //gAttributes = Descriptor.Attributes;
  }

  Status = gDS->SetMemorySpaceAttributes (PhysicalAddress, EFI_PAGES_TO_SIZE (Pages), EFI_MEMORY_WC);
  if (EFI_ERROR (Status)) {    
    return NULL;
  }
  
  (VOID)WriteBackInvalidateDataCacheRange((VOID *)(UINTN)PhysicalAddress, EFI_PAGES_TO_SIZE(Pages));
  
  return  (VOID *)(UINTN)PhysicalAddress;
#else
  return UncachedAllocatePages (Pages);
#endif
}

EFI_STATUS
EFIAPI
MemMap (
  IN     EFI_PCI_IO_PROTOCOL            *This,
  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
  IN     VOID                           *HostAddress,
  IN OUT UINTN                          *NumberOfBytes,
  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
  OUT    VOID                           **Mapping
  )
{
  EFI_STATUS                      Status;
  MEM_MAP_INFO_INSTANCE           *Map;
  VOID                            *Buffer;
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
  
  if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  *DeviceAddress = ConvertToPhysicalAddress (HostAddress);

  // Remember range so we can flush on the other side
  Map = AllocatePool (sizeof (MEM_MAP_INFO_INSTANCE));
  if (Map == NULL) {
    return  EFI_OUT_OF_RESOURCES;
  }  

  *Mapping = Map;

  if ((((UINTN)HostAddress & (EFI_PAGE_SIZE - 1)) != 0) ||
      ((*NumberOfBytes % EFI_PAGE_SIZE) != 0)) {
    
    // Get the cacheability of the region
    Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor);    
    if (EFI_ERROR(Status)) {
      return Status;
    }
    
    // If the mapped buffer is not an uncached buffer
    if ( (GcdDescriptor.Attributes != EFI_MEMORY_WC) &&
         (GcdDescriptor.Attributes != EFI_MEMORY_UC) )
    {        
      //
      // If the buffer does not fill entire cache lines we must double buffer into
      // uncached memory. Device (PCI) address becomes uncached page.
      //
      Map->DoubleBuffer  = TRUE;
      Buffer = UncachedAllocatePagesBelow4G(EFI_SIZE_TO_PAGES (*NumberOfBytes));
      
      if (Buffer == NULL) {
        return EFI_OUT_OF_RESOURCES;
      }

      (VOID)CopyMem(Buffer, HostAddress, *NumberOfBytes);

      *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
    } else {
      Map->DoubleBuffer  = FALSE;
    }
  } else {
    Map->DoubleBuffer  = FALSE;

    // Flush the Data Cache (should not have any effect if the memory region is uncached)
    gCpu->FlushDataCache (gCpu, *DeviceAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);

    Status = gDS->SetMemorySpaceAttributes (*DeviceAddress & ~(BASE_4KB - 1), ALIGN_VALUE (*NumberOfBytes, BASE_4KB), EFI_MEMORY_WC);
    //ASSERT_EFI_ERROR (Status);
    if (EFI_ERROR (Status)) {    
      DEBUG((EFI_D_ERROR, "[%a]:[%dL] SetMemorySpaceAttributes Fail. %r\n", __FUNCTION__, __LINE__, Status));
    }
  }

  Map->HostAddress   = (UINTN)HostAddress;
  Map->DeviceAddress = *DeviceAddress;
  Map->NumberOfBytes = *NumberOfBytes;
  Map->Operation     = Operation;

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
MemUnmap (
  IN  VOID                         *Mapping
  )<commit_msg>D02/Ehci: Do not convert memory attribute of caller's buffer<commit_after>/** @file  
  The Ehci controller driver.

  EhciDxe driver is responsible for managing the behavior of EHCI controller. 
  It implements the interfaces of monitoring the status of all ports and transferring 
  Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device.

  Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached
  to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or 
  OHCI controller.  This way avoids the control transfer on a shared port between EHCI 
  and companion host controller when UHCI or OHCI gets attached earlier than EHCI and a 
  USB 2.0 device inserts.

Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

Based on the files under MdeModulePkg/Bus/Pci/EhciDxe/

**/


#include "Ehci.h"

//
// Two arrays used to translate the EHCI port state (change)
// to the UEFI protocol's port state (change).
//
USB_PORT_STATE_MAP  mUsbPortStateMap[] = {
  {PORTSC_CONN,     USB_PORT_STAT_CONNECTION},
  {PORTSC_ENABLED,  USB_PORT_STAT_ENABLE},
  {PORTSC_SUSPEND,  USB_PORT_STAT_SUSPEND},
  {PORTSC_OVERCUR,  USB_PORT_STAT_OVERCURRENT},
  {PORTSC_RESET,    USB_PORT_STAT_RESET},
  {PORTSC_POWER,    USB_PORT_STAT_POWER},
  {PORTSC_OWNER,    USB_PORT_STAT_OWNER}
};

USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
  {PORTSC_CONN_CHANGE,    USB_PORT_STAT_C_CONNECTION},
  {PORTSC_ENABLE_CHANGE,  USB_PORT_STAT_C_ENABLE},
  {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
};

EFI_DRIVER_BINDING_PROTOCOL
gEhciDriverBinding = {
  EhcDriverBindingSupported,
  EhcDriverBindingStart,
  EhcDriverBindingStop,
  0x30,
  NULL,
  NULL
};

EFI_HANDLE      gGlobalController = NULL;
BOOLEAN         gEhciAleadyInit = FALSE;

EFI_CPU_ARCH_PROTOCOL      *gCpu;

typedef struct {
  EFI_PHYSICAL_ADDRESS              HostAddress;
  EFI_PHYSICAL_ADDRESS              DeviceAddress;
  UINTN                             NumberOfBytes;
  EFI_PCI_IO_PROTOCOL_OPERATION     Operation;
  BOOLEAN                           DoubleBuffer;
} MEM_MAP_INFO_INSTANCE;

VOID *
UncachedAllocatePagesBelow4G(
  IN UINTN  Pages
  ) 
{
  // Work around
#if 0
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR   Descriptor;

  if (Pages == 0) {
    return NULL;
  }

  PhysicalAddress = 0xffffffff;
  Status = gBS->AllocatePages (
                  AllocateMaxAddress,
                  EfiBootServicesData,
                  Pages,
                  &PhysicalAddress
                  );
  
  if (EFI_ERROR (Status)) {    
    return NULL;
  }
  
  Status = gDS->GetMemorySpaceDescriptor (PhysicalAddress, &Descriptor);
  if (!EFI_ERROR (Status)) {
    // We are making an assumption that all of memory has the same default attributes
    //gAttributes = Descriptor.Attributes;
  }

  Status = gDS->SetMemorySpaceAttributes (PhysicalAddress, EFI_PAGES_TO_SIZE (Pages), EFI_MEMORY_WC);
  if (EFI_ERROR (Status)) {    
    return NULL;
  }
  
  (VOID)WriteBackInvalidateDataCacheRange((VOID *)(UINTN)PhysicalAddress, EFI_PAGES_TO_SIZE(Pages));
  
  return  (VOID *)(UINTN)PhysicalAddress;
#else
  return UncachedAllocatePages (Pages);
#endif
}

EFI_STATUS
EFIAPI
MemMap (
  IN     EFI_PCI_IO_PROTOCOL            *This,
  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
  IN     VOID                           *HostAddress,
  IN OUT UINTN                          *NumberOfBytes,
  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
  OUT    VOID                           **Mapping
  )
{
  EFI_STATUS                      Status;
  MEM_MAP_INFO_INSTANCE           *Map;
  VOID                            *Buffer;
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
  
  if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  *DeviceAddress = ConvertToPhysicalAddress (HostAddress);

  // Remember range so we can flush on the other side
  Map = AllocatePool (sizeof (MEM_MAP_INFO_INSTANCE));
  if (Map == NULL) {
    return  EFI_OUT_OF_RESOURCES;
  }  

  *Mapping = Map;

    
  // Get the cacheability of the region
  Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor);
  if (EFI_ERROR(Status)) {
    return Status;
  }

  // If the mapped buffer is not an uncached buffer
  if ( (GcdDescriptor.Attributes != EFI_MEMORY_WC) &&
       (GcdDescriptor.Attributes != EFI_MEMORY_UC) )
  {
    //
    // If the buffer does not fill entire cache lines we must double buffer into
    // uncached memory. Device (PCI) address becomes uncached page.
    //
    Map->DoubleBuffer  = TRUE;
    Buffer = UncachedAllocatePagesBelow4G(EFI_SIZE_TO_PAGES (*NumberOfBytes));
    
    if (Buffer == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }

    (VOID)CopyMem(Buffer, HostAddress, *NumberOfBytes);

    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
  } else {
    Map->DoubleBuffer  = FALSE;
  }

  Map->HostAddress   = (UINTN)HostAddress;
  Map->DeviceAddress = *DeviceAddress;
  Map->NumberOfBytes = *NumberOfBytes;
  Map->Operation     = Operation;

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
MemUnmap (
  IN  VOID                         *Mapping
  )
{'fraction_non_alphanumeric': 0.07667757774140753, 'fraction_numerical': 0.00425531914893617, 'mean_word_length': 2.9911822338340954, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5270841', 'n_tokens_mistral': 4058, 'n_tokens_neox': 3903, 'n_words': 1021}