Home | History | Annotate | Download | only in VirtualEhciPciIo
      1 /** @file
      2 *
      3 *  Copyright (c) 2016, Hisilicon Limited. All rights reserved.
      4 *  Copyright (c) 2016, Linaro Limited. All rights reserved.
      5 *
      6 *  This program and the accompanying materials
      7 *  are licensed and made available under the terms and conditions of the BSD License
      8 *  which accompanies this distribution.  The full text of the license may be found at
      9 *  http://opensource.org/licenses/bsd-license.php
     10 *
     11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 *
     14 **/
     15 
     16 #include "VirtualEhciPciIo.h"
     17 #include <Protocol/PciRootBridgeIo.h>
     18 
     19 UINT32 mUsbMemBase;
     20 UINTN mSegmentNumber  = 0;
     21 // Use 0xFF for the virtual PCI devices
     22 UINTN mBusNumber      = 0xFF;
     23 UINTN mDeviceNumber   = 0;
     24 UINTN mFunctionNumber = 0;
     25 
     26 typedef struct {
     27   EFI_PHYSICAL_ADDRESS              HostAddress;
     28   EFI_PHYSICAL_ADDRESS              DeviceAddress;
     29   UINTN                             NumberOfBytes;
     30   EFI_PCI_IO_PROTOCOL_OPERATION     Operation;
     31   BOOLEAN                           DoubleBuffer;
     32 } MEM_MAP_INFO_INSTANCE;
     33 
     34 
     35 EFI_CPU_ARCH_PROTOCOL      *gCpu;
     36 
     37 
     38 EHCI_PCI_CONFIG mEhciPciConfig = {
     39   {
     40     0x00,//UINT16  VendorId;
     41     0x00,//UINT16  DeviceId;
     42     0x00,//UINT16  Command;
     43     0x0010,//UINT16  Status;
     44     0x00,//UINT8   RevisionID;
     45     {
     46       PCI_IF_EHCI,//UINT8   ClassCode[3];
     47       PCI_CLASS_SERIAL_USB,
     48       PCI_CLASS_SERIAL
     49     },
     50     0x00,//UINT8   CacheLineSize;
     51     0x00,//UINT8   LatencyTimer;
     52     0x00,//UINT8   HeaderType;
     53     0x00//UINT8   BIST;
     54   },
     55   {
     56     {
     57       0x00,//UINT32  Bar[6];
     58       0x00,
     59       0x00,
     60       0x00,
     61       0x00,
     62       0x00
     63     },
     64     0x00,//UINT32  CISPtr;
     65     0x00,//UINT16  SubsystemVendorID;
     66     0x00,//UINT16  SubsystemID;
     67     0x00,//UINT32  ExpansionRomBar;
     68     0x40,//UINT8   CapabilityPtr;
     69     {
     70       0x00,//UINT8   Reserved1[3];
     71       0x00,
     72       0x00
     73     },
     74     0x00,//UINT32  Reserved2;
     75     0x00,//UINT8   InterruptLine;
     76     0x00,//UINT8   InterruptPin;
     77     0x00,//UINT8   MinGnt;
     78     0x00//UINT8   MaxLat;
     79   },
     80     0x0A,//  UINT8 CapabilityID offset 0x40
     81     0x00,// UINT8 NextItemPtr
     82     0x2000 //UINT16 DebugPort
     83 };
     84 
     85 
     86 
     87 EFI_STATUS
     88 EhciPciIoPollMem (
     89   IN EFI_PCI_IO_PROTOCOL           *This,
     90   IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
     91   IN  UINT8                        BarIndex,
     92   IN  UINT64                       Offset,
     93   IN  UINT64                       Mask,
     94   IN  UINT64                       Value,
     95   IN  UINT64                       Delay,
     96   OUT UINT64                       *Result
     97   )
     98 {
     99   ASSERT (FALSE);
    100   return EFI_UNSUPPORTED;
    101 }
    102 
    103 EFI_STATUS
    104 EhciPciIoPollIo (
    105   IN EFI_PCI_IO_PROTOCOL           *This,
    106   IN  EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    107   IN  UINT8                        BarIndex,
    108   IN  UINT64                       Offset,
    109   IN  UINT64                       Mask,
    110   IN  UINT64                       Value,
    111   IN  UINT64                       Delay,
    112   OUT UINT64                       *Result
    113   )
    114 {
    115   ASSERT (FALSE);
    116   return EFI_UNSUPPORTED;
    117 }
    118 
    119 EFI_STATUS
    120 EhciPciIoMemRead (
    121   IN EFI_PCI_IO_PROTOCOL              *This,
    122   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    123   IN     UINT8                        BarIndex,
    124   IN     UINT64                       Offset,
    125   IN     UINTN                        Count,
    126   IN OUT VOID                         *Buffer
    127   )
    128 {
    129   UINT32 i;
    130 
    131   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    132     return EFI_INVALID_PARAMETER;
    133   }
    134 
    135   if (Buffer == NULL) {
    136     return EFI_INVALID_PARAMETER;
    137   }
    138 
    139   if (BarIndex != 0) {
    140     return EFI_INVALID_PARAMETER;
    141   }
    142 
    143   Width     = Width & 0x03;
    144 
    145   //
    146   // Loop for each iteration and move the data
    147   //
    148   switch (Width) {
    149   case EfiPciWidthUint8:
    150     for (i = 0; i < Count; i++){
    151       *((UINT8 *)Buffer + i)= MmioRead8(mUsbMemBase + Offset + i);
    152     }
    153     break;
    154   case EfiPciWidthUint16:
    155     for (i = 0; i < Count; i++){
    156       *((UINT16 *)Buffer + i)= MmioRead16(mUsbMemBase + Offset + i * 2);
    157     }
    158     break;
    159   case EfiPciWidthUint32:
    160     for (i = 0; i < Count; i++){
    161       *((UINT32 *)Buffer + i)= MmioRead32(mUsbMemBase + Offset + i * 4);
    162     }
    163     break;
    164   case EfiPciWidthUint64:
    165     for (i = 0; i < Count; i++){
    166       *((UINT64 *)Buffer + i)= MmioRead64(mUsbMemBase + Offset + i * 8);
    167     }
    168     break;
    169   default:
    170     return EFI_INVALID_PARAMETER;
    171   }
    172 
    173   return EFI_SUCCESS;
    174 }
    175 
    176 EFI_STATUS
    177 EhciPciIoMemWrite (
    178   IN EFI_PCI_IO_PROTOCOL              *This,
    179   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    180   IN     UINT8                        BarIndex,
    181   IN     UINT64                       Offset,
    182   IN     UINTN                        Count,
    183   IN OUT VOID                         *Buffer
    184   )
    185 {
    186   UINT32 i;
    187 
    188   if ((UINT32)Width >= EfiPciIoWidthMaximum) {
    189     return EFI_INVALID_PARAMETER;
    190   }
    191 
    192   if (Buffer == NULL) {
    193     return EFI_INVALID_PARAMETER;
    194   }
    195 
    196   Width     = Width & 0x03;
    197 
    198   //
    199   // Loop for each iteration and move the data
    200   //
    201   switch (Width) {
    202   case EfiPciWidthUint8:
    203     for (i = 0; i < Count; i++){
    204       MmioWrite8(mUsbMemBase + Offset + i, *((UINT8 *)Buffer + i));
    205     }
    206     break;
    207   case EfiPciWidthUint16:
    208     for (i = 0; i < Count; i++){
    209       MmioWrite16(mUsbMemBase + Offset + i * 2, *((UINT16 *)Buffer + i));
    210     }
    211     break;
    212   case EfiPciWidthUint32:
    213     for (i = 0; i < Count; i++){
    214       MmioWrite32(mUsbMemBase + Offset + i * 4, *((UINT32 *)Buffer + i));
    215     }
    216     break;
    217   case EfiPciWidthUint64:
    218     for (i = 0; i < Count; i++){
    219       MmioWrite64(mUsbMemBase + Offset + i * 8, *((UINT64 *)Buffer + i));
    220     }
    221     break;
    222   default:
    223     return EFI_INVALID_PARAMETER;
    224   }
    225 
    226   return EFI_SUCCESS;
    227 
    228 }
    229 
    230 EFI_STATUS
    231 EhciPciIoIoRead (
    232   IN EFI_PCI_IO_PROTOCOL              *This,
    233   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    234   IN     UINT8                        BarIndex,
    235   IN     UINT64                       Offset,
    236   IN     UINTN                        Count,
    237   IN OUT VOID                         *Buffer
    238   )
    239 {
    240   ASSERT (FALSE);
    241   return EFI_UNSUPPORTED;
    242 }
    243 
    244 EFI_STATUS
    245 EhciPciIoIoWrite (
    246   IN EFI_PCI_IO_PROTOCOL              *This,
    247   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    248   IN     UINT8                        BarIndex,
    249   IN     UINT64                       Offset,
    250   IN     UINTN                        Count,
    251   IN OUT VOID                         *Buffer
    252   )
    253 {
    254   ASSERT (FALSE);
    255   return EFI_UNSUPPORTED;
    256 }
    257 
    258 EFI_STATUS
    259 EhciPciIoPciRead (
    260   IN     EFI_PCI_IO_PROTOCOL       *This,
    261   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
    262   IN     UINT32                     Offset,
    263   IN     UINTN                      Count,
    264   IN OUT VOID                      *Buffer
    265   )
    266 {
    267   UINT32 i;
    268   UINT8 *DataPtr;
    269 
    270   Width     = Width & 0x03;
    271 
    272   if (Offset < sizeof (EHCI_PCI_CONFIG) / sizeof (UINT8)){
    273 
    274     DataPtr = (UINT8 *)(&mEhciPciConfig) + Offset;
    275 
    276     switch (Width) {
    277     case EfiPciWidthUint8:
    278       for (i = 0; i < Count; i++){
    279         *((UINT8 *)Buffer + i)= *(DataPtr + i);
    280       }
    281       break;
    282     case EfiPciWidthUint16:
    283       for (i = 0; i < Count; i++){
    284         *((UINT16 *)Buffer + i)= *((UINT16 *)DataPtr + i);
    285       }
    286       break;
    287     case EfiPciWidthUint32:
    288       for (i = 0; i < Count; i++){
    289         *(UINT32 *)(Buffer + i)= *((UINT32 *)DataPtr + i);
    290       }
    291       break;
    292     case EfiPciWidthUint64:
    293       for (i = 0; i < Count; i++){
    294         *(UINT64 *)(Buffer + i)= *((UINT64 *)DataPtr + i);
    295       }
    296       break;
    297     default:
    298       return EFI_INVALID_PARAMETER;
    299     }
    300 
    301   } else {
    302     switch (Width) {
    303     case EfiPciWidthUint8:
    304         *(UINT8 *)Buffer = 0xFF;
    305       break;
    306     case EfiPciWidthUint16:
    307         *(UINT16 *)Buffer = 0xFFFF;
    308       break;
    309     case EfiPciWidthUint32:
    310         *(UINT32 *)Buffer = 0xFFFFFFFF;
    311       break;
    312     case EfiPciWidthUint64:
    313         *(UINT64 *)Buffer = 0xFFFFFFFFFFFFFFFF;
    314       break;
    315     default:
    316       return EFI_INVALID_PARAMETER;
    317     }
    318   }
    319 
    320   return EFI_SUCCESS;
    321 }
    322 
    323 EFI_STATUS
    324 EhciPciIoPciWrite (
    325   IN EFI_PCI_IO_PROTOCOL              *This,
    326   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    327   IN     UINT32                       Offset,
    328   IN     UINTN                        Count,
    329   IN OUT VOID                         *Buffer
    330   )
    331 {
    332 
    333   return EFI_SUCCESS;
    334 }
    335 
    336 EFI_STATUS
    337 EhciPciIoCopyMem (
    338   IN EFI_PCI_IO_PROTOCOL              *This,
    339   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
    340   IN     UINT8                        DestBarIndex,
    341   IN     UINT64                       DestOffset,
    342   IN     UINT8                        SrcBarIndex,
    343   IN     UINT64                       SrcOffset,
    344   IN     UINTN                        Count
    345   )
    346 {
    347   ASSERT (FALSE);
    348   return EFI_UNSUPPORTED;
    349 }
    350 
    351 EFI_STATUS
    352 EhciPciIoMap (
    353   IN EFI_PCI_IO_PROTOCOL                *This,
    354   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
    355   IN     VOID                           *HostAddress,
    356   IN OUT UINTN                          *NumberOfBytes,
    357   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
    358   OUT    VOID                           **Mapping
    359   )
    360 {
    361   EFI_STATUS                      Status;
    362   MEM_MAP_INFO_INSTANCE           *Map;
    363   VOID                            *Buffer;
    364   EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
    365 
    366   if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
    367     return EFI_INVALID_PARAMETER;
    368   }
    369 
    370   if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
    371     return EFI_INVALID_PARAMETER;
    372   }
    373 
    374   *DeviceAddress = ConvertToPhysicalAddress (HostAddress);
    375 
    376   // Remember range so we can flush on the other side
    377   Map = AllocatePool (sizeof (MEM_MAP_INFO_INSTANCE));
    378   if (Map == NULL) {
    379     return  EFI_OUT_OF_RESOURCES;
    380   }
    381 
    382   *Mapping = Map;
    383 
    384   if ((((UINTN)HostAddress & (EFI_PAGE_SIZE - 1)) != 0) ||
    385       ((*NumberOfBytes % EFI_PAGE_SIZE) != 0)) {
    386 
    387     // Get the cacheability of the region
    388     Status = gDS->GetMemorySpaceDescriptor (*DeviceAddress, &GcdDescriptor);
    389     if (EFI_ERROR(Status)) {
    390       return Status;
    391     }
    392 
    393     // If the mapped buffer is not an uncached buffer
    394     if ( (GcdDescriptor.Attributes != EFI_MEMORY_WC) &&
    395          (GcdDescriptor.Attributes != EFI_MEMORY_UC) )
    396     {
    397       //
    398       // If the buffer does not fill entire cache lines we must double buffer into
    399       // uncached memory. Device (PCI) address becomes uncached page.
    400       //
    401       Map->DoubleBuffer  = TRUE;
    402       Buffer = UncachedAllocatePages(EFI_SIZE_TO_PAGES (*NumberOfBytes));
    403 
    404       if (Buffer == NULL) {
    405         return EFI_OUT_OF_RESOURCES;
    406       }
    407 
    408     CopyMem (Buffer,  HostAddress, *NumberOfBytes);
    409       *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
    410     } else {
    411       Map->DoubleBuffer  = FALSE;
    412     }
    413   } else {
    414     Map->DoubleBuffer  = FALSE;
    415 
    416     // Flush the Data Cache (should not have any effect if the memory region is uncached)
    417     gCpu->FlushDataCache (gCpu, *DeviceAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate);
    418 
    419     Status = gDS->SetMemorySpaceAttributes (*DeviceAddress & ~(BASE_4KB - 1), ALIGN_VALUE (*NumberOfBytes, BASE_4KB), EFI_MEMORY_WC);
    420     if (EFI_ERROR (Status)) {
    421       DEBUG((EFI_D_ERROR, "[%a]:[%dL] SetMemorySpaceAttributes Fail. %r\n", __FUNCTION__, __LINE__, Status));
    422     }
    423   }
    424 
    425   Map->HostAddress   = (UINTN)HostAddress;
    426   Map->DeviceAddress = *DeviceAddress;
    427   Map->NumberOfBytes = *NumberOfBytes;
    428   Map->Operation     = Operation;
    429 
    430   return EFI_SUCCESS;
    431 }
    432 
    433 EFI_STATUS
    434 EhciPciIoUnmap (
    435   IN EFI_PCI_IO_PROTOCOL           *This,
    436   IN  VOID                         *Mapping
    437   )
    438 {
    439   MEM_MAP_INFO_INSTANCE *Map;
    440 
    441   if (Mapping == NULL) {
    442     return EFI_INVALID_PARAMETER;
    443   }
    444 
    445   Map = (MEM_MAP_INFO_INSTANCE *)Mapping;
    446 
    447   if (Map->DoubleBuffer) {
    448     if ((Map->Operation == EfiPciIoOperationBusMasterWrite) || (Map->Operation == EfiPciIoOperationBusMasterCommonBuffer)) {
    449       CopyMem ((VOID *)(UINTN)Map->HostAddress, (VOID *)(UINTN)Map->DeviceAddress, Map->NumberOfBytes);
    450     }
    451 
    452     if((VOID *)(UINTN)Map->DeviceAddress != NULL) {
    453       UncachedFreePages ((VOID *)(UINTN)Map->DeviceAddress, EFI_SIZE_TO_PAGES (Map->NumberOfBytes));
    454     }
    455 
    456 
    457   } else {
    458     if (Map->Operation == EfiPciIoOperationBusMasterWrite) {
    459       //
    460       // Make sure we read buffer from uncached memory and not the cache
    461       //
    462       gCpu->FlushDataCache (gCpu, Map->HostAddress, Map->NumberOfBytes, EfiCpuFlushTypeInvalidate);
    463     }
    464   }
    465 
    466   FreePool (Map);
    467 
    468   return EFI_SUCCESS;
    469 }
    470 
    471 
    472 
    473 EFI_STATUS
    474 EhciPciIoAllocateBuffer (
    475   IN EFI_PCI_IO_PROTOCOL  *This,
    476   IN  EFI_ALLOCATE_TYPE   Type,
    477   IN  EFI_MEMORY_TYPE     MemoryType,
    478   IN  UINTN               Pages,
    479   OUT VOID                **HostAddress,
    480   IN  UINT64              Attributes
    481   )
    482 {
    483   UINT32 HcCapParams;
    484 
    485   if (Attributes &
    486       (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
    487          EFI_PCI_ATTRIBUTE_MEMORY_CACHED         ))) {
    488     return EFI_UNSUPPORTED;
    489   }
    490 
    491   if (HostAddress == NULL) {
    492     return EFI_INVALID_PARAMETER;
    493   }
    494 
    495   if (MemoryType == EfiBootServicesData) {
    496     HcCapParams  = MmioRead32(mUsbMemBase + EHC_HCCPARAMS_OFFSET);
    497     if ((BOOLEAN)(((HcCapParams) & (HCCP_64BIT)) == (HCCP_64BIT))){
    498       *HostAddress = UncachedAllocatePages(Pages);
    499     } else {
    500       // TODO: We need support allocating UC memory below 4GB strictly
    501       *HostAddress = UncachedAllocatePages(Pages);
    502     }
    503 
    504   }else{
    505     return EFI_INVALID_PARAMETER;
    506   }
    507 
    508   return EFI_SUCCESS;
    509 }
    510 
    511 
    512 EFI_STATUS
    513 EhciPciIoFreeBuffer (
    514   IN EFI_PCI_IO_PROTOCOL           *This,
    515   IN  UINTN                        Pages,
    516   IN  VOID                         *HostAddress
    517   )
    518 {
    519   UncachedFreePages (HostAddress, Pages);
    520   return EFI_SUCCESS;
    521 }
    522 
    523 EFI_STATUS
    524 EhciPciIoFlush (
    525   IN EFI_PCI_IO_PROTOCOL  *This
    526   )
    527 {
    528   return EFI_SUCCESS;
    529 }
    530 
    531 EFI_STATUS
    532 EhciPciIoGetLocation (
    533   IN   EFI_PCI_IO_PROTOCOL  *This,
    534   OUT  UINTN                *SegmentNumber,
    535   OUT  UINTN                *BusNumber,
    536   OUT  UINTN                *DeviceNumber,
    537   OUT  UINTN                *FunctionNumber
    538   )
    539 {
    540 
    541   *SegmentNumber  = mSegmentNumber;
    542   *BusNumber      = mBusNumber;
    543   *DeviceNumber   = mDeviceNumber;
    544   *FunctionNumber = mFunctionNumber;
    545 
    546   return EFI_SUCCESS;
    547 }
    548 
    549 
    550 EFI_STATUS
    551 EhciPciIoAttributes (
    552   IN EFI_PCI_IO_PROTOCOL                       *This,
    553   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
    554   IN  UINT64                                   Attributes,
    555   OUT UINT64                                   *Result OPTIONAL
    556   )
    557 {
    558   if (Result != NULL) {
    559      *Result = 0;
    560   }
    561   return EFI_SUCCESS;
    562 }
    563 
    564 EFI_STATUS
    565 EhciPciIoGetBarAttributes (
    566   IN EFI_PCI_IO_PROTOCOL             *This,
    567   IN  UINT8                          BarIndex,
    568   OUT UINT64                         *Supports, OPTIONAL
    569   OUT VOID                           **Resources OPTIONAL
    570   )
    571 {
    572   ASSERT (FALSE);
    573   return EFI_UNSUPPORTED;
    574 }
    575 
    576 EFI_STATUS
    577 EhciPciIoSetBarAttributes (
    578   IN EFI_PCI_IO_PROTOCOL              *This,
    579   IN     UINT64                       Attributes,
    580   IN     UINT8                        BarIndex,
    581   IN OUT UINT64                       *Offset,
    582   IN OUT UINT64                       *Length
    583   )
    584 {
    585   ASSERT (FALSE);
    586   return EFI_UNSUPPORTED;
    587 }
    588 
    589 //
    590 // Pci Io Protocol Interface
    591 //
    592 EFI_PCI_IO_PROTOCOL  mEhciPciIoInterface = {
    593   EhciPciIoPollMem,
    594   EhciPciIoPollIo,
    595   {
    596     EhciPciIoMemRead,
    597     EhciPciIoMemWrite
    598   },
    599   {
    600     EhciPciIoIoRead,
    601     EhciPciIoIoWrite
    602   },
    603   {
    604     EhciPciIoPciRead,
    605     EhciPciIoPciWrite
    606   },
    607   EhciPciIoCopyMem,
    608   EhciPciIoMap,
    609   EhciPciIoUnmap,
    610   EhciPciIoAllocateBuffer,
    611   EhciPciIoFreeBuffer,
    612   EhciPciIoFlush,
    613   EhciPciIoGetLocation,
    614   EhciPciIoAttributes,
    615   EhciPciIoGetBarAttributes,
    616   EhciPciIoSetBarAttributes,
    617   0,
    618   NULL
    619 };
    620 
    621 
    622 EFI_STATUS
    623 EFIAPI
    624 EhciVirtualPciIoInitialize (
    625   IN EFI_HANDLE         ImageHandle,
    626   IN EFI_SYSTEM_TABLE   *SystemTable
    627   )
    628 {
    629   EFI_STATUS          Status;
    630   EFI_HANDLE                    Handle;
    631   EFI_DEV_PATH              EndNode;
    632   EFI_DEV_PATH              Node;
    633   EFI_DEVICE_PATH_PROTOCOL  *DevicePath = NULL;
    634 
    635   mUsbMemBase            = PlatformGetEhciBase ();
    636 
    637     DEBUG ((EFI_D_ERROR, "mUsbMemBase: 0x%x\n", mUsbMemBase));
    638 
    639   // Get the Cpu protocol for later use
    640   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
    641 
    642   //
    643   // Install the pciio protocol, device path protocol
    644   //
    645   Handle = NULL;
    646 
    647   Status = gBS->InstallMultipleProtocolInterfaces (
    648                   &Handle,
    649                   &gEfiPciIoProtocolGuid,
    650                   &mEhciPciIoInterface,
    651                   NULL
    652                   );
    653   if (EFI_ERROR (Status)) {
    654     return Status;
    655   }
    656 
    657   (void)ZeroMem (&Node, sizeof (Node));
    658   Node.DevPath.Type = HARDWARE_DEVICE_PATH;
    659   Node.DevPath.SubType = HW_PCI_DP;
    660   (void)SetDevicePathNodeLength (&Node.DevPath, sizeof (PCI_DEVICE_PATH));
    661   // Make USB controller device path different from built-in SATA controller
    662   Node.Pci.Function = 1;
    663   Node.Pci.Device = 0;
    664 
    665   SetDevicePathEndNode (&EndNode.DevPath);
    666 
    667   DevicePath = AppendDevicePathNode (&EndNode.DevPath, &Node.DevPath);
    668 
    669   Status = gBS->InstallProtocolInterface (
    670                   &Handle,
    671                   &gEfiDevicePathProtocolGuid,
    672                   EFI_NATIVE_INTERFACE,
    673                   DevicePath
    674                   );
    675   if(EFI_ERROR(Status))
    676   {
    677       DEBUG((EFI_D_ERROR, "[%a]:[%dL] InstallProtocolInterface fail. %r\n", __FUNCTION__, __LINE__, Status));
    678   }
    679 
    680 
    681   return EFI_SUCCESS;
    682 }
    683