hikey: Add UEFI sources for reference

UEFI needs to be built outside Android build system.
Please follow the instructions in README.

The sources correspond to:
https://github.com/96boards/edk2/commit/14eae0c12e71fd33c4c0fc51e4475e8db02566cf
https://github.com/96boards/arm-trusted-firmware/commit/e9b4909dcd75fc4ae7041cfb83d28ab9adb7afdf
https://github.com/96boards/l-loader/commit/6b784ad5c4ab00e2b1c6f53cd5f74054e5d00a78
https://git.linaro.org/uefi/uefi-tools.git/commit/abe618f8ab72034fff1ce46c9c006a2c6bd40a7e

Change-Id: Ieeefdb63e673e0c8e64e0a1f02c7bddc63b2c7fb
Signed-off-by: Vishal Bhoj <vishal.bhoj@linaro.org>
diff --git a/uefi/linaro-edk2/OptionRomPkg/Application/BltLibSample/BltLibSample.c b/uefi/linaro-edk2/OptionRomPkg/Application/BltLibSample/BltLibSample.c
new file mode 100644
index 0000000..c21eb7a
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Application/BltLibSample/BltLibSample.c
@@ -0,0 +1,287 @@
+/** @file

+  Example program using BltLib

+

+  Copyright (c) 2006 - 2011, 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.

+

+**/

+

+#include <Uefi.h>

+#include <Library/BltLib.h>

+#include <Library/DebugLib.h>

+#include <Library/UefiLib.h>

+#include <Library/UefiApplicationEntryPoint.h>

+#include <Library/UefiBootServicesTableLib.h>

+

+

+UINT64

+ReadTimestamp (

+  VOID

+  )

+{

+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)

+  return AsmReadTsc ();

+#elif defined (MDE_CPU_IPF)

+  return AsmReadItc ();

+#else

+#error ReadTimestamp not supported for this architecture!

+#endif

+}

+

+UINT32

+Rand32 (

+  VOID

+  )

+{

+  UINTN    Found;

+  INTN     Bits;

+  UINT64   Tsc1;

+  UINT64   Tsc2;

+  UINT64   TscBits;

+  UINT32   R32;

+

+  R32 = 0;

+  Found = 0;

+  Tsc1 = ReadTimestamp ();

+  Tsc2 = ReadTimestamp ();

+  do {

+    Tsc2 = ReadTimestamp ();

+    TscBits = Tsc2 ^ Tsc1;

+    Bits = HighBitSet64 (TscBits);

+    if (Bits > 0) {

+      Bits = Bits - 1;

+    }

+    R32 = (UINT32)((R32 << Bits) |

+                   RShiftU64 (LShiftU64 (TscBits, (UINTN) (64 - Bits)), (UINTN) (64 - Bits)));

+    Found = Found + Bits;

+  } while (Found < 32);

+

+  return R32;

+}

+

+

+VOID

+TestFills (

+  VOID

+  )

+{

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;

+  UINTN                          Loop;

+  UINTN                          X;

+  UINTN                          Y;

+  UINTN                          W;

+  UINTN                          H;

+  UINTN                          Width;

+  UINTN                          Height;

+

+  BltLibGetSizes (&Width, &Height);

+  for (Loop = 0; Loop < 10000; Loop++) {

+    W = Width - (Rand32 () % Width);

+    H = Height - (Rand32 () % Height);

+    if (W != Width) {

+      X = Rand32 () % (Width - W);

+    } else {

+      X = 0;

+    }

+    if (H != Height) {

+      Y = Rand32 () % (Height - H);

+    } else {

+      Y = 0;

+    }

+    *(UINT32*) (&Color) = Rand32 () & 0xffffff;

+    BltLibVideoFill (&Color, X, Y, W, H);

+  }

+}

+

+

+VOID

+TestColor1 (

+  VOID

+  )

+{

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;

+  UINTN                          X;

+  UINTN                          Y;

+  UINTN                          Width;

+  UINTN                          Height;

+

+  BltLibGetSizes (&Width, &Height);

+  *(UINT32*) (&Color) = 0;

+

+  for (Y = 0; Y < Height; Y++) {

+    for (X = 0; X < Width; X++) {

+      Color.Red =   (UINT8) ((X * 0x100) / Width);

+      Color.Green = (UINT8) ((Y * 0x100) / Height);

+      Color.Blue =  (UINT8) ((Y * 0x100) / Height);

+      BltLibVideoFill (&Color, X, Y, 1, 1);

+    }

+  }

+}

+

+

+UINT32

+Uint32SqRt (

+  IN  UINT32  Uint32

+  )

+{

+  UINT32 Mask;

+  UINT32 SqRt;

+  UINT32 SqRtMask;

+  UINT32 Squared;

+

+  if (Uint32 == 0) {

+    return 0;

+  }

+

+  for (SqRt = 0, Mask = (UINT32) (1 << (HighBitSet32 (Uint32) / 2));

+       Mask != 0;

+       Mask = Mask >> 1

+      ) {

+    SqRtMask = SqRt | Mask;

+    //DEBUG ((EFI_D_INFO, "Uint32=0x%x SqRtMask=0x%x\n", Uint32, SqRtMask));

+    Squared = (UINT32) (SqRtMask * SqRtMask);

+    if (Squared > Uint32) {

+      continue;

+    } else if (Squared < Uint32) {

+      SqRt = SqRtMask;

+    } else {

+      return SqRtMask;

+    }

+  }

+

+  return SqRt;

+}

+

+

+UINT32

+Uint32Dist (

+  IN UINTN X,

+  IN UINTN Y

+  )

+{

+  return Uint32SqRt ((UINT32) ((X * X) + (Y * Y)));

+}

+

+UINT8

+GetTriColor (

+  IN UINTN ColorDist,

+  IN UINTN TriWidth

+  )

+{

+  return (UINT8) (((TriWidth - ColorDist) * 0x100) / TriWidth);

+  //return (((TriWidth * TriWidth - ColorDist * ColorDist) * 0x100) / (TriWidth * TriWidth));

+}

+

+VOID

+TestColor (

+  VOID

+  )

+{

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Color;

+  UINTN                          X, Y;

+  UINTN                          X1, X2, X3;

+  UINTN                          Y1, Y2;

+  UINTN                          LineWidth, TriWidth, ScreenWidth;

+  UINTN                          TriHeight, ScreenHeight;

+  UINT32                         ColorDist;

+

+  BltLibGetSizes (&ScreenWidth, &ScreenHeight);

+  *(UINT32*) (&Color) = 0;

+  BltLibVideoFill (&Color, 0, 0, ScreenWidth, ScreenHeight);

+

+  TriWidth = (UINTN) DivU64x32 (

+                       MultU64x32 (11547005, (UINT32) ScreenHeight),

+                       10000000

+                       );

+  TriHeight = (UINTN) DivU64x32 (

+                        MultU64x32 (8660254, (UINT32) ScreenWidth),

+                        10000000

+                        );

+  if (TriWidth > ScreenWidth) {

+    DEBUG ((EFI_D_INFO, "TriWidth at %d was too big\n", TriWidth));

+    TriWidth = ScreenWidth;

+  } else if (TriHeight > ScreenHeight) {

+    DEBUG ((EFI_D_INFO, "TriHeight at %d was too big\n", TriHeight));

+    TriHeight = ScreenHeight;

+  }

+

+  DEBUG ((EFI_D_INFO, "Triangle Width: %d; Height: %d\n", TriWidth, TriHeight));

+

+  X1 = (ScreenWidth - TriWidth) / 2;

+  X3 = X1 + TriWidth - 1;

+  X2 = (X1 + X3) / 2;

+  Y2 = (ScreenHeight - TriHeight) / 2;

+  Y1 = Y2 + TriHeight - 1;

+

+  for (Y = Y2; Y <= Y1; Y++) {

+    LineWidth =

+      (UINTN) DivU64x32 (

+                MultU64x32 (11547005, (UINT32) (Y - Y2)),

+                20000000

+                );

+    for (X = X2 - LineWidth; X < (X2 + LineWidth); X++) {

+      ColorDist = Uint32Dist(X - X1, Y1 - Y);

+      Color.Red = GetTriColor (ColorDist, TriWidth);

+

+      ColorDist = Uint32Dist((X < X2) ? X2 - X : X - X2, Y - Y2);

+      Color.Green = GetTriColor (ColorDist, TriWidth);

+

+      ColorDist = Uint32Dist(X3 - X, Y1 - Y);

+      Color.Blue = GetTriColor (ColorDist, TriWidth);

+

+      BltLibVideoFill (&Color, X, Y, 1, 1);

+    }

+  }

+}

+

+

+/**

+  The user Entry Point for Application. The user code starts with this function

+  as the real entry point for the application.

+

+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.

+  @param[in] SystemTable    A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS       The entry point is executed successfully.

+  @retval other             Some error occurs when executing this entry point.

+

+**/

+EFI_STATUS

+EFIAPI

+UefiMain (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  EFI_STATUS                     Status;

+  EFI_GRAPHICS_OUTPUT_PROTOCOL   *Gop;

+

+  Status = gBS->HandleProtocol (

+                  gST->ConsoleOutHandle,

+                  &gEfiGraphicsOutputProtocolGuid,

+                  (VOID **) &Gop

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = BltLibConfigure (

+             (VOID*)(UINTN) Gop->Mode->FrameBufferBase,

+             Gop->Mode->Info

+             );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  TestFills ();

+

+  TestColor ();

+

+  return EFI_SUCCESS;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Application/BltLibSample/BltLibSample.inf b/uefi/linaro-edk2/OptionRomPkg/Application/BltLibSample/BltLibSample.inf
new file mode 100644
index 0000000..a1334f8
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Application/BltLibSample/BltLibSample.inf
@@ -0,0 +1,35 @@
+## @file

+#  Test the BltLib interface

+#

+#  Copyright (c) 2008 - 2011, 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.

+#

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = BltLibSample

+  FILE_GUID                      = f7763316-8c04-41d8-a87d-45b73c13c43c

+  MODULE_TYPE                    = UEFI_APPLICATION

+  VERSION_STRING                 = 1.0

+  ENTRY_POINT                    = UefiMain

+

+[Sources]

+  BltLibSample.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OptionRomPkg/OptionRomPkg.dec

+

+[LibraryClasses]

+  BltLib

+  UefiApplicationEntryPoint

+  UefiLib

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c
new file mode 100644
index 0000000..3578a1e
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c
@@ -0,0 +1,3416 @@
+/** @file

+  Copyright (c) 2006, 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.

+

+**/

+

+#include "AtapiPassThru.h"

+

+

+SCSI_COMMAND_SET     gEndTable = { 0xff, (DATA_DIRECTION) 0xff };

+

+///

+/// This table contains all the supported ATAPI commands.

+///

+SCSI_COMMAND_SET     gSupportedATAPICommands[] = {

+  { OP_INQUIRY,                     DataIn  },

+  { OP_LOAD_UNLOAD_CD,              NoData  },

+  { OP_MECHANISM_STATUS,            DataIn  },

+  { OP_MODE_SELECT_10,              DataOut },

+  { OP_MODE_SENSE_10,               DataIn  },

+  { OP_PAUSE_RESUME,                NoData  },

+  { OP_PLAY_AUDIO_10,               DataIn  },

+  { OP_PLAY_AUDIO_MSF,              DataIn  },

+  { OP_PLAY_CD,                     DataIn  },

+  { OP_PLAY_CD_MSF,                 DataIn  },

+  { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData  },

+  { OP_READ_10,                     DataIn  },

+  { OP_READ_12,                     DataIn  },

+  { OP_READ_CAPACITY,               DataIn  },

+  { OP_READ_CD,                     DataIn  },

+  { OP_READ_CD_MSF,                 DataIn  },

+  { OP_READ_HEADER,                 DataIn  },

+  { OP_READ_SUB_CHANNEL,            DataIn  },

+  { OP_READ_TOC,                    DataIn  },

+  { OP_REQUEST_SENSE,               DataIn  },

+  { OP_SCAN,                        NoData  },

+  { OP_SEEK_10,                     NoData  },

+  { OP_SET_CD_SPEED,                DataOut },

+  { OP_STOPPLAY_SCAN,               NoData  },

+  { OP_START_STOP_UNIT,             NoData  },

+  { OP_TEST_UNIT_READY,             NoData  },

+  { OP_FORMAT_UNIT,                 DataOut },

+  { OP_READ_FORMAT_CAPACITIES,      DataIn  },

+  { OP_VERIFY,                      DataOut },

+  { OP_WRITE_10,                    DataOut },

+  { OP_WRITE_12,                    DataOut },

+  { OP_WRITE_AND_VERIFY,            DataOut },

+  { 0xff,                           (DATA_DIRECTION) 0xff    }

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {

+  L"ATAPI Controller",

+  L"ATAPI Channel",

+  4,

+  EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,

+  0

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {

+  &gScsiPassThruMode,

+  AtapiScsiPassThruFunction,

+  AtapiScsiPassThruGetNextDevice,

+  AtapiScsiPassThruBuildDevicePath,

+  AtapiScsiPassThruGetTargetLun,

+  AtapiScsiPassThruResetChannel,

+  AtapiScsiPassThruResetTarget

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {

+  4,

+  EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,

+  0

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {

+  &gExtScsiPassThruMode,

+  AtapiExtScsiPassThruFunction,

+  AtapiExtScsiPassThruGetNextTargetLun,

+  AtapiExtScsiPassThruBuildDevicePath,

+  AtapiExtScsiPassThruGetTargetLun,

+  AtapiExtScsiPassThruResetChannel,

+  AtapiExtScsiPassThruResetTarget,

+  AtapiExtScsiPassThruGetNextTarget

+};

+

+EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {

+  AtapiScsiPassThruDriverBindingSupported,

+  AtapiScsiPassThruDriverBindingStart,

+  AtapiScsiPassThruDriverBindingStop,

+  0x10,

+  NULL,

+  NULL

+};

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  )

+/*++

+

+Routine Description:

+  Test to see if this driver supports ControllerHandle. Any ControllerHandle

+  that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.

+

+Arguments:

+

+  This                - Protocol instance pointer.

+  Controller          - Handle of device to test

+  RemainingDevicePath - Not used

+

+Returns:

+    EFI_STATUS

+

+--*/

+{

+  EFI_STATUS          Status;

+  EFI_PCI_IO_PROTOCOL *PciIo;

+  PCI_TYPE00          Pci;

+

+

+  //

+  // Open the IO Abstraction(s) needed to perform the supported test

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  //

+  // Use the PCI I/O Protocol to see if Controller is a IDE Controller that

+  // can be managed by this driver.  Read the PCI Configuration Header

+  // for this device.

+  //

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint32,

+                        0,

+                        sizeof (Pci) / sizeof (UINT32),

+                        &Pci

+                        );

+  if (EFI_ERROR (Status)) {

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiPciIoProtocolGuid,

+           This->DriverBindingHandle,

+           Controller

+           );

+    return EFI_UNSUPPORTED;

+  }

+

+  if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE) {

+

+    Status = EFI_UNSUPPORTED;

+  }

+

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiPciIoProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  )

+/*++

+

+Routine Description:

+  Create handles for IDE channels specified by RemainingDevicePath.

+  Install SCSI Pass Thru Protocol onto each created handle.

+

+Arguments:

+

+  This                - Protocol instance pointer.

+  Controller          - Handle of device to test

+  RemainingDevicePath - Not used

+

+Returns:

+    EFI_STATUS

+

+--*/

+{

+  EFI_STATUS          Status;

+  EFI_PCI_IO_PROTOCOL *PciIo;

+  UINT64              Supports;

+  UINT64              OriginalPciAttributes;

+  BOOLEAN             PciAttributesSaved;

+

+  PciIo = NULL;

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  PciAttributesSaved = FALSE;

+  //

+  // Save original PCI attributes

+  //

+  Status = PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationGet,

+                    0,

+                    &OriginalPciAttributes

+                    );

+

+  if (EFI_ERROR (Status)) {

+    goto Done;

+  }

+  PciAttributesSaved = TRUE;

+

+  Status = PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationSupported,

+                    0,

+                    &Supports

+                    );

+  if (!EFI_ERROR (Status)) {

+    Supports &= (EFI_PCI_DEVICE_ENABLE               |

+                 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |

+                 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);

+    Status = PciIo->Attributes (

+                      PciIo,

+                      EfiPciIoAttributeOperationEnable,

+                      Supports,

+                      NULL

+                      );

+  }

+  if (EFI_ERROR (Status)) {

+    goto Done;

+  }

+

+  //

+  // Create SCSI Pass Thru instance for the IDE channel.

+  //

+  Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);

+

+Done:

+  if (EFI_ERROR (Status)) {

+    if (PciAttributesSaved == TRUE) {

+      //

+      // Restore original PCI attributes

+      //

+      PciIo->Attributes (

+                      PciIo,

+                      EfiPciIoAttributeOperationSet,

+                      OriginalPciAttributes,

+                      NULL

+                      );

+    }

+

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiPciIoProtocolGuid,

+           This->DriverBindingHandle,

+           Controller

+           );

+  }

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,

+  IN  EFI_HANDLE                      Controller,

+  IN  UINTN                           NumberOfChildren,

+  IN  EFI_HANDLE                      *ChildHandleBuffer

+  )

+/*++

+

+Routine Description:

+

+  Stop this driver on ControllerHandle. Support stoping any child handles

+  created by this driver.

+

+Arguments:

+

+  This              - Protocol instance pointer.

+  Controller        - Handle of device to stop driver on

+  NumberOfChildren  - Number of Children in the ChildHandleBuffer

+  ChildHandleBuffer - List of handles for the children we need to stop.

+

+Returns:

+

+    EFI_STATUS

+

+--*/

+{

+  EFI_STATUS                      Status;

+  EFI_SCSI_PASS_THRU_PROTOCOL     *ScsiPassThru;

+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate;

+

+  if (FeaturePcdGet (PcdSupportScsiPassThru)) {

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiScsiPassThruProtocolGuid,

+                    (VOID **) &ScsiPassThru,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);

+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      Controller,

+                      &gEfiScsiPassThruProtocolGuid,

+                      &AtapiScsiPrivate->ScsiPassThru,

+                      &gEfiExtScsiPassThruProtocolGuid,

+                      &AtapiScsiPrivate->ExtScsiPassThru,

+                      NULL

+                      );

+    } else {

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      Controller,

+                      &gEfiScsiPassThruProtocolGuid,

+                      &AtapiScsiPrivate->ScsiPassThru,

+                      NULL

+                      );

+    }

+  } else {

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiExtScsiPassThruProtocolGuid,

+                    (VOID **) &ExtScsiPassThru,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);

+    Status = gBS->UninstallMultipleProtocolInterfaces (

+                    Controller,

+                    &gEfiExtScsiPassThruProtocolGuid,

+                    &AtapiScsiPrivate->ExtScsiPassThru,

+                    NULL

+                    );

+  }

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Restore original PCI attributes

+  //

+  AtapiScsiPrivate->PciIo->Attributes (

+                  AtapiScsiPrivate->PciIo,

+                  EfiPciIoAttributeOperationSet,

+                  AtapiScsiPrivate->OriginalPciAttributes,

+                  NULL

+                  );

+

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiPciIoProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+

+  gBS->FreePool (AtapiScsiPrivate);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+RegisterAtapiScsiPassThru (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN  EFI_HANDLE                  Controller,

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  IN  UINT64                      OriginalPciAttributes

+  )

+/*++

+

+Routine Description:

+  Attaches SCSI Pass Thru Protocol for specified IDE channel.

+

+Arguments:

+  This              - Protocol instance pointer.

+  Controller        - Parent device handle to the IDE channel.

+  PciIo             - PCI I/O protocol attached on the "Controller".

+

+Returns:

+  Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.

+

+--*/

+{

+  EFI_STATUS                Status;

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+  IDE_REGISTERS_BASE_ADDR   IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];

+

+  AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));

+  if (AtapiScsiPrivate == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;

+  AtapiScsiPrivate->Handle    = Controller;

+

+  //

+  // will reset the IoPort inside each API function.

+  //

+  AtapiScsiPrivate->IoPort                = NULL;

+  AtapiScsiPrivate->PciIo                 = PciIo;

+  AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;

+

+  //

+  // Obtain IDE IO port registers' base addresses

+  //

+  Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);

+

+  //

+  // Initialize the LatestTargetId to MAX_TARGET_ID.

+  //

+  AtapiScsiPrivate->LatestTargetId  = MAX_TARGET_ID;

+  AtapiScsiPrivate->LatestLun       = 0;

+

+  Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruFunction (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,

+  IN UINT32                                             Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored,

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported,

+            then non-blocking I/O is performed, and Event will be signaled

+            when the SCSI Request Packet completes.

+

+Returns:

+

+   EFI_STATUS

+

+--*/

+{

+  ATAPI_SCSI_PASS_THRU_DEV               *AtapiScsiPrivate;

+  EFI_STATUS                             Status;

+

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Target is not allowed beyond MAX_TARGET_ID

+  //

+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // check the data fields in Packet parameter.

+  //

+  Status = CheckSCSIRequestPacket (Packet);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // If Request Packet targets at the IDE channel itself,

+  // do nothing.

+  //

+  if (Target == This->Mode->AdapterId) {

+    Packet->TransferLength = 0;

+    return EFI_SUCCESS;

+  }

+

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((Target / 2) == 0) {

+    Target = Target % 2;

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    Target = Target % 2;

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+

+  //

+  // the ATAPI SCSI interface does not support non-blocking I/O

+  // ignore the Event parameter

+  //

+  // Performs blocking I/O.

+  //

+  Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetNextDevice (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT32                      *Target,

+  IN OUT UINT64                      *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI

+                          device present on the SCSI channel.  On output,

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of

+                          0xFFFFFFFF retrieves the Target ID of the first

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+--*/

+{

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+

+  //

+  // Retrieve Device Private Data Structure.

+  //

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Check whether Target is valid.

+  //

+  if (Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if ((*Target != 0xFFFFFFFF) &&

+      ((*Target != AtapiScsiPrivate->LatestTargetId) ||

+      (*Lun != AtapiScsiPrivate->LatestLun))) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (*Target == MAX_TARGET_ID) {

+    return EFI_NOT_FOUND;

+  }

+

+  if (*Target == 0xFFFFFFFF) {

+    *Target = 0;

+  } else {

+    *Target = AtapiScsiPrivate->LatestTargetId + 1;

+  }

+

+  *Lun = 0;

+

+  //

+  // Update the LatestTargetId.

+  //

+  AtapiScsiPrivate->LatestTargetId  = *Target;

+  AtapiScsiPrivate->LatestLun       = *Lun;

+

+  return EFI_SUCCESS;

+

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruBuildDevicePath (

+  IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT32                         Target,

+  IN     UINT64                         Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that

+                          describes the SCSI device specified by

+                          Target and Lun. This function is responsible

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate

+                          DevicePath.

+--*/

+{

+  EFI_DEV_PATH              *Node;

+

+

+  //

+  // Validate parameters passed in.

+  //

+

+  if (DevicePath == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // can not build device path for the SCSI Host Controller.

+  //

+  if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {

+    return EFI_NOT_FOUND;

+  }

+

+  Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));

+  if (Node == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;

+  Node->DevPath.SubType = MSG_ATAPI_DP;

+  SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));

+

+  Node->Atapi.PrimarySecondary  = (UINT8) (Target / 2);

+  Node->Atapi.SlaveMaster       = (UINT8) (Target % 2);

+  Node->Atapi.Lun               = (UINT16) Lun;

+

+  *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetTargetLun (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,

+  OUT UINT32                         *Target,

+  OUT UINT64                         *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device

+                          on the SCSI channel.

+  Lun                   - A pointer to the LUN of a SCSI device on

+                          the SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a

+                          Target ID and LUN, and they were returned

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a

+                          Target ID and LUN does not exist.

+--*/

+{

+  EFI_DEV_PATH  *Node;

+

+  //

+  // Validate parameters passed in.

+  //

+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH

+  //

+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||

+      (DevicePath->SubType != MSG_ATAPI_DP) ||

+      (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {

+    return EFI_UNSUPPORTED;

+  }

+

+  Node    = (EFI_DEV_PATH *) DevicePath;

+

+  *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;

+  *Lun    = Node->Atapi.Lun;

+

+  if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {

+    return EFI_NOT_FOUND;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetChannel (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting

+                          to reset the SCSI channel.

+--*/

+{

+  UINT8                     DeviceControlValue;

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+  UINT8                     Index;

+  BOOLEAN                   ResetFlag;

+

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+  ResetFlag = FALSE;

+

+  //

+  // Reset both Primary channel and Secondary channel.

+  // so, the IoPort pointer must point to the right I/O Register group

+  //

+  for (Index = 0; Index < 2; Index++) {

+    //

+    // Reset

+    //

+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];

+

+    DeviceControlValue        = 0;

+    //

+    // set SRST bit to initiate soft reset

+    //

+    DeviceControlValue |= SRST;

+    //

+    // disable Interrupt

+    //

+    DeviceControlValue |= BIT1;

+    WritePortB (

+      AtapiScsiPrivate->PciIo,

+      AtapiScsiPrivate->IoPort->Alt.DeviceControl,

+      DeviceControlValue

+      );

+

+    //

+    // Wait 10us

+    //

+    gBS->Stall (10);

+

+    //

+    // Clear SRST bit

+    // 0xfb:1111,1011

+    //

+    DeviceControlValue &= 0xfb;

+

+    WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);

+

+    //

+    // slave device needs at most 31s to clear BSY

+    //

+    if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {

+      ResetFlag = TRUE;

+    }

+  }

+

+  if (ResetFlag) {

+    return EFI_SUCCESS;

+  }

+

+  return EFI_TIMEOUT;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetTarget (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT32                         Target,

+  IN UINT64                         Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset.

+  Lun                   - The LUN of the SCSI device to reset.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting

+                          to reset the SCSI device specified by Target

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset

+                          the SCSI device specified by Target and Lun.

+--*/

+{

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate;

+  UINT8                     Command;

+  UINT8                     DeviceSelect;

+

+  AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  if ((Target > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  //

+  // Directly return EFI_SUCCESS if want to reset the host controller

+  //

+  if (Target == This->Mode->AdapterId) {

+    return EFI_SUCCESS;

+  }

+

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((Target / 2) == 0) {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+

+  //

+  // for ATAPI device, no need to wait DRDY ready after device selecting.

+  //

+  // bit7 and bit5 are both set to 1 for backward compatibility

+  //

+  DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Target << 4)));

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);

+

+  Command = ATAPI_SOFT_RESET_CMD;

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);

+

+  //

+  // BSY clear is the only status return to the host by the device

+  // when reset is complete.

+  // slave device needs at most 31s to clear BSY

+  //

+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {

+    return EFI_TIMEOUT;

+  }

+

+  //

+  // stall 5 seconds to make the device status stable

+  //

+  gBS->Stall (5000000);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruFunction (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,

+  IN UINT8                                              *Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored,

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported,

+            then non-blocking I/O is performed, and Event will be signaled

+            when the SCSI Request Packet completes.

+

+Returns:

+

+   EFI_STATUS

+

+--*/

+{

+  EFI_STATUS                          Status;

+  ATAPI_SCSI_PASS_THRU_DEV            *AtapiScsiPrivate;

+  UINT8                                TargetId;

+

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.

+  //

+  TargetId = Target[0];

+

+  //

+  // Target is not allowed beyond MAX_TARGET_ID

+  //

+  if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // check the data fields in Packet parameter.

+  //

+  Status = CheckExtSCSIRequestPacket (Packet);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // If Request Packet targets at the IDE channel itself,

+  // do nothing.

+  //

+  if (TargetId == (UINT8)This->Mode->AdapterId) {

+    Packet->InTransferLength = Packet->OutTransferLength = 0;

+    return EFI_SUCCESS;

+  }

+

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((TargetId / 2) == 0) {

+    TargetId = (UINT8) (TargetId % 2);

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    TargetId = (UINT8) (TargetId % 2);

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+

+  //

+  // the ATAPI SCSI interface does not support non-blocking I/O

+  // ignore the Event parameter

+  //

+  // Performs blocking I/O.

+  //

+  Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target,

+  IN OUT UINT64                          *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI

+                          device present on the SCSI channel.  On output,

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of

+                          0xFFFFFFFF retrieves the Target ID of the first

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+--*/

+{

+  UINT8                          ByteIndex;

+  UINT8                          TargetId;

+  UINT8                          ScsiId[TARGET_MAX_BYTES];

+  ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate;

+

+  //

+  // Retrieve Device Private Data Structure.

+  //

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Check whether Target is valid.

+  //

+  if (*Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);

+

+  TargetId = (*Target)[0];

+

+  //

+  // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.

+  //

+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {

+    for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {

+      if ((*Target)[ByteIndex] != 0) {

+        return EFI_INVALID_PARAMETER;

+      }

+    }

+  }

+

+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&

+      ((TargetId != AtapiScsiPrivate->LatestTargetId) ||

+      (*Lun != AtapiScsiPrivate->LatestLun))) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (TargetId == MAX_TARGET_ID) {

+    return EFI_NOT_FOUND;

+  }

+

+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {

+    SetMem (*Target, TARGET_MAX_BYTES,0);

+  } else {

+    (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);

+  }

+

+  *Lun = 0;

+

+  //

+  // Update the LatestTargetId.

+  //

+  AtapiScsiPrivate->LatestTargetId  = (*Target)[0];

+  AtapiScsiPrivate->LatestLun       = *Lun;

+

+  return EFI_SUCCESS;

+

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruBuildDevicePath (

+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT8                              *Target,

+  IN     UINT64                             Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that

+                          describes the SCSI device specified by

+                          Target and Lun. This function is responsible

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate

+                          DevicePath.

+--*/

+{

+  EFI_DEV_PATH                   *Node;

+  UINT8                          TargetId;

+

+  TargetId = Target[0];

+

+  //

+  // Validate parameters passed in.

+  //

+

+  if (DevicePath == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // can not build device path for the SCSI Host Controller.

+  //

+  if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {

+    return EFI_NOT_FOUND;

+  }

+

+  Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));

+  if (Node == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;

+  Node->DevPath.SubType = MSG_ATAPI_DP;

+  SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));

+

+  Node->Atapi.PrimarySecondary  = (UINT8) (TargetId / 2);

+  Node->Atapi.SlaveMaster       = (UINT8) (TargetId % 2);

+  Node->Atapi.Lun               = (UINT16) Lun;

+

+  *DevicePath                   = (EFI_DEVICE_PATH_PROTOCOL *) Node;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,

+  OUT UINT8                              **Target,

+  OUT UINT64                             *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device

+                          on the SCSI channel.

+  Lun                   - A pointer to the LUN of a SCSI device on

+                          the SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a

+                          Target ID and LUN, and they were returned

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a

+                          Target ID and LUN does not exist.

+--*/

+{

+  EFI_DEV_PATH  *Node;

+

+  //

+  // Validate parameters passed in.

+  //

+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH

+  //

+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||

+      (DevicePath->SubType != MSG_ATAPI_DP) ||

+      (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {

+    return EFI_UNSUPPORTED;

+  }

+

+  ZeroMem (*Target, TARGET_MAX_BYTES);

+

+  Node    = (EFI_DEV_PATH *) DevicePath;

+

+  (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);

+  *Lun    = Node->Atapi.Lun;

+

+  if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {

+    return EFI_NOT_FOUND;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetChannel (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting

+                          to reset the SCSI channel.

+--*/

+{

+  UINT8                         DeviceControlValue;

+  UINT8                         Index;

+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;

+  BOOLEAN                       ResetFlag;

+

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+  ResetFlag = FALSE;

+  //

+  // Reset both Primary channel and Secondary channel.

+  // so, the IoPort pointer must point to the right I/O Register group

+  // And if there is a channel reset successfully, return EFI_SUCCESS.

+  //

+  for (Index = 0; Index < 2; Index++) {

+    //

+    // Reset

+    //

+    AtapiScsiPrivate->IoPort  = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];

+

+    DeviceControlValue        = 0;

+    //

+    // set SRST bit to initiate soft reset

+    //

+    DeviceControlValue |= SRST;

+    //

+    // disable Interrupt

+    //

+    DeviceControlValue |= BIT1;

+    WritePortB (

+      AtapiScsiPrivate->PciIo,

+      AtapiScsiPrivate->IoPort->Alt.DeviceControl,

+      DeviceControlValue

+      );

+

+    //

+    // Wait 10us

+    //

+    gBS->Stall (10);

+

+    //

+    // Clear SRST bit

+    // 0xfb:1111,1011

+    //

+    DeviceControlValue &= 0xfb;

+

+    WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);

+

+    //

+    // slave device needs at most 31s to clear BSY

+    //

+    if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {

+      ResetFlag = TRUE;

+    }

+  }

+

+  if (ResetFlag) {

+    return EFI_SUCCESS;

+  }

+

+  return EFI_TIMEOUT;

+}

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetTarget (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT8                              *Target,

+  IN UINT64                             Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset.

+  Lun                   - The LUN of the SCSI device to reset.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting

+                          to reset the SCSI device specified by Target

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset

+                          the SCSI device specified by Target and Lun.

+--*/

+{

+  UINT8                         Command;

+  UINT8                         DeviceSelect;

+  UINT8                         TargetId;

+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;

+

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+  TargetId = Target[0];

+

+  if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  //

+  // Directly return EFI_SUCCESS if want to reset the host controller

+  //

+  if (TargetId == This->Mode->AdapterId) {

+    return EFI_SUCCESS;

+  }

+

+  //

+  // According to Target ID, reset the Atapi I/O Register mapping

+  // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],

+  //  Target Id in [2,3] area, using AtapiIoPortRegisters[1]

+  //

+  if ((TargetId / 2) == 0) {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];

+  } else {

+    AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];

+  }

+

+  //

+  // for ATAPI device, no need to wait DRDY ready after device selecting.

+  //

+  // bit7 and bit5 are both set to 1 for backward compatibility

+  //

+  DeviceSelect = (UINT8) ((BIT7 | BIT5) | (TargetId << 4));

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);

+

+  Command = ATAPI_SOFT_RESET_CMD;

+  WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);

+

+  //

+  // BSY clear is the only status return to the host by the device

+  // when reset is complete.

+  // slave device needs at most 31s to clear BSY

+  //

+  if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {

+    return EFI_TIMEOUT;

+  }

+

+  //

+  // stall 5 seconds to make the device status stable

+  //

+  gBS->Stall (5000000);

+

+  return EFI_SUCCESS;

+}

+

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTarget (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target

+  )

+/*++

+

+Routine Description:

+  Used to retrieve the list of legal Target IDs for SCSI devices

+  on a SCSI channel.

+

+Arguments:

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI

+                          device present on the SCSI channel.  On output,

+                          a pointer to the Target ID of the next SCSI device

+                           present on a SCSI channel.  An input value of

+                           0xFFFFFFFF retrieves the Target ID of the first

+                           SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on

+                          a SCSI channel.

+

+Returns:

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                          returned on a previous call to GetNextDevice().

+--*/

+{

+  UINT8                         TargetId;

+  UINT8                         ScsiId[TARGET_MAX_BYTES];

+  ATAPI_SCSI_PASS_THRU_DEV      *AtapiScsiPrivate;

+  UINT8                         ByteIndex;

+

+  //

+  // Retrieve Device Private Data Structure.

+  //

+  AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);

+

+  //

+  // Check whether Target is valid.

+  //

+  if (*Target == NULL ) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  TargetId = (*Target)[0];

+  SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);

+

+  //

+  // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.

+  //

+  if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {

+    for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {

+      if ((*Target)[ByteIndex] != 0) {

+        return EFI_INVALID_PARAMETER;

+      }

+    }

+  }

+

+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (TargetId == MAX_TARGET_ID) {

+    return EFI_NOT_FOUND;

+  }

+

+  if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {

+    SetMem (*Target, TARGET_MAX_BYTES, 0);

+  } else {

+    (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);

+  }

+

+  //

+  // Update the LatestTargetId.

+  //

+  AtapiScsiPrivate->LatestTargetId  = (*Target)[0];

+  AtapiScsiPrivate->LatestLun       = 0;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+GetIdeRegistersBaseAddr (

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,

+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in

+  the PCI IDE controller's Configuration Space.

+

+Arguments:

+  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance

+  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to

+                      receive IDE IO port registers' base addresses

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  EFI_STATUS  Status;

+  PCI_TYPE00  PciData;

+

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint8,

+                        0,

+                        sizeof (PciData),

+                        &PciData

+                        );

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {

+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;

+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;

+  } else {

+    //

+    // The BARs should be of IO type

+    //

+    if ((PciData.Device.Bar[0] & BIT0) == 0 ||

+        (PciData.Device.Bar[1] & BIT0) == 0) {

+      return EFI_UNSUPPORTED;

+    }

+

+    IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =

+    (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);

+    IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =

+    (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);

+  }

+

+  if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {

+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;

+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;

+  } else {

+    //

+    // The BARs should be of IO type

+    //

+    if ((PciData.Device.Bar[2] & BIT0) == 0 ||

+        (PciData.Device.Bar[3] & BIT0) == 0) {

+      return EFI_UNSUPPORTED;

+    }

+

+    IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =

+    (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);

+    IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =

+    (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);

+  }

+

+  return EFI_SUCCESS;

+}

+

+VOID

+InitAtapiIoPortRegisters (

+  IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+

+  Initialize each Channel's Base Address of CommandBlock and ControlBlock.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR

+

+Returns:

+

+  None

+

+--*/

+{

+

+  UINT8               IdeChannel;

+  UINT16              CommandBlockBaseAddr;

+  UINT16              ControlBlockBaseAddr;

+  IDE_BASE_REGISTERS  *RegisterPointer;

+

+

+  for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {

+

+    RegisterPointer =  &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];

+

+    //

+    // Initialize IDE IO port addresses, including Command Block registers

+    // and Control Block registers

+    //

+    CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;

+    ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;

+

+    RegisterPointer->Data = CommandBlockBaseAddr;

+    (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);

+    RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);

+    RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);

+    RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);

+    RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);

+    RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);

+    (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);

+

+    (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;

+    RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);

+  }

+

+}

+

+

+EFI_STATUS

+CheckSCSIRequestPacket (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  if (Packet == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (!ValidCdbLength (Packet->CdbLength)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Packet->Cdb == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Checks whether the request command is supported.

+  //

+  if (!IsCommandValid (Packet)) {

+    return EFI_UNSUPPORTED;

+  }

+

+  return EFI_SUCCESS;

+}

+

+BOOLEAN

+IsCommandValid (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the requested SCSI command:

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT8 Index;

+  UINT8 *OpCode;

+  UINT8 ArrayLen;

+

+  OpCode = (UINT8 *) (Packet->Cdb);

+  ArrayLen = (UINT8) (sizeof (gSupportedATAPICommands) / sizeof (gSupportedATAPICommands[0]));

+

+  for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {

+

+    if (*OpCode == gSupportedATAPICommands[Index].OpCode) {

+      //

+      // Check whether the requested Command is supported by this driver

+      //

+      if (Packet->DataDirection == DataIn) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataOut) {

+          return FALSE;

+        }

+      }

+

+      if (Packet->DataDirection == DataOut) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataIn) {

+          return FALSE;

+        }

+      }

+

+      return TRUE;

+    }

+  }

+

+  return FALSE;

+}

+

+EFI_STATUS

+SubmitBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,

+  UINT32                                    Target,

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device

+                      specified by Target.

+

+  Returns:            EFI_STATUS

+

+--*/

+{

+  UINT8       PacketCommand[12];

+  UINT64      TimeoutInMicroSeconds;

+  EFI_STATUS  PacketCommandStatus;

+

+  //

+  // Fill ATAPI Command Packet according to CDB

+  //

+  ZeroMem (&PacketCommand, 12);

+  CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);

+

+  //

+  // Timeout is 100ns unit, convert it to 1000ns (1us) unit.

+  //

+  TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);

+

+  //

+  // Submit ATAPI Command Packet

+  //

+  PacketCommandStatus = AtapiPacketCommand (

+                          AtapiScsiPrivate,

+                          Target,

+                          PacketCommand,

+                          Packet->DataBuffer,

+                          &(Packet->TransferLength),

+                          (DATA_DIRECTION) Packet->DataDirection,

+                          TimeoutInMicroSeconds

+                          );

+  if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {

+    Packet->SenseDataLength = 0;

+    return PacketCommandStatus;

+  }

+

+  //

+  // Return SenseData if PacketCommandStatus matches

+  // the following return codes.

+  //

+  if ((PacketCommandStatus ==  EFI_BAD_BUFFER_SIZE) ||

+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||

+      (PacketCommandStatus == EFI_TIMEOUT)) {

+

+    //

+    // avoid submit request sense command continuously.

+    //

+    if (PacketCommand[0] == OP_REQUEST_SENSE) {

+      Packet->SenseDataLength = 0;

+      return PacketCommandStatus;

+    }

+

+    RequestSenseCommand (

+      AtapiScsiPrivate,

+      Target,

+      Packet->Timeout,

+      Packet->SenseData,

+      &Packet->SenseDataLength

+      );

+  }

+

+  return PacketCommandStatus;

+}

+

+EFI_STATUS

+RequestSenseCommand (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT32                      Target,

+  UINT64                      Timeout,

+  VOID                        *SenseData,

+  UINT8                       *SenseDataLength

+  )

+/*++

+

+Routine Description:

+

+  Sumbit request sense command

+

+Arguments:

+

+  AtapiScsiPrivate  - The pionter of ATAPI_SCSI_PASS_THRU_DEV

+  Target            - The target ID

+  Timeout           - The time to complete the command

+  SenseData         - The buffer to fill in sense data

+  SenseDataLength   - The length of buffer

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  Packet;

+  UINT8                                   Cdb[12];

+  EFI_STATUS                              Status;

+

+  ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));

+  ZeroMem (Cdb, 12);

+

+  Cdb[0]                = OP_REQUEST_SENSE;

+  Cdb[4]                = (UINT8) (*SenseDataLength);

+

+  Packet.Timeout        = Timeout;

+  Packet.DataBuffer     = SenseData;

+  Packet.SenseData      = NULL;

+  Packet.Cdb            = Cdb;

+  Packet.TransferLength = *SenseDataLength;

+  Packet.CdbLength      = 12;

+  Packet.DataDirection  = DataIn;

+

+  Status                = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);

+  *SenseDataLength      = (UINT8) (Packet.TransferLength);

+  return Status;

+}

+

+EFI_STATUS

+CheckExtSCSIRequestPacket (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet       - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  if (Packet == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (!ValidCdbLength (Packet->CdbLength)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Packet->Cdb == NULL) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Checks whether the request command is supported.

+  //

+  if (!IsExtCommandValid (Packet)) {

+    return EFI_UNSUPPORTED;

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+BOOLEAN

+IsExtCommandValid (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the requested SCSI command:

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT8 Index;

+  UINT8 *OpCode;

+  UINT8 ArrayLen;

+

+  OpCode = (UINT8 *) (Packet->Cdb);

+  ArrayLen = (UINT8) (sizeof (gSupportedATAPICommands) / sizeof (gSupportedATAPICommands[0]));

+

+  for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {

+

+    if (*OpCode == gSupportedATAPICommands[Index].OpCode) {

+      //

+      // Check whether the requested Command is supported by this driver

+      //

+      if (Packet->DataDirection == DataIn) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataOut) {

+          return FALSE;

+        }

+      }

+

+      if (Packet->DataDirection == DataOut) {

+        //

+        // Check whether the requested data direction conforms to

+        // what it should be.

+        //

+        if (gSupportedATAPICommands[Index].Direction == DataIn) {

+          return FALSE;

+        }

+      }

+

+      return TRUE;

+    }

+  }

+

+  return FALSE;

+}

+

+EFI_STATUS

+SubmitExtBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,

+  UINT8                                         Target,

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device

+                      specified by Target.

+

+  Returns:            EFI_STATUS

+

+--*/

+{

+  UINT8       PacketCommand[12];

+  UINT64      TimeoutInMicroSeconds;

+  EFI_STATUS  PacketCommandStatus;

+

+  //

+  // Fill ATAPI Command Packet according to CDB

+  //

+  ZeroMem (&PacketCommand, 12);

+  CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);

+

+  //

+  // Timeout is 100ns unit, convert it to 1000ns (1us) unit.

+  //

+  TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);

+

+  //

+  // Submit ATAPI Command Packet

+  //

+  if (Packet->DataDirection == DataIn) {

+    PacketCommandStatus = AtapiPacketCommand (

+                              AtapiScsiPrivate,

+                              Target,

+                              PacketCommand,

+                              Packet->InDataBuffer,

+                              &(Packet->InTransferLength),

+                              DataIn,

+                              TimeoutInMicroSeconds

+                              );

+  } else {

+

+    PacketCommandStatus = AtapiPacketCommand (

+                            AtapiScsiPrivate,

+                            Target,

+                            PacketCommand,

+                            Packet->OutDataBuffer,

+                            &(Packet->OutTransferLength),

+                            DataOut,

+                            TimeoutInMicroSeconds

+                            );

+  }

+

+  if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {

+    Packet->SenseDataLength = 0;

+    return PacketCommandStatus;

+  }

+

+  //

+  // Return SenseData if PacketCommandStatus matches

+  // the following return codes.

+  //

+  if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||

+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||

+      (PacketCommandStatus == EFI_TIMEOUT)) {

+

+    //

+    // avoid submit request sense command continuously.

+    //

+    if (PacketCommand[0] == OP_REQUEST_SENSE) {

+      Packet->SenseDataLength = 0;

+      return PacketCommandStatus;

+    }

+

+    RequestSenseCommand (

+      AtapiScsiPrivate,

+      Target,

+      Packet->Timeout,

+      Packet->SenseData,

+      &Packet->SenseDataLength

+      );

+  }

+

+  return PacketCommandStatus;

+}

+

+

+EFI_STATUS

+AtapiPacketCommand (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT32                      Target,

+  UINT8                       *PacketCommand,

+  VOID                        *Buffer,

+  UINT32                      *ByteCount,

+  DATA_DIRECTION              Direction,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Submits ATAPI command packet to the specified ATAPI device.

+

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  PacketCommand:      Points to the ATAPI command packet.

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction.

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that

+                      this function will wait indefinitely for the ATAPI

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then

+                      this function will return EFI_TIMEOUT if the time

+                      required to execute the ATAPI command is greater

+                      than TimeoutInMicroSeconds.

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+

+  UINT16      *CommandIndex;

+  UINT8       Count;

+  EFI_STATUS  Status;

+

+  //

+  // Set all the command parameters by fill related registers.

+  // Before write to all the following registers, BSY must be 0.

+  //

+  Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);

+  if (EFI_ERROR (Status)) {

+    return EFI_DEVICE_ERROR;

+  }

+

+

+  //

+  // Select device via Device/Head Register.

+  // "Target = 0" indicates device 0; "Target = 1" indicates device 1

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Head,

+    (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)

+    );

+

+  //

+  // Set all the command parameters by fill related registers.

+  // Before write to all the following registers, BSY DRQ must be 0.

+  //

+  Status =  StatusDRQClear(AtapiScsiPrivate,  TimeoutInMicroSeconds);

+

+  if (EFI_ERROR (Status)) {

+    if (Status == EFI_ABORTED) {

+      Status = EFI_DEVICE_ERROR;

+    }

+    *ByteCount = 0;

+    return Status;

+  }

+

+  //

+  // No OVL; No DMA (by setting feature register)

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Reg1.Feature,

+    0x00

+    );

+

+  //

+  // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device

+  // determine how much data should be transfered.

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->CylinderLsb,

+    (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)

+    );

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->CylinderMsb,

+    (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)

+    );

+

+  //

+  //  DEFAULT_CTL:0x0a (0000,1010)

+  //  Disable interrupt

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Alt.DeviceControl,

+    DEFAULT_CTL

+    );

+

+  //

+  // Send Packet command to inform device

+  // that the following data bytes are command packet.

+  //

+  WritePortB (

+    AtapiScsiPrivate->PciIo,

+    AtapiScsiPrivate->IoPort->Reg.Command,

+    PACKET_CMD

+    );

+

+  //

+  // Before data transfer, BSY should be 0 and DRQ should be 1.

+  // if they are not in specified time frame,

+  // retrieve Sense Key from Error Register before return.

+  //

+  Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);

+  if (EFI_ERROR (Status)) {

+    if (Status == EFI_ABORTED) {

+      Status = EFI_DEVICE_ERROR;

+    }

+

+    *ByteCount = 0;

+    return Status;

+  }

+

+  //

+  // Send out command packet

+  //

+  CommandIndex = (UINT16 *) PacketCommand;

+  for (Count = 0; Count < 6; Count++, CommandIndex++) {

+    WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);

+  }

+

+  //

+  // call AtapiPassThruPioReadWriteData() function to get

+  // requested transfer data form device.

+  //

+  return AtapiPassThruPioReadWriteData (

+          AtapiScsiPrivate,

+          Buffer,

+          ByteCount,

+          Direction,

+          TimeoutInMicroSeconds

+          );

+}

+

+EFI_STATUS

+AtapiPassThruPioReadWriteData (

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,

+  UINT16                    *Buffer,

+  UINT32                    *ByteCount,

+  DATA_DIRECTION            Direction,

+  UINT64                    TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Performs data transfer between ATAPI device and host after the

+  ATAPI command packet is sent.

+

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction.

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that

+                      this function will wait indefinitely for the ATAPI

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then

+                      this function will return EFI_TIMEOUT if the time

+                      required to execute the ATAPI command is greater

+                      than TimeoutInMicroSeconds.

+ Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT32      Index;

+  UINT32      RequiredWordCount;

+  UINT32      ActualWordCount;

+  UINT32      WordCount;

+  EFI_STATUS  Status;

+  UINT16      *ptrBuffer;

+

+  Status = EFI_SUCCESS;

+

+  //

+  // Non Data transfer request is also supported.

+  //

+  if (*ByteCount == 0 || Buffer == NULL) {

+    *ByteCount = 0;

+    if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {

+      return EFI_DEVICE_ERROR;

+    }

+  }

+

+  ptrBuffer         = Buffer;

+  RequiredWordCount = *ByteCount / 2;

+

+  //

+  // ActuralWordCount means the word count of data really transfered.

+  //

+  ActualWordCount = 0;

+

+  while (ActualWordCount < RequiredWordCount) {

+    //

+    // before each data transfer stream, the host should poll DRQ bit ready,

+    // which indicates device's ready for data transfer .

+    //

+    Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);

+    if (EFI_ERROR (Status)) {

+      *ByteCount = ActualWordCount * 2;

+

+      AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);

+

+      if (ActualWordCount == 0) {

+        return EFI_DEVICE_ERROR;

+      }

+      //

+      // ActualWordCount > 0

+      //

+      if (ActualWordCount < RequiredWordCount) {

+        return EFI_BAD_BUFFER_SIZE;

+      }

+    }

+    //

+    // get current data transfer size from Cylinder Registers.

+    //

+    WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;

+    WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);

+    WordCount = WordCount & 0xffff;

+    WordCount /= 2;

+

+    //

+    // perform a series data In/Out.

+    //

+    for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {

+

+      if (Direction == DataIn) {

+

+        *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);

+      } else {

+

+        WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);

+      }

+

+      ptrBuffer++;

+

+    }

+  }

+  //

+  // After data transfer is completed, normally, DRQ bit should clear.

+  //

+  StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);

+

+  //

+  // read status register to check whether error happens.

+  //

+  Status      = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);

+

+  *ByteCount  = ActualWordCount * 2;

+

+  return Status;

+}

+

+

+UINT8

+ReadPortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one byte from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+

+Returns:

+

+  A byte read out

+

+--*/

+{

+  UINT8 Data;

+

+  Data = 0;

+  PciIo->Io.Read (

+              PciIo,

+              EfiPciIoWidthUint8,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+  return Data;

+}

+

+

+UINT16

+ReadPortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one word from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+

+Returns:

+

+  A word read out

+--*/

+{

+  UINT16  Data;

+

+  Data = 0;

+  PciIo->Io.Read (

+              PciIo,

+              EfiPciIoWidthUint16,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+  return Data;

+}

+

+

+VOID

+WritePortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT8                 Data

+  )

+/*++

+

+Routine Description:

+

+  Write one byte to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+

+Returns:

+

+   NONE

+

+--*/

+{

+  PciIo->Io.Write (

+              PciIo,

+              EfiPciIoWidthUint8,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+}

+

+

+VOID

+WritePortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT16                Data

+  )

+/*++

+

+Routine Description:

+

+  Write one word to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+

+Returns:

+

+   NONE

+

+--*/

+{

+  PciIo->Io.Write (

+              PciIo,

+              EfiPciIoWidthUint16,

+              EFI_PCI_IO_PASS_THROUGH_BAR,

+              (UINT64) Port,

+              1,

+              &Data

+              );

+}

+

+EFI_STATUS

+StatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+

+    //

+    // wait for BSY == 0 and DRQ == 0

+    //

+    if ((StatusRegister & (DRQ | BSY)) == 0) {

+      break;

+    }

+    //

+    // check whether the command is aborted by the device

+    //

+    if ((StatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+

+        return EFI_ABORTED;

+      }

+    }

+    //

+    //  Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Alternate Status Register.

+  (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should

+  wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+

+    //

+    // wait for BSY == 0 and DRQ == 0

+    //

+    if ((AltStatusRegister & (DRQ | BSY)) == 0) {

+      break;

+    }

+

+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+

+        return EFI_ABORTED;

+      }

+    }

+    //

+    //  Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+StatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    //

+    //  read Status Register will clear interrupt

+    //

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+

+    //

+    //  BSY==0,DRQ==1

+    //

+    if ((StatusRegister & (BSY | DRQ)) == DRQ) {

+      break;

+    }

+

+    if ((StatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Alternate Status Register.

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    //

+    //  read Status Register will clear interrupt

+    //

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+    //

+    //  BSY==0,DRQ==1

+    //

+    if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {

+      break;

+    }

+

+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+StatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+    if ((StatusRegister & BSY) == 0x00) {

+      break;

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Alternate Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+    if ((AltStatusRegister & BSY) == 0x00) {

+      break;

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+StatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  UINT64                       TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Status Register.

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   StatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    StatusRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg.Status

+                      );

+    //

+    //  BSY == 0 , DRDY == 1

+    //

+    if ((StatusRegister & (DRDY | BSY)) == DRDY) {

+      break;

+    }

+

+    if ((StatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AltStatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  UINT64                       TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Alternate Status Register.

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT64  Delay;

+  UINT8   AltStatusRegister;

+  UINT8   ErrRegister;

+

+  if (TimeoutInMicroSeconds == 0) {

+    Delay = 2;

+  } else {

+    Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;

+  }

+

+  do {

+    AltStatusRegister = ReadPortB (

+                          AtapiScsiPrivate->PciIo,

+                          AtapiScsiPrivate->IoPort->Alt.AltStatus

+                          );

+    //

+    //  BSY == 0 , DRDY == 1

+    //

+    if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {

+      break;

+    }

+

+    if ((AltStatusRegister & (BSY | ERR)) == ERR) {

+

+      ErrRegister = ReadPortB (

+                      AtapiScsiPrivate->PciIo,

+                      AtapiScsiPrivate->IoPort->Reg1.Error

+                      );

+      if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {

+        return EFI_ABORTED;

+      }

+    }

+

+    //

+    // Stall for 30 us

+    //

+    gBS->Stall (30);

+    //

+    // Loop infinitely if not meeting expected condition

+    //

+    if (TimeoutInMicroSeconds == 0) {

+      Delay = 2;

+    }

+

+    Delay--;

+  } while (Delay);

+

+  if (Delay == 0) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+AtapiPassThruCheckErrorStatus (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate

+  )

+/*++

+

+Routine Description:

+

+  Check Error Register for Error Information.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+{

+  UINT8 StatusRegister;

+  UINT8 ErrorRegister;

+

+  StatusRegister = ReadPortB (

+                    AtapiScsiPrivate->PciIo,

+                    AtapiScsiPrivate->IoPort->Reg.Status

+                    );

+

+  DEBUG_CODE_BEGIN ();

+

+    if (StatusRegister & DWF) {

+      DEBUG (

+        (EFI_D_BLKIO,

+        "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",

+        StatusRegister)

+        );

+    }

+

+    if (StatusRegister & CORR) {

+      DEBUG (

+        (EFI_D_BLKIO,

+        "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",

+        StatusRegister)

+        );

+    }

+

+    if (StatusRegister & ERR) {

+      ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);

+

+

+      if (ErrorRegister & BBK_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & UNC_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & MC_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & ABRT_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & TK0NF_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",

+          ErrorRegister)

+          );

+      }

+

+      if (ErrorRegister & AMNF_ERR) {

+        DEBUG (

+          (EFI_D_BLKIO,

+          "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",

+          ErrorRegister)

+          );

+       }

+    }

+

+  DEBUG_CODE_END ();

+

+  if ((StatusRegister & (ERR | DWF | CORR)) == 0) {

+    return EFI_SUCCESS;

+  }

+

+

+  return EFI_DEVICE_ERROR;

+}

+

+

+/**

+  Installs Scsi Pass Thru and/or Ext Scsi Pass Thru

+  protocols based on feature flags.

+

+  @param Controller         The controller handle to

+                            install these protocols on.

+  @param AtapiScsiPrivate   A pointer to the protocol private

+                            data structure.

+

+  @retval EFI_SUCCESS       The installation succeeds.

+  @retval other             The installation fails.

+

+**/

+EFI_STATUS

+InstallScsiPassThruProtocols (

+  IN EFI_HANDLE                     *ControllerHandle,

+  IN ATAPI_SCSI_PASS_THRU_DEV       *AtapiScsiPrivate

+  )

+{

+  EFI_STATUS                        Status;

+  EFI_SCSI_PASS_THRU_PROTOCOL       *ScsiPassThru;

+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *ExtScsiPassThru;

+

+  ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;

+  ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;

+

+  if (FeaturePcdGet (PcdSupportScsiPassThru)) {

+    ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));

+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {

+      ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      ControllerHandle,

+                      &gEfiScsiPassThruProtocolGuid,

+                      ScsiPassThru,

+                      &gEfiExtScsiPassThruProtocolGuid,

+                      ExtScsiPassThru,

+                      NULL

+                      );

+    } else {

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      ControllerHandle,

+                      &gEfiScsiPassThruProtocolGuid,

+                      ScsiPassThru,

+                      NULL

+                      );

+    }

+  } else {

+    if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {

+      ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      ControllerHandle,

+                      &gEfiExtScsiPassThruProtocolGuid,

+                      ExtScsiPassThru,

+                      NULL

+                      );

+    } else {

+      //

+      // This driver must support either ScsiPassThru or

+      // ExtScsiPassThru protocols

+      //

+      ASSERT (FALSE);

+      Status = EFI_UNSUPPORTED;

+    }

+  }

+

+  return Status;

+}

+

+/**

+  The user Entry Point for module AtapiPassThru. The user code starts with this function.

+

+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.

+  @param[in] SystemTable    A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS       The entry point is executed successfully.

+  @retval other             Some error occurs when executing this entry point.

+

+**/

+EFI_STATUS

+EFIAPI

+InitializeAtapiPassThru(

+  IN EFI_HANDLE           ImageHandle,

+  IN EFI_SYSTEM_TABLE     *SystemTable

+  )

+{

+  EFI_STATUS              Status;

+

+  //

+  // Install driver model protocol(s).

+  //

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             SystemTable,

+             &gAtapiScsiPassThruDriverBinding,

+             ImageHandle,

+             &gAtapiScsiPassThruComponentName,

+             &gAtapiScsiPassThruComponentName2

+             );

+  ASSERT_EFI_ERROR (Status);

+

+  //

+  // Install EFI Driver Supported EFI Version Protocol required for

+  // EFI drivers that are on PCI and other plug in cards.

+  //

+  gAtapiScsiPassThruDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                  &ImageHandle,

+                  &gEfiDriverSupportedEfiVersionProtocolGuid,

+                  &gAtapiScsiPassThruDriverSupportedEfiVersion,

+                  NULL

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h
new file mode 100644
index 0000000..e1f1759
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h
@@ -0,0 +1,1624 @@
+/** @file

+  Copyright (c) 2006 - 2011, 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.

+

+  Module Name:  AtapiPassThru.h

+

+**/

+

+#ifndef _APT_H

+#define _APT_H

+

+

+

+#include <Uefi.h>

+

+#include <Protocol/ScsiPassThru.h>

+#include <Protocol/ScsiPassThruExt.h>

+#include <Protocol/PciIo.h>

+#include <Protocol/DriverSupportedEfiVersion.h>

+

+#include <Library/DebugLib.h>

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/BaseLib.h>

+#include <Library/UefiLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/PcdLib.h>

+#include <Library/DevicePathLib.h>

+

+#include <IndustryStandard/Pci.h>

+

+#define MAX_TARGET_ID 4

+

+//

+// IDE Registers

+//

+typedef union {

+  UINT16  Command;        /* when write */

+  UINT16  Status;         /* when read */

+} IDE_CMD_OR_STATUS;

+

+typedef union {

+  UINT16  Error;          /* when read */

+  UINT16  Feature;        /* when write */

+} IDE_ERROR_OR_FEATURE;

+

+typedef union {

+  UINT16  AltStatus;      /* when read */

+  UINT16  DeviceControl;  /* when write */

+} IDE_AltStatus_OR_DeviceControl;

+

+

+typedef enum {

+  IdePrimary    = 0,

+  IdeSecondary  = 1,

+  IdeMaxChannel = 2

+} EFI_IDE_CHANNEL;

+

+///

+

+

+//

+// Bit definitions in Programming Interface byte of the Class Code field

+// in PCI IDE controller's Configuration Space

+//

+#define IDE_PRIMARY_OPERATING_MODE            BIT0

+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR    BIT1

+#define IDE_SECONDARY_OPERATING_MODE          BIT2

+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR  BIT3

+

+

+#define ATAPI_MAX_CHANNEL 2

+

+///

+/// IDE registers set

+///

+typedef struct {

+  UINT16                          Data;

+  IDE_ERROR_OR_FEATURE            Reg1;

+  UINT16                          SectorCount;

+  UINT16                          SectorNumber;

+  UINT16                          CylinderLsb;

+  UINT16                          CylinderMsb;

+  UINT16                          Head;

+  IDE_CMD_OR_STATUS               Reg;

+  IDE_AltStatus_OR_DeviceControl  Alt;

+  UINT16                          DriveAddress;

+} IDE_BASE_REGISTERS;

+

+#define ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE  SIGNATURE_32 ('a', 's', 'p', 't')

+

+typedef struct {

+  UINTN                            Signature;

+  EFI_HANDLE                       Handle;

+  EFI_SCSI_PASS_THRU_PROTOCOL      ScsiPassThru;

+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL  ExtScsiPassThru;

+  EFI_PCI_IO_PROTOCOL              *PciIo;

+  UINT64                           OriginalPciAttributes;

+  //

+  // Local Data goes here

+  //

+  IDE_BASE_REGISTERS               *IoPort;

+  IDE_BASE_REGISTERS               AtapiIoPortRegisters[2];

+  UINT32                           LatestTargetId;

+  UINT64                           LatestLun;

+} ATAPI_SCSI_PASS_THRU_DEV;

+

+//

+// IDE registers' base addresses

+//

+typedef struct {

+  UINT16  CommandBlockBaseAddr;

+  UINT16  ControlBlockBaseAddr;

+} IDE_REGISTERS_BASE_ADDR;

+

+#define ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS(a) \

+  CR (a, \

+      ATAPI_SCSI_PASS_THRU_DEV, \

+      ScsiPassThru, \

+      ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \

+      )

+

+#define ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS(a) \

+  CR (a, \

+      ATAPI_SCSI_PASS_THRU_DEV, \

+      ExtScsiPassThru, \

+      ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE \

+      )

+

+//

+// Global Variables

+//

+extern EFI_DRIVER_BINDING_PROTOCOL                gAtapiScsiPassThruDriverBinding;

+extern EFI_COMPONENT_NAME_PROTOCOL                gAtapiScsiPassThruComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL               gAtapiScsiPassThruComponentName2;

+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL  gAtapiScsiPassThruDriverSupportedEfiVersion;

+

+//

+// ATAPI Command op code

+//

+#define OP_INQUIRY                      0x12

+#define OP_LOAD_UNLOAD_CD               0xa6

+#define OP_MECHANISM_STATUS             0xbd

+#define OP_MODE_SELECT_10               0x55

+#define OP_MODE_SENSE_10                0x5a

+#define OP_PAUSE_RESUME                 0x4b

+#define OP_PLAY_AUDIO_10                0x45

+#define OP_PLAY_AUDIO_MSF               0x47

+#define OP_PLAY_CD                      0xbc

+#define OP_PLAY_CD_MSF                  0xb4

+#define OP_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e

+#define OP_READ_10                      0x28

+#define OP_READ_12                      0xa8

+#define OP_READ_CAPACITY                0x25

+#define OP_READ_CD                      0xbe

+#define OP_READ_CD_MSF                  0xb9

+#define OP_READ_HEADER                  0x44

+#define OP_READ_SUB_CHANNEL             0x42

+#define OP_READ_TOC                     0x43

+#define OP_REQUEST_SENSE                0x03

+#define OP_SCAN                         0xba

+#define OP_SEEK_10                      0x2b

+#define OP_SET_CD_SPEED                 0xbb

+#define OP_STOPPLAY_SCAN                0x4e

+#define OP_START_STOP_UNIT              0x1b

+#define OP_TEST_UNIT_READY              0x00

+

+#define OP_FORMAT_UNIT                  0x04

+#define OP_READ_FORMAT_CAPACITIES       0x23

+#define OP_VERIFY                       0x2f

+#define OP_WRITE_10                     0x2a

+#define OP_WRITE_12                     0xaa

+#define OP_WRITE_AND_VERIFY             0x2e

+

+//

+// ATA Command

+//

+#define ATAPI_SOFT_RESET_CMD  0x08

+

+typedef enum {

+  DataIn  = 0,

+  DataOut = 1,

+  DataBi  = 2,

+  NoData  = 3,

+  End     = 0xff

+} DATA_DIRECTION;

+

+typedef struct {

+  UINT8           OpCode;

+  DATA_DIRECTION  Direction;

+} SCSI_COMMAND_SET;

+

+#define MAX_CHANNEL         2

+

+#define ValidCdbLength(Len) ((Len) == 6 || (Len) == 10 || (Len) == 12) ? 1 : 0

+

+//

+// IDE registers bit definitions

+//

+// ATA Err Reg bitmap

+//

+#define BBK_ERR   BIT7 ///< Bad block detected

+#define UNC_ERR   BIT6 ///< Uncorrectable Data

+#define MC_ERR    BIT5 ///< Media Change

+#define IDNF_ERR  BIT4 ///< ID Not Found

+#define MCR_ERR   BIT3 ///< Media Change Requested

+#define ABRT_ERR  BIT2 ///< Aborted Command

+#define TK0NF_ERR BIT1 ///< Track 0 Not Found

+#define AMNF_ERR  BIT0 ///< Address Mark Not Found

+

+//

+// ATAPI Err Reg bitmap

+//

+#define SENSE_KEY_ERR (BIT7 | BIT6 | BIT5 | BIT4)

+#define EOM_ERR BIT1 ///< End of Media Detected

+#define ILI_ERR BIT0 ///< Illegal Length Indication

+

+//

+// Device/Head Reg

+//

+#define LBA_MODE  BIT6

+#define DEV       BIT4

+#define HS3       BIT3

+#define HS2       BIT2

+#define HS1       BIT1

+#define HS0       BIT0

+#define CHS_MODE  (0)

+#define DRV0      (0)

+#define DRV1      (1)

+#define MST_DRV   DRV0

+#define SLV_DRV   DRV1

+

+//

+// Status Reg

+//

+#define BSY   BIT7 ///< Controller Busy

+#define DRDY  BIT6 ///< Drive Ready

+#define DWF   BIT5 ///< Drive Write Fault

+#define DSC   BIT4 ///< Disk Seek Complete

+#define DRQ   BIT3 ///< Data Request

+#define CORR  BIT2 ///< Corrected Data

+#define IDX   BIT1 ///< Index

+#define ERR   BIT0 ///< Error

+#define CHECK BIT0 ///< Check bit for ATAPI Status Reg

+

+//

+// Device Control Reg

+//

+#define SRST  BIT2 ///< Software Reset

+#define IEN_L BIT1 ///< Interrupt Enable

+

+//

+// ATAPI Feature Register

+//

+#define OVERLAP BIT1

+#define DMA     BIT0

+

+//

+// ATAPI Interrupt Reason Reson Reg (ATA Sector Count Register)

+//

+#define RELEASE     BIT2

+#define IO          BIT1

+#define CoD         BIT0

+

+#define PACKET_CMD  0xA0

+

+#define DEFAULT_CMD (0xa0)

+//

+// default content of device control register, disable INT

+//

+#define DEFAULT_CTL           (0x0a)

+#define MAX_ATAPI_BYTE_COUNT  (0xfffe)

+

+//

+// function prototype

+//

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,

+  IN  EFI_HANDLE                      Controller,

+  IN  UINTN                           NumberOfChildren,

+  IN  EFI_HANDLE                      *ChildHandleBuffer

+  );

+

+//

+// EFI Component Name Functions

+//

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  );

+

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruDriverEntryPoint (

+  IN EFI_HANDLE         ImageHandle,

+  IN EFI_SYSTEM_TABLE   *SystemTable

+  )

+ /*++

+

+Routine Description:

+

+  Entry point for EFI drivers.

+

+Arguments:

+

+  ImageHandle - EFI_HANDLE

+  SystemTable - EFI_SYSTEM_TABLE

+

+Returns:

+

+  EFI_SUCCESS

+  Others 

+

+--*/

+;

+

+EFI_STATUS

+RegisterAtapiScsiPassThru (

+  IN  EFI_DRIVER_BINDING_PROTOCOL *This,

+  IN  EFI_HANDLE                  Controller,

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  IN  UINT64                      OriginalPciAttributes

+  )

+/*++

+

+Routine Description:

+  Attaches SCSI Pass Thru Protocol for specified IDE channel.

+    

+Arguments:

+  This              - Protocol instance pointer.

+  Controller        - Parent device handle to the IDE channel.    

+  PciIo             - PCI I/O protocol attached on the "Controller".                        

+  

+Returns:

+  Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruFunction (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL                        *This,

+  IN UINT32                                             Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET         *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI 

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device 

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored, 

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported, 

+            then non-blocking I/O is performed, and Event will be signaled 

+            when the SCSI Request Packet completes.      

+

+Returns:  

+

+   EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetNextDevice (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT32                      *Target,

+  IN OUT UINT64                      *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of 

+                          0xFFFFFFFF retrieves the Target ID of the first 

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruBuildDevicePath (

+  IN     EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT32                         Target,

+  IN     UINT64                         Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL       **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device 

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device 

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that 

+                          describes the SCSI device specified by 

+                          Target and Lun. This function is responsible 

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's 

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.    

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and 

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate 

+                          DevicePath.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruGetTargetLun (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,

+  OUT UINT32                         *Target,

+  OUT UINT64                         *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that 

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device 

+                          on the SCSI channel. 

+  Lun                   - A pointer to the LUN of a SCSI device on 

+                          the SCSI channel.    

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a 

+                          Target ID and LUN, and they were returned 

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path 

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a 

+                          Target ID and LUN does not exist.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetChannel (

+  IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the 

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support 

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while 

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting 

+                          to reset the SCSI channel.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruResetTarget (

+  IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT32                         Target,

+  IN UINT64                         Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset. 

+  Lun                   - The LUN of the SCSI device to reset.

+    

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and 

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting 

+                          to reset the SCSI device specified by Target 

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset 

+                          the SCSI device specified by Target and Lun.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruFunction (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,

+  IN UINT8                                              *Target,

+  IN UINT64                                             Lun,

+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,

+  IN EFI_EVENT                                          Event OPTIONAL

+  )

+/*++

+

+Routine Description:

+

+  Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.

+

+Arguments:

+

+  This:     The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.

+  Target:   The Target ID of the ATAPI device to send the SCSI 

+            Request Packet. To ATAPI devices attached on an IDE

+            Channel, Target ID 0 indicates Master device;Target

+            ID 1 indicates Slave device.

+  Lun:      The LUN of the ATAPI device to send the SCSI Request

+            Packet. To the ATAPI device, Lun is always 0.

+  Packet:   The SCSI Request Packet to send to the ATAPI device 

+            specified by Target and Lun.

+  Event:    If non-blocking I/O is not supported then Event is ignored, 

+            and blocking I/O is performed.

+            If Event is NULL, then blocking I/O is performed.

+            If Event is not NULL and non blocking I/O is supported, 

+            then non-blocking I/O is performed, and Event will be signaled 

+            when the SCSI Request Packet completes.      

+

+Returns:  

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target,

+  IN OUT UINT64                          *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                          present on a SCSI channel.  An input value of 

+                          0xFFFFFFFF retrieves the Target ID of the first 

+                          SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+Returns:

+

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                           returned on a previous call to GetNextDevice().

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruBuildDevicePath (

+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN     UINT8                              *Target,

+  IN     UINT64                             Lun,

+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath

+  )

+/*++

+

+Routine Description:

+

+  Used to allocate and build a device path node for a SCSI device 

+  on a SCSI channel. Would not build device path for a SCSI Host Controller.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device for which

+                          a device path node is to be allocated and built.

+  Lun                   - The LUN of the SCSI device for which a device 

+                          path node is to be allocated and built.

+  DevicePath            - A pointer to a single device path node that 

+                          describes the SCSI device specified by 

+                          Target and Lun. This function is responsible 

+                          for allocating the buffer DevicePath with the boot

+                          service AllocatePool().  It is the caller's 

+                          responsibility to free DevicePath when the caller

+                          is finished with DevicePath.    

+  Returns:

+  EFI_SUCCESS           - The device path node that describes the SCSI device

+                          specified by Target and Lun was allocated and 

+                          returned in DevicePath.

+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does

+                          not exist on the SCSI channel.

+  EFI_INVALID_PARAMETER - DevicePath is NULL.

+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate 

+                          DevicePath.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL       *DevicePath,

+  OUT UINT8                          **Target,

+  OUT UINT64                         *Lun

+  )

+/*++

+

+Routine Description:

+

+  Used to translate a device path node to a Target ID and LUN.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  DevicePath            - A pointer to the device path node that 

+                          describes a SCSI device on the SCSI channel.

+  Target                - A pointer to the Target ID of a SCSI device 

+                          on the SCSI channel. 

+  Lun                   - A pointer to the LUN of a SCSI device on 

+                          the SCSI channel.    

+Returns:

+

+  EFI_SUCCESS           - DevicePath was successfully translated to a 

+                          Target ID and LUN, and they were returned 

+                          in Target and Lun.

+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.

+  EFI_UNSUPPORTED       - This driver does not support the device path 

+                          node type in DevicePath.

+  EFI_NOT_FOUND         - A valid translation from DevicePath to a 

+                          Target ID and LUN does not exist.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetChannel (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI channel.This operation resets all the 

+  SCSI devices connected to the SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+

+Returns:

+

+  EFI_SUCCESS           - The SCSI channel was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support 

+                          a channel reset operation.

+  EFI_DEVICE_ERROR      - A device error occurred while 

+                          attempting to reset the SCSI channel.

+  EFI_TIMEOUT           - A timeout occurred while attempting 

+                          to reset the SCSI channel.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruResetTarget (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN UINT8                              *Target,

+  IN UINT64                             Lun

+  )

+/*++

+

+Routine Description:

+

+  Resets a SCSI device that is connected to a SCSI channel.

+

+Arguments:

+

+  This                  - Protocol instance pointer.

+  Target                - The Target ID of the SCSI device to reset. 

+  Lun                   - The LUN of the SCSI device to reset.

+    

+Returns:

+

+  EFI_SUCCESS           - The SCSI device specified by Target and 

+                          Lun was reset.

+  EFI_UNSUPPORTED       - The SCSI channel does not support a target

+                          reset operation.

+  EFI_INVALID_PARAMETER - Target or Lun are invalid.

+  EFI_DEVICE_ERROR      - A device error occurred while attempting 

+                          to reset the SCSI device specified by Target 

+                          and Lun.

+  EFI_TIMEOUT           - A timeout occurred while attempting to reset 

+                          the SCSI device specified by Target and Lun.

+

+--*/

+;

+

+EFI_STATUS

+EFIAPI

+AtapiExtScsiPassThruGetNextTarget (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,

+  IN OUT UINT8                           **Target

+  )

+/*++

+

+Routine Description:

+  Used to retrieve the list of legal Target IDs for SCSI devices 

+  on a SCSI channel.

+

+Arguments:

+  This                  - Protocol instance pointer.

+  Target                - On input, a pointer to the Target ID of a SCSI 

+                          device present on the SCSI channel.  On output, 

+                          a pointer to the Target ID of the next SCSI device

+                           present on a SCSI channel.  An input value of 

+                           0xFFFFFFFF retrieves the Target ID of the first 

+                           SCSI device present on a SCSI channel.

+  Lun                   - On input, a pointer to the LUN of a SCSI device

+                          present on the SCSI channel. On output, a pointer

+                          to the LUN of the next SCSI device present on 

+                          a SCSI channel.

+    

+Returns:

+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device 

+                          on the SCSI channel was returned in Target and Lun.

+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.

+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not

+                          returned on a previous call to GetNextDevice().

+

+--*/

+;

+

+EFI_STATUS

+CheckSCSIRequestPacket (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+SubmitBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,

+  UINT32                                    Target,

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device 

+                      specified by Target.

+  

+  Returns:            EFI_STATUS  

+

+--*/

+;

+

+BOOLEAN

+IsCommandValid (

+  EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+ /*++

+

+Routine Description:

+

+  Checks the requested SCSI command: 

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+CheckExtSCSIRequestPacket (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet

+  )

+/*++

+

+Routine Description:

+

+  Checks the parameters in the SCSI Request Packet to make sure

+  they are valid for a SCSI Pass Thru request.

+

+Arguments:

+

+  Packet       - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET

+  

+Returns:

+  

+  EFI_STATUS

+

+--*/

+;

+

+

+BOOLEAN

+IsExtCommandValid (

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet

+  )

+/*++

+  

+Routine Description:

+

+  Checks the requested SCSI command: 

+  Is it supported by this driver?

+  Is the Data transfer direction reasonable?

+

+Arguments:

+

+  Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+SubmitExtBlockingIoCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,

+  UINT8                                         Target,

+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet

+  )

+/*++

+

+Routine Description:

+

+  Performs blocking I/O request.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  Packet:             The SCSI Request Packet to send to the ATAPI device 

+                      specified by Target.

+  

+  Returns:            EFI_STATUS  

+  

+--*/

+;

+

+EFI_STATUS

+RequestSenseCommand (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT32                      Target,

+  UINT64                      Timeout,

+  VOID                        *SenseData,

+  UINT8                       *SenseDataLength

+  )

+/*++

+

+Routine Description:

+

+  Sumbit request sense command

+

+Arguments:

+

+  AtapiScsiPrivate  - The pionter of ATAPI_SCSI_PASS_THRU_DEV

+  Target            - The target ID

+  Timeout           - The time to complete the command

+  SenseData         - The buffer to fill in sense data

+  SenseDataLength   - The length of buffer

+

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AtapiPacketCommand (

+  ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,

+  UINT32                                    Target,

+  UINT8                                     *PacketCommand,

+  VOID                                      *Buffer,

+  UINT32                                    *ByteCount,

+  DATA_DIRECTION                            Direction,

+  UINT64                                    TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Submits ATAPI command packet to the specified ATAPI device.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.

+  Target:             The Target ID of the ATAPI device to send the SCSI 

+                      Request Packet. To ATAPI devices attached on an IDE

+                      Channel, Target ID 0 indicates Master device;Target

+                      ID 1 indicates Slave device.

+  PacketCommand:      Points to the ATAPI command packet.

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction. 

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the 

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that 

+                      this function will wait indefinitely for the ATAPI 

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then 

+                      this function will return EFI_TIMEOUT if the time 

+                      required to execute the ATAPI command is greater 

+                      than TimeoutInMicroSeconds.

+  

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+

+UINT8

+ReadPortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one byte from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  

+Returns:

+

+  A byte read out

+

+--*/

+;

+

+

+UINT16

+ReadPortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port

+  )

+/*++

+

+Routine Description:

+

+  Read one word from a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  

+Returns:     

+

+  A word read out

+

+--*/

+;

+

+

+VOID

+WritePortB (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT8                 Data

+  )

+/*++

+

+Routine Description:

+

+  Write one byte to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+  

+Returns:

+ 

+  NONE

+ 

+--*/

+;

+

+

+VOID

+WritePortW (

+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,

+  IN  UINT16                Port,

+  IN  UINT16                Data

+  )

+/*++

+

+Routine Description:

+

+  Write one word to a specified I/O port.

+

+Arguments:

+

+  PciIo      - The pointer of EFI_PCI_IO_PROTOCOL

+  Port       - IO port

+  Data       - The data to write

+  

+Returns:

+

+  NONE

+  

+--*/

+;

+

+EFI_STATUS

+StatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusDRQClear (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is clear in the Alternate Status Register. 

+  (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should 

+  wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+StatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Status Register. (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusDRQReady (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,

+  UINT64                          TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRQ is ready in the Alternate Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+StatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusWaitForBSYClear (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether BSY is clear in the Alternate Status Register.

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+StatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AltStatusDRDYReady (

+  ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,

+  UINT64                      TimeoutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Check whether DRDY is ready in the Alternate Status Register. 

+  (BSY must also be cleared)

+  If TimeoutInMicroSeconds is zero, this routine should wait infinitely for

+  DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is 

+  elapsed.

+

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  TimeoutInMicroSeconds       - The time to wait for

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AtapiPassThruPioReadWriteData (

+  ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,

+  UINT16                    *Buffer,

+  UINT32                    *ByteCount,

+  DATA_DIRECTION            Direction,

+  UINT64                    TimeOutInMicroSeconds

+  )

+/*++

+

+Routine Description:

+

+  Performs data transfer between ATAPI device and host after the

+  ATAPI command packet is sent.

+    

+Arguments:

+

+  AtapiScsiPrivate:   Private data structure for the specified channel.    

+  Buffer:             Points to the transferred data.

+  ByteCount:          When input,indicates the buffer size; when output,

+                      indicates the actually transferred data size.

+  Direction:          Indicates the data transfer direction. 

+  TimeoutInMicroSeconds:

+                      The timeout, in micro second units, to use for the 

+                      execution of this ATAPI command.

+                      A TimeoutInMicroSeconds value of 0 means that 

+                      this function will wait indefinitely for the ATAPI 

+                      command to execute.

+                      If TimeoutInMicroSeconds is greater than zero, then 

+                      this function will return EFI_TIMEOUT if the time 

+                      required to execute the ATAPI command is greater 

+                      than TimeoutInMicroSeconds.

+ Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+EFI_STATUS

+AtapiPassThruCheckErrorStatus (

+  ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate

+  )

+/*++

+

+Routine Description:

+

+  Check Error Register for Error Information. 

+  

+Arguments:

+

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+   

+Returns:

+

+  EFI_STATUS

+

+--*/

+;

+

+

+EFI_STATUS

+GetIdeRegistersBaseAddr (

+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,

+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+  Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,

+  use fixed addresses. In Native-PCI mode, get base addresses from BARs in

+  the PCI IDE controller's Configuration Space.

+

+Arguments:

+  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance

+  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to 

+                      receive IDE IO port registers' base addresses

+                      

+Returns:

+

+  EFI_STATUS

+    

+--*/

+;

+

+

+VOID

+InitAtapiIoPortRegisters (

+  IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,

+  IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr

+  )

+/*++

+

+Routine Description:

+

+  Initialize each Channel's Base Address of CommandBlock and ControlBlock.

+

+Arguments:

+    

+  AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV

+  IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR

+  

+Returns:

+  

+  None

+

+--*/  

+;

+

+/**

+  Installs Scsi Pass Thru and/or Ext Scsi Pass Thru 

+  protocols based on feature flags. 

+

+  @param Controller         The controller handle to 

+                            install these protocols on.

+  @param AtapiScsiPrivate   A pointer to the protocol private

+                            data structure.

+

+  @retval EFI_SUCCESS       The installation succeeds. 

+  @retval other             The installation fails. 

+   

+**/

+EFI_STATUS

+InstallScsiPassThruProtocols (

+  IN EFI_HANDLE                 *ControllerHandle,

+  IN ATAPI_SCSI_PASS_THRU_DEV   *AtapiScsiPrivate

+  );

+

+#endif

diff --git a/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf
new file mode 100644
index 0000000..8709f15
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf
@@ -0,0 +1,75 @@
+## @file

+# Description file for the Atapi Pass Thru driver.

+#

+# This driver simulates SCSI devices with Atapi devices to test the SCSI io

+#  protocol.

+# Copyright (c) 2007 - 2010, 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.

+#

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = AtapiPassThruDxe

+  FILE_GUID                      = E49061CE-99A7-41d3-AB3A-36E5CFBAD63E

+  MODULE_TYPE                    = UEFI_DRIVER

+  VERSION_STRING                 = 1.0

+

+  ENTRY_POINT                    = InitializeAtapiPassThru

+

+  PCI_VENDOR_ID                  = 0x8086

+  PCI_DEVICE_ID                  = 0x2921

+  PCI_CLASS_CODE                 = 0x010100

+  PCI_REVISION                   = 0x0003

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+#  DRIVER_BINDING                =  gAtapiScsiPassThruDriverBinding              

+#  COMPONENT_NAME                =  gAtapiScsiPassThruComponentName              

+#

+

+[Sources]

+  DriverSupportedEfiVersion.c

+  ComponentName.c

+  AtapiPassThru.c

+  AtapiPassThru.h

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OptionRomPkg/OptionRomPkg.dec

+

+[LibraryClasses]

+  UefiBootServicesTableLib

+  MemoryAllocationLib

+  BaseMemoryLib

+  UefiLib

+  BaseLib

+  UefiDriverEntryPoint

+  DebugLib

+  DevicePathLib

+

+

+[Protocols]

+  gEfiScsiPassThruProtocolGuid                  # PROTOCOL BY_START

+  gEfiExtScsiPassThruProtocolGuid               # PROTOCOL BY_START

+  gEfiPciIoProtocolGuid                         # PROTOCOL TO_START

+  gEfiDriverSupportedEfiVersionProtocolGuid     # PROTOCOL ALWAYS_PRODUCED

+

+[FeaturePcd]

+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru

+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru

+

+[Pcd]

+  gOptionRomPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/ComponentName.c b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/ComponentName.c
new file mode 100644
index 0000000..f179db7
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/ComponentName.c
@@ -0,0 +1,175 @@
+/** @file

+  Copyright (c) 2006 - 2011, 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.             

+

+  Module Name:  ComponentName.c

+

+**/

+#include "AtapiPassThru.h"

+

+//

+// EFI Component Name Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gAtapiScsiPassThruComponentName = {

+  AtapiScsiPassThruComponentNameGetDriverName,

+  AtapiScsiPassThruComponentNameGetControllerName,

+  "eng"

+};

+

+//

+// EFI Component Name 2 Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtapiScsiPassThruComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtapiScsiPassThruComponentNameGetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtapiScsiPassThruComponentNameGetControllerName,

+  "en"

+};

+

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtapiScsiPassThruDriverNameTable[] = {

+  { "eng;en", (CHAR16 *) L"ATAPI SCSI Pass Thru Driver" },

+  { NULL , NULL }

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  )

+{

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mAtapiScsiPassThruDriverNameTable,

+           DriverName,

+           (BOOLEAN)(This == &gAtapiScsiPassThruComponentName)

+           );

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+AtapiScsiPassThruComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  )

+{

+  return EFI_UNSUPPORTED;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c
new file mode 100644
index 0000000..ca5c173
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c
@@ -0,0 +1,20 @@
+/** @file

+  Copyright (c) 2007, 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.             

+

+  Module Name:  DriverSupportEfiVersion.c

+

+**/

+#include "AtapiPassThru.h"

+

+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gAtapiScsiPassThruDriverSupportedEfiVersion = {

+  sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.

+  0                                                   // Version number to be filled at start up.

+};

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/CompatibleDevices.txt b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/CompatibleDevices.txt
new file mode 100644
index 0000000..1ec1cce
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/CompatibleDevices.txt
@@ -0,0 +1,5 @@
+The following devices have been confirmed to work with the USB Serial Driver:

+

+Brand        Model Name        Product Name          Vendor ID    Device ID

+Gearmo       USA_FTDI-36       USB to RS-232         0x0403       0x6001

+Sabrent      CB-FTDI                                 0x0403       0x6001
\ No newline at end of file
diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c
new file mode 100644
index 0000000..c200878
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c
@@ -0,0 +1,224 @@
+/** @file

+  UEFI Component Name(2) protocol implementation for USB Serial driver.

+

+Copyright (c) 2004 - 2013, 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.

+

+**/

+

+#include "FtdiUsbSerialDriver.h"

+

+//

+// EFI Component Name Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbSerialComponentName = {

+  (EFI_COMPONENT_NAME_GET_DRIVER_NAME) UsbSerialComponentNameGetDriverName,

+  (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) UsbSerialComponentNameGetControllerName,

+  "eng"

+};

+

+//

+// EFI Component Name 2 Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbSerialComponentName2 = {

+  UsbSerialComponentNameGetDriverName,

+  UsbSerialComponentNameGetControllerName,

+  "en"

+};

+

+//

+// Driver name string table

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbSerialDriverNameTable[] = {

+  { "eng;en", L"FTDI-232 USB Serial Driver" },

+  { NULL , NULL }

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param  Language              A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+  @param  DriverName            A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,

+  IN  CHAR8                         *Language,

+  OUT CHAR16                        **DriverName

+  )

+{

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mUsbSerialDriverNameTable,

+           DriverName,

+           (BOOLEAN)(This == &gUsbSerialComponentName2)

+           );

+}

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param  ControllerHandle      The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+  @param  ChildHandle           The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+  @param  Language              A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+  @param  ControllerName        A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,

+  IN  EFI_HANDLE                    ControllerHandle,

+  IN  EFI_HANDLE                    ChildHandle      OPTIONAL,

+  IN  CHAR8                         *Language,

+  OUT CHAR16                        **ControllerName

+  )

+{

+  EFI_STATUS              Status;

+  USB_SER_DEV             *UsbSerDev;

+  EFI_SERIAL_IO_PROTOCOL  *SerialIo;

+  EFI_USB_IO_PROTOCOL     *UsbIoProtocol;

+  

+  //

+  // This is a device driver, so ChildHandle must be NULL.

+  //

+  if (ChildHandle != NULL) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Check Controller's handle

+  //

+  Status = gBS->OpenProtocol (

+                  ControllerHandle,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &UsbIoProtocol,

+                  gUsbSerialDriverBinding.DriverBindingHandle,

+                  ControllerHandle,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (!EFI_ERROR (Status)) {

+    gBS->CloseProtocol (

+           ControllerHandle,

+           &gEfiUsbIoProtocolGuid,

+           gUsbSerialDriverBinding.DriverBindingHandle,

+           ControllerHandle

+           );

+

+    return EFI_UNSUPPORTED;

+  }

+

+  if (Status != EFI_ALREADY_STARTED) {

+    return EFI_UNSUPPORTED;

+  }

+  //

+  // Get the device context

+  //

+  Status = gBS->OpenProtocol (

+                  ControllerHandle,

+                  &gEfiSerialIoProtocolGuid,

+                  (VOID **) &SerialIo,

+                  gUsbSerialDriverBinding.DriverBindingHandle,

+                  ControllerHandle,

+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  UsbSerDev = USB_SER_DEV_FROM_THIS (SerialIo);

+

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           UsbSerDev->ControllerNameTable,

+           ControllerName,

+           (BOOLEAN)(This == &gUsbSerialComponentName2)

+           );

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c
new file mode 100644
index 0000000..595ef4a
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c
@@ -0,0 +1,2588 @@
+/** @file

+  USB Serial Driver that manages USB to Serial and produces Serial IO Protocol.

+

+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.

+Portions Copyright 2012 Ashley DeSimone

+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.

+

+**/

+

+//

+

+// Tested with VEND_ID 0x0403, DEVICE_ID 0x6001

+//

+// Driver starts the device with the following values:

+// 115200, No parity, 8 data bits, 1 stop bit, No Flow control

+//

+

+#include "FtdiUsbSerialDriver.h"

+

+//

+// Table of supported devices. This is the device information that this

+// driver was developed with. Add other FTDI devices as needed.

+//

+USB_DEVICE gUSBDeviceList[] = {

+  {VID_FTDI, DID_FTDI_FT232},

+  {0,0}

+};

+

+//

+// USB Serial Driver Global Variables

+//

+EFI_DRIVER_BINDING_PROTOCOL  gUsbSerialDriverBinding = {

+  UsbSerialDriverBindingSupported,

+  UsbSerialDriverBindingStart,

+  UsbSerialDriverBindingStop,

+  0xa,

+  NULL,

+  NULL

+};

+

+//

+// Table with the nearest power of 2 for the numbers 0-15

+//

+UINT8 gRoundedPowersOf2[16] = { 0, 2, 2, 4, 4, 4, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16 };

+

+/**

+  Check to see if the device path node is the Flow control node

+

+  @param[in] FlowControl    The device path node to be checked

+

+  @retval    TRUE           It is the flow control node

+  @retval    FALSE          It is not the flow control node

+

+**/

+BOOLEAN

+IsUartFlowControlNode (

+  IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl

+  )

+{

+  return (BOOLEAN) (

+           (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&

+           (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&

+           (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))

+           );

+}

+

+/**

+  Checks the device path to see if it contains flow control.

+

+  @param[in] DevicePath    The device path to be checked

+

+  @retval    TRUE          It contains flow control

+  @retval    FALSE         It does not contain flow control

+

+**/

+BOOLEAN

+ContainsFlowControl (

+  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath

+  )

+{

+  while (!IsDevicePathEnd (DevicePath)) {

+    if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {

+      return TRUE;

+    }

+    DevicePath = NextDevicePathNode (DevicePath);

+  }

+  return FALSE;

+}

+

+/**

+  Transfer the data between the device and host.

+

+  This function transfers the data between the device and host.

+  BOT transfer is composed of three phases: Command, Data, and Status.

+  This is the Data phase.

+

+  @param  UsbBot[in]                     The USB BOT device

+  @param  DataDir[in]                    The direction of the data

+  @param  Data[in, out]                  The buffer to hold data

+  @param  TransLen[in, out]              The expected length of the data

+  @param  Timeout[in]                    The time to wait the command to complete

+

+  @retval EFI_SUCCESS                    The data is transferred

+  @retval EFI_SUCCESS                    No data to transfer

+  @retval EFI_NOT_READY                  The device return NAK to the transfer

+  @retval Others                         Failed to transfer data

+

+**/

+EFI_STATUS

+UsbSerialDataTransfer (

+  IN USB_SER_DEV             *UsbBot,

+  IN EFI_USB_DATA_DIRECTION  DataDir,

+  IN OUT VOID                *Data,

+  IN OUT UINTN               *TransLen,

+  IN UINT32                  Timeout

+  )

+{

+  EFI_USB_ENDPOINT_DESCRIPTOR  *Endpoint;

+  EFI_STATUS                   Status;

+  UINT32                       Result;

+

+  //

+  // If no data to transfer, just return EFI_SUCCESS.

+  //

+  if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {

+    return EFI_SUCCESS;

+  }

+

+  //

+  // Select the endpoint then issue the transfer

+  //

+  if (DataDir == EfiUsbDataIn) {

+    Endpoint = &UsbBot->InEndpointDescriptor;

+  } else {

+    Endpoint = &UsbBot->OutEndpointDescriptor;

+  }

+

+  Result = 0;

+  Status = UsbBot->UsbIo->UsbBulkTransfer (

+                            UsbBot->UsbIo,

+                            Endpoint->EndpointAddress,

+                            Data,

+                            TransLen,

+                            Timeout,

+                            &Result

+                            );

+  if (EFI_ERROR (Status)) {

+    if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {

+      Status = EFI_NOT_READY;

+    } else {

+      UsbBot->Shutdown = TRUE; // Fixes infinite loop in older EFI

+    }

+    return Status;

+  }

+  return Status;

+}

+

+/**

+  Sets the status values of the Usb Serial Device.

+

+  @param  UsbSerialDevice[in]  Handle to the Usb Serial Device to set the status

+                               for

+  @param  StatusBuffer[in]     Buffer holding the status values

+

+  @retval EFI_SUCCESS          The status values were read and set correctly

+

+**/

+EFI_STATUS

+EFIAPI

+SetStatusInternal (

+  IN USB_SER_DEV  *UsbSerialDevice,

+  IN UINT8        *StatusBuffer

+  )

+{

+  UINT8  Msr;

+

+  Msr = (StatusBuffer[0] & MSR_MASK);

+

+  //

+  // set the Status values to disabled

+  //

+  UsbSerialDevice->StatusValues.CtsState = FALSE;

+  UsbSerialDevice->StatusValues.DsrState = FALSE;

+  UsbSerialDevice->StatusValues.RiState  = FALSE;

+  UsbSerialDevice->StatusValues.SdState  = FALSE;

+

+  //

+  // Check the values from the status buffer and set the appropriate status

+  // values to enabled

+  //

+  if ((Msr & CTS_MASK) == CTS_MASK) {

+    UsbSerialDevice->StatusValues.CtsState = TRUE;

+  }

+  if ((Msr & DSR_MASK) == DSR_MASK) {

+    UsbSerialDevice->StatusValues.DsrState = TRUE;

+  }

+  if ((Msr & RI_MASK) == RI_MASK) {

+    UsbSerialDevice->StatusValues.RiState = TRUE;

+  }

+  if ((Msr & SD_MASK) == SD_MASK) {

+    UsbSerialDevice->StatusValues.SdState = TRUE;

+  }

+  return EFI_SUCCESS;

+}

+

+/**

+  Initiates a read operation on the Usb Serial Device.

+

+  @param  UsbSerialDevice[in]        Handle to the USB device to read

+  @param  BufferSize[in, out]        On input, the size of the Buffer. On output,

+                                     the amount of data returned in Buffer.

+                                     Setting this to zero will initiate a read

+                                     and store all data returned in the internal

+                                     buffer.

+  @param  Buffer [out]               The buffer to return the data into.

+

+  @retval EFI_SUCCESS                The data was read.

+  @retval EFI_DEVICE_ERROR           The device reported an error.

+  @retval EFI_TIMEOUT                The data write was stopped due to a timeout.

+

+**/

+EFI_STATUS

+EFIAPI

+ReadDataFromUsb (

+  IN USB_SER_DEV  *UsbSerialDevice,

+  IN OUT UINTN    *BufferSize,

+  OUT VOID        *Buffer

+  )

+{

+  EFI_STATUS  Status;

+  UINTN       ReadBufferSize;

+  UINT8       *ReadBuffer;

+  UINTN       Index;

+  EFI_TPL     Tpl;

+  UINT8       StatusBuffer[2]; // buffer to store the status bytes

+

+  ReadBufferSize = 512;

+  ReadBuffer     = &(UsbSerialDevice->ReadBuffer[0]);

+

+  if (UsbSerialDevice->Shutdown) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  Tpl = gBS->RaiseTPL (TPL_NOTIFY);

+

+  Status = UsbSerialDataTransfer (

+             UsbSerialDevice,

+             EfiUsbDataIn,

+             ReadBuffer,

+             &ReadBufferSize,

+             FTDI_TIMEOUT*2  //Padded because timers won't be exactly aligned

+             );

+  if (EFI_ERROR (Status)) {

+    gBS->RestoreTPL (Tpl);

+    if (Status == EFI_TIMEOUT) {

+      return EFI_TIMEOUT;

+    } else {

+      return EFI_DEVICE_ERROR;

+    }

+  }

+

+  //

+  // Store the status bytes in the status buffer

+  //

+  for (Index = 0; Index < 2; Index++) {//only the first 2 bytes are status bytes

+    StatusBuffer[Index] = ReadBuffer[Index];

+  }

+  //

+  // update the statusvalue field of the usbserialdevice

+  //

+  Status = SetStatusInternal (UsbSerialDevice, StatusBuffer);

+  if (Status != EFI_SUCCESS) {

+  }

+

+  //

+  // Store the read data in the read buffer, start at 2 to ignore status bytes

+  //

+  for (Index = 2; Index < ReadBufferSize; Index++) {

+    if (((UsbSerialDevice->DataBufferTail + 1) % SW_FIFO_DEPTH) == UsbSerialDevice->DataBufferHead) {

+      break;

+    }

+    if (ReadBuffer[Index] == 0x00) {

+      //

+      // This is null, do not add

+      //

+    } else {

+      UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferTail] = ReadBuffer[Index];

+      UsbSerialDevice->DataBufferTail = (UsbSerialDevice->DataBufferTail + 1) % SW_FIFO_DEPTH;

+    }

+  }

+

+  //

+  // Read characters out of the buffer to satisfy caller's request.

+  //

+  for (Index = 0; Index < *BufferSize; Index++) {

+    if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {

+      break;

+    }

+    //

+    // Still have characters in the buffer to return

+    //

+    ((UINT8 *)Buffer)[Index]        = UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferHead];

+    UsbSerialDevice->DataBufferHead = (UsbSerialDevice->DataBufferHead + 1) % SW_FIFO_DEPTH;

+  }

+  //

+  // Return actual number of bytes returned.

+  //

+  *BufferSize = Index;

+  gBS->RestoreTPL (Tpl);

+  return EFI_SUCCESS;

+}

+

+/**

+  Sets the initial status values of the Usb Serial Device by reading the status

+  bytes from the device.

+

+  @param  UsbSerialDevice[in]  Handle to the Usb Serial Device that needs its

+                               initial status values set

+

+  @retval EFI_SUCCESS          The status bytes were read successfully and the

+                               initial status values were set correctly

+  @retval EFI_TIMEOUT          The read of the status bytes was stopped due to a

+                               timeout

+  @retval EFI_DEVICE_ERROR     The device reported an error during the read of

+                               the status bytes

+

+**/

+EFI_STATUS

+EFIAPI

+SetInitialStatus (

+  IN USB_SER_DEV          *UsbSerialDevice

+  )

+{

+  EFI_STATUS      Status;

+  UINTN           BufferSize;

+  EFI_TPL         Tpl;

+  UINT8           StatusBuffer[2];

+

+  Status          = EFI_UNSUPPORTED;

+  BufferSize      = sizeof (StatusBuffer);

+

+  if (UsbSerialDevice->Shutdown) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  Tpl = gBS->RaiseTPL (TPL_NOTIFY);

+

+  Status = UsbSerialDataTransfer (

+             UsbSerialDevice,

+             EfiUsbDataIn,

+             StatusBuffer,

+             &BufferSize,

+             40    //Slightly more than 2x the FTDI polling frequency to make sure that data will be returned

+             );

+

+  Status = SetStatusInternal (UsbSerialDevice, StatusBuffer);

+

+  gBS->RestoreTPL (Tpl);

+

+  return Status;

+}

+

+/**

+  UsbSerialDriverCheckInput.

+  attempts to read data in from the device periodically, stores any read data

+  and updates the control attributes.

+

+  @param  Event[in]

+  @param  Context[in]....The current instance of the USB serial device

+

+**/

+VOID

+EFIAPI

+UsbSerialDriverCheckInput (

+  IN  EFI_EVENT  Event,

+  IN  VOID       *Context

+  )

+{

+  UINTN        BufferSize;

+  USB_SER_DEV  *UsbSerialDevice;

+

+  UsbSerialDevice = (USB_SER_DEV*)Context;

+

+  if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {

+    //

+    // Data buffer is empty, try to read from device

+    //

+    BufferSize = 0;

+    ReadDataFromUsb (UsbSerialDevice, &BufferSize, NULL);

+    if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {

+      //

+      // Data buffer still has no data, set the EFI_SERIAL_INPUT_BUFFER_EMPTY

+      // flag

+      //

+      UsbSerialDevice->ControlBits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;

+    } else {

+      //

+      // Read has returned some data, clear the EFI_SERIAL_INPUT_BUFFER_EMPTY

+      // flag

+      //

+      UsbSerialDevice->ControlBits &= ~(EFI_SERIAL_INPUT_BUFFER_EMPTY);

+    }

+  } else {

+    //

+    // Data buffer has data, no read attempt required

+    //

+    UsbSerialDevice->ControlBits &= ~(EFI_SERIAL_INPUT_BUFFER_EMPTY);

+  }

+}

+

+/**

+  Encodes the baud rate into the format expected by the Ftdi device.

+

+  @param  BaudRate[in]                The baudrate to be set on the device

+  @param  EncodedBaudRate[out]        The baud rate encoded in the format

+                                      expected by the Ftdi device

+

+  @return EFI_SUCCESS                 Baudrate encoding was calculated

+                                      successfully

+  @return EFI_INVALID_PARAMETER       An invalid value of BaudRate was received

+

+**/

+EFI_STATUS

+EFIAPI

+EncodeBaudRateForFtdi (

+  IN  UINT64  BaudRate,

+  OUT UINT16  *EncodedBaudRate

+  )

+{

+  UINT32 Divisor;

+  UINT32 AdjustedFrequency;

+  UINT16 Result;

+

+  //

+  // Check to make sure we won't get an integer overflow

+  //

+  if ((BaudRate < 178) || ( BaudRate > ((FTDI_UART_FREQUENCY * 100) / 97))) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Baud Rates of 2000000 and 3000000 are special cases

+  //

+  if ((BaudRate >= FTDI_SPECIAL_CASE_300_MIN) && (BaudRate <= FTDI_SPECIAL_CASE_300_MAX)) {

+    *EncodedBaudRate = 0;

+    return EFI_SUCCESS;

+  }

+  if ((BaudRate >= FTDI_SPECIAL_CASE_200_MIN) && (BaudRate <= FTDI_SPECIAL_CASE_200_MAX)) {

+    *EncodedBaudRate = 1;

+    return EFI_SUCCESS;

+  }

+

+  //

+  // Compute divisor

+  //

+  Divisor = (FTDI_UART_FREQUENCY << 4) / (UINT32)BaudRate;

+

+  //

+  // Round the last 4 bits to the nearest power of 2

+  //

+  Divisor = (Divisor & ~(0xF)) + (gRoundedPowersOf2[Divisor & 0xF]);

+

+  //

+  // Check to make sure computed divisor is within 

+  // the min and max that FTDI controller will accept

+  //

+  if (Divisor < FTDI_MIN_DIVISOR) {

+    Divisor = FTDI_MIN_DIVISOR;

+  } else if (Divisor > FTDI_MAX_DIVISOR) {

+    Divisor = FTDI_MAX_DIVISOR;

+  }

+

+  //

+  // Check to make sure the frequency that the FTDI chip will need to

+  // generate to attain the requested Baud Rate is within 3% of the

+  // 3MHz clock frequency that the FTDI chip runs at.

+  //

+  // (3MHz * 1600) / 103 = 46601941

+  // (3MHz * 1600) / 97  = 49484536

+  //

+  AdjustedFrequency = (((UINT32)BaudRate) * Divisor);

+  if ((AdjustedFrequency < FTDI_MIN_FREQUENCY) || (AdjustedFrequency > FTDI_MAX_FREQUENCY)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Encode the Divisor into the format FTDI expects

+  //

+  Result = (UINT16)(Divisor >> 4);

+  if ((Divisor & 0x8) != 0) {

+    Result |= 0x4000;

+  } else if ((Divisor & 0x4) != 0) {

+    Result |= 0x8000;

+  } else if ((Divisor & 0x2) != 0) {

+    Result |= 0xC000;

+  }

+

+  *EncodedBaudRate = Result;

+  return EFI_SUCCESS;

+}

+

+/**

+  Uses USB I/O to check whether the device is a USB Serial device.

+

+  @param  UsbIo[in]    Pointer to a USB I/O protocol instance.

+

+  @retval TRUE         Device is a USB Serial device.

+  @retval FALSE        Device is a not USB Serial device.

+

+**/

+BOOLEAN

+IsUsbSerial (

+  IN  EFI_USB_IO_PROTOCOL  *UsbIo

+  )

+{

+  EFI_STATUS                 Status;

+  EFI_USB_DEVICE_DESCRIPTOR  DeviceDescriptor;

+  CHAR16                     *StrMfg;

+  BOOLEAN                    Found;

+  UINT32                     Index;

+

+  //

+  // Get the default device descriptor

+  //

+  Status = UsbIo->UsbGetDeviceDescriptor (

+                    UsbIo,

+                    &DeviceDescriptor

+                    );

+  if (EFI_ERROR (Status)) {

+    return FALSE;

+  }

+

+  Found = FALSE;

+  Index = 0;

+  while (gUSBDeviceList[Index].VendorId != 0 &&

+         gUSBDeviceList[Index].DeviceId != 0 &&

+         !Found                                  ) {

+    if (DeviceDescriptor.IdProduct == gUSBDeviceList[Index].DeviceId &&

+        DeviceDescriptor.IdVendor  == gUSBDeviceList[Index].VendorId      ){

+        //

+        // Checks to see if a string descriptor can be pulled from the device in

+        // the selected language. If not False is returned indicating that this

+        // is not a Usb Serial Device that can be managegd by this driver

+        //

+        StrMfg = NULL;

+        Status = UsbIo->UsbGetStringDescriptor (

+                          UsbIo,

+                          USB_US_LANG_ID, // LANGID selector, should make this

+                                          // more robust to verify lang support

+                                          // for device

+                          DeviceDescriptor.StrManufacturer,

+                          &StrMfg

+                          );

+        if (StrMfg != NULL) {

+          FreePool (StrMfg);

+        }

+        if (EFI_ERROR (Status)) {

+          return FALSE;

+        }

+        return TRUE;

+    }

+    Index++;

+  }

+  return FALSE;

+}

+

+/**

+  Internal function that sets the Data Bits, Stop Bits and Parity values on the

+  Usb Serial Device with a single usb control transfer.

+

+  @param  UsbIo[in]                  Usb Io Protocol instance pointer

+  @param  DataBits[in]               The data bits value to be set on the Usb

+                                     Serial Device

+  @param  Parity[in]                 The parity type that will be set on the Usb

+                                     Serial Device

+  @param  StopBits[in]               The stop bits type that will be set on the

+                                     Usb Serial Device

+  @param  LastSettings[in]           A pointer to the Usb Serial Device's

+                                     PREVIOUS_ATTRIBUTES item

+

+  @retval EFI_SUCCESS                The data items were correctly set on the

+                                     USB Serial Device

+  @retval EFI_INVALID_PARAMETER      An invalid data parameter or an invalid

+                                     combination or parameters was used

+  @retval EFI_DEVICE_ERROR           The device is not functioning correctly and

+                                     the data values were unable to be set

+

+**/

+EFI_STATUS

+EFIAPI

+SetDataInternal (

+  IN EFI_USB_IO_PROTOCOL  *UsbIo,

+  IN UINT8                DataBits,

+  IN EFI_PARITY_TYPE      Parity,

+  IN EFI_STOP_BITS_TYPE   StopBits,

+  IN PREVIOUS_ATTRIBUTES  *LastSettings

+  )

+{

+  EFI_STATUS              Status;

+  EFI_USB_DEVICE_REQUEST  DevReq;

+  UINT32                  ReturnValue;

+  UINT8                   ConfigurationValue;

+

+  //

+  // Since data bits settings of 6,7,8 cannot be set with a stop bits setting of

+  // 1.5 check to see if this happens when the values of last settings are used

+  //

+  if ((DataBits == 0) && (StopBits == OneFiveStopBits)) {

+    if ((LastSettings->DataBits == 6) || (LastSettings->DataBits == 7) || (LastSettings->DataBits == 8)) {

+      return EFI_INVALID_PARAMETER;

+    }

+  } else if ((StopBits == DefaultStopBits) && ((DataBits == 6) || (DataBits == 7) || (DataBits == 8))) {

+    if (LastSettings->StopBits == OneFiveStopBits) {

+      return EFI_INVALID_PARAMETER;

+    }

+  } else if ((DataBits == 0) && (StopBits == DefaultStopBits)) {

+    if (LastSettings->StopBits == OneFiveStopBits) {

+      if ((LastSettings->DataBits == 6) || (LastSettings->DataBits == 7) || (LastSettings->DataBits == 8)) {

+        return EFI_INVALID_PARAMETER;

+      }

+    }

+  }

+

+  //

+  // set the DevReq.Value for the usb control transfer to the correct value

+  // based on the seleceted number of data bits if there is an invalid number of

+  // data bits requested return EFI_INVALID_PARAMETER

+  //

+  if (((DataBits < 5 ) || (DataBits > 8)) && (DataBits != 0)) {

+    return EFI_INVALID_PARAMETER;

+  }

+  if (DataBits == 0) {

+    //

+    // use the value of LastDataBits

+    //

+    DevReq.Value = SET_DATA_BITS (LastSettings->DataBits);

+  } else {

+    //

+    // use the value of DataBits

+    //

+    DevReq.Value = SET_DATA_BITS (DataBits);

+  }

+

+  //

+  // Set Parity

+  //

+  if (Parity == DefaultParity) {

+    Parity = LastSettings->Parity;

+  }

+

+  if (Parity == NoParity) {

+    DevReq.Value |= SET_PARITY_NONE;

+  } else if (Parity == EvenParity) {

+    DevReq.Value |= SET_PARITY_EVEN;

+  } else if (Parity == OddParity){

+    DevReq.Value |= SET_PARITY_ODD;

+  } else if (Parity == MarkParity) {

+    DevReq.Value |= SET_PARITY_MARK;

+  } else if (Parity == SpaceParity) {

+    DevReq.Value |= SET_PARITY_SPACE;

+  }

+

+  //

+  // Set Stop Bits

+  //

+  if (StopBits == DefaultStopBits) {

+    StopBits = LastSettings->StopBits;

+  }

+

+  if (StopBits == OneStopBit) {

+    DevReq.Value |= SET_STOP_BITS_1;

+  } else if (StopBits == OneFiveStopBits) {

+    DevReq.Value |= SET_STOP_BITS_15;

+  } else if (StopBits == TwoStopBits) {

+    DevReq.Value |= SET_STOP_BITS_2;

+  }

+

+  //

+  // set the rest of the DevReq parameters and perform the usb control transfer

+  // to set the data bits on the device

+  //

+  DevReq.Request     = FTDI_COMMAND_SET_DATA;

+  DevReq.RequestType = USB_REQ_TYPE_VENDOR;

+  DevReq.Index       = FTDI_PORT_IDENTIFIER;

+  DevReq.Length      = 0; // indicates that there is no data phase in this request

+

+  Status = UsbIo->UsbControlTransfer (

+                    UsbIo,

+                    &DevReq,

+                    EfiUsbDataOut,

+                    WDR_SHORT_TIMEOUT,

+                    &ConfigurationValue,

+                    1,

+                    &ReturnValue

+                    );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+  return Status;

+

+StatusError:

+  if ((Status != EFI_INVALID_PARAMETER) || (Status != EFI_DEVICE_ERROR)) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Internal function that sets the baudrate on the Usb Serial Device.

+

+  @param  UsbIo[in]                  Usb Io Protocol instance pointer

+  @param  BaudRate[in]               The baudrate value to be set on the device.

+                                     If this value is 0 the value of LastBaudRate

+                                     will be used instead

+  @param  LastBaudRate[in]           The baud rate value that was previously set

+                                     on the Usb Serial Device

+

+  @retval EFI_SUCCESS                The baudrate was set succesfully

+  @retval EFI_INVALID_PARAMETER      An invalid baudrate was used

+  @retval EFI_DEVICE_ERROR           The device is not functioning correctly and

+                                     the baudrate was unable to be set

+

+**/

+EFI_STATUS

+EFIAPI

+SetBaudRateInternal (

+  IN EFI_USB_IO_PROTOCOL  *UsbIo,

+  IN UINT64               BaudRate,

+  IN UINT64               LastBaudRate

+  )

+{

+  EFI_STATUS              Status;

+  EFI_USB_DEVICE_REQUEST  DevReq;

+  UINT32                  ReturnValue;

+  UINT8                   ConfigurationValue;

+  UINT16                  EncodedBaudRate;

+  EFI_TPL                 Tpl;

+

+  Tpl    = gBS->RaiseTPL(TPL_NOTIFY);

+

+  //

+  // set the value of DevReq.Value based on the value of BaudRate

+  // if 0 is selected as baud rate use the value of LastBaudRate

+  //

+  if (BaudRate == 0) {

+    Status = EncodeBaudRateForFtdi (LastBaudRate, &EncodedBaudRate);

+    if (EFI_ERROR (Status)) {

+      gBS->RestoreTPL (Tpl);

+      //

+      // EncodeBaudRateForFtdi returns EFI_INVALID_PARAMETER when not

+      // succesfull

+      //

+      return Status;

+    }

+    DevReq.Value = EncodedBaudRate;

+  } else {

+    Status = EncodeBaudRateForFtdi (BaudRate, &EncodedBaudRate);

+    if (EFI_ERROR (Status)) {

+      gBS->RestoreTPL (Tpl);

+      //

+      // EncodeBaudRateForFtdi returns EFI_INVALID_PARAMETER when not

+      // successfull

+      //

+      return Status;

+    }

+    DevReq.Value = EncodedBaudRate;

+  }

+

+  //

+  // set the remaining parameters of DevReq and perform the usb control transfer

+  // to set the device

+  //

+  DevReq.Request     = FTDI_COMMAND_SET_BAUDRATE;

+  DevReq.RequestType = USB_REQ_TYPE_VENDOR;

+  DevReq.Index       = FTDI_PORT_IDENTIFIER;

+  DevReq.Length      = 0; // indicates that there is no data phase in this request

+

+  Status = UsbIo->UsbControlTransfer (

+                    UsbIo,

+                    &DevReq,

+                    EfiUsbDataOut,

+                    WDR_SHORT_TIMEOUT,

+                    &ConfigurationValue,

+                    1,

+                    &ReturnValue

+                    );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+  gBS->RestoreTPL (Tpl);

+  return Status;

+

+StatusError:

+  gBS->RestoreTPL (Tpl);

+  if ((Status != EFI_INVALID_PARAMETER) || (Status != EFI_DEVICE_ERROR)) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,

+  data bits, and stop bits on a serial device.

+

+  @param  UsbSerialDevice[in]  Pointer to the current instance of the USB Serial

+                               Device.

+  @param  BaudRate[in]         The requested baud rate. A BaudRate value of 0

+                               will use the device's default interface speed.

+  @param  ReveiveFifoDepth[in] The requested depth of the FIFO on the receive

+                               side of the serial interface. A ReceiveFifoDepth

+                               value of 0 will use the device's default FIFO

+                               depth.

+  @param  Timeout[in]          The requested time out for a single character in

+                               microseconds.This timeout applies to both the

+                               transmit and receive side of the interface.A

+                               Timeout value of 0 will use the device's default

+                               time out value.

+  @param  Parity[in]           The type of parity to use on this serial device.

+                               A Parity value of DefaultParity will use the

+                               device's default parity value.

+  @param  DataBits[in]         The number of data bits to use on the serial

+                               device. A DataBits value of 0 will use the

+                               device's default data bit setting.

+  @param  StopBits[in]         The number of stop bits to use on this serial

+                               device. A StopBits value of DefaultStopBits will

+                               use the device's default number of stop bits.

+

+  @retval EFI_SUCCESS          The attributes were set

+  @retval EFI_DEVICE_ERROR     The attributes were not able to be set

+

+**/

+EFI_STATUS

+EFIAPI

+SetAttributesInternal (

+  IN USB_SER_DEV         *UsbSerialDevice,

+  IN UINT64              BaudRate,

+  IN UINT32              ReceiveFifoDepth,

+  IN UINT32              Timeout,

+  IN EFI_PARITY_TYPE     Parity,

+  IN UINT8               DataBits,

+  IN EFI_STOP_BITS_TYPE  StopBits

+  )

+{

+  EFI_STATUS                Status;

+  EFI_TPL                   Tpl;

+  UART_DEVICE_PATH          *Uart;

+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;

+

+  Status = EFI_UNSUPPORTED;

+  Tpl    = gBS->RaiseTPL(TPL_NOTIFY);

+  Uart   = NULL;

+

+  //

+  // check for invalid combinations of parameters

+  //

+  if (((DataBits >= 6) && (DataBits <= 8)) && (StopBits == OneFiveStopBits)) {

+    return  EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // set data bits, parity and stop bits

+  //

+  Status = SetDataInternal (

+             UsbSerialDevice->UsbIo,

+             DataBits,

+             Parity,

+             StopBits,

+             &(UsbSerialDevice->LastSettings)

+             );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+  //

+  // set baudrate

+  //

+  Status = SetBaudRateInternal (

+             UsbSerialDevice->UsbIo,

+             BaudRate,

+             UsbSerialDevice->LastSettings.BaudRate

+             );

+  if (EFI_ERROR (Status)){

+    goto StatusError;

+  }

+

+  //

+  // update the values of UsbSerialDevice->LastSettings and UsbSerialDevice->SerialIo.Mode

+  //

+  if (BaudRate == 0) {

+    UsbSerialDevice->LastSettings.BaudRate   = UsbSerialDevice->LastSettings.BaudRate;

+    UsbSerialDevice->SerialIo.Mode->BaudRate = UsbSerialDevice->LastSettings.BaudRate;

+  } else {

+    UsbSerialDevice->LastSettings.BaudRate   = BaudRate;

+    UsbSerialDevice->SerialIo.Mode->BaudRate = BaudRate;

+  }

+

+  UsbSerialDevice->LastSettings.Timeout          = FTDI_TIMEOUT;

+  UsbSerialDevice->LastSettings.ReceiveFifoDepth = FTDI_MAX_RECEIVE_FIFO_DEPTH;

+

+  if (Parity == DefaultParity) {

+    UsbSerialDevice->LastSettings.Parity   = UsbSerialDevice->LastSettings.Parity;

+    UsbSerialDevice->SerialIo.Mode->Parity = UsbSerialDevice->LastSettings.Parity;

+  } else {

+    UsbSerialDevice->LastSettings.Parity   = Parity;

+    UsbSerialDevice->SerialIo.Mode->Parity = Parity;

+  }

+  if (DataBits == 0) {

+    UsbSerialDevice->LastSettings.DataBits   = UsbSerialDevice->LastSettings.DataBits;

+    UsbSerialDevice->SerialIo.Mode->DataBits = UsbSerialDevice->LastSettings.DataBits;

+  } else {

+    UsbSerialDevice->LastSettings.DataBits   = DataBits;

+    UsbSerialDevice->SerialIo.Mode->DataBits = DataBits;

+  }

+  if (StopBits == DefaultStopBits) {

+    UsbSerialDevice->LastSettings.StopBits   = UsbSerialDevice->LastSettings.StopBits;

+    UsbSerialDevice->SerialIo.Mode->StopBits = UsbSerialDevice->LastSettings.StopBits;

+  } else {

+    UsbSerialDevice->LastSettings.StopBits   = StopBits;

+    UsbSerialDevice->SerialIo.Mode->StopBits = StopBits;

+  }

+

+  //

+  // See if the device path node has changed

+  //

+  if (UsbSerialDevice->UartDevicePath.BaudRate == BaudRate &&

+      UsbSerialDevice->UartDevicePath.DataBits == DataBits &&

+      UsbSerialDevice->UartDevicePath.StopBits == StopBits &&

+      UsbSerialDevice->UartDevicePath.Parity == Parity

+      ) {

+    gBS->RestoreTPL (Tpl);

+    return EFI_SUCCESS;

+  }

+

+  //

+  // Update the device path

+  //

+  UsbSerialDevice->UartDevicePath.BaudRate = BaudRate;

+  UsbSerialDevice->UartDevicePath.DataBits = DataBits;

+  UsbSerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;

+  UsbSerialDevice->UartDevicePath.Parity   = (UINT8) Parity;

+

+  Status = EFI_SUCCESS;

+  if (UsbSerialDevice->ControllerHandle != NULL) {

+    RemainingDevicePath = UsbSerialDevice->DevicePath;

+    while (!IsDevicePathEnd (RemainingDevicePath)) {

+      Uart = (UART_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);

+      if (Uart->Header.Type == MESSAGING_DEVICE_PATH &&

+          Uart->Header.SubType == MSG_UART_DP &&

+          sizeof (UART_DEVICE_PATH) == DevicePathNodeLength ((EFI_DEVICE_PATH *) Uart)) {

+        Uart->BaudRate = BaudRate;

+        Uart->DataBits = DataBits;

+        Uart->StopBits = (UINT8)StopBits;

+        Uart->Parity   = (UINT8) Parity;

+        break;

+        }

+        RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);

+    }

+  }

+

+  gBS->RestoreTPL (Tpl);

+  return Status;

+

+StatusError:

+  gBS->RestoreTPL (Tpl);

+  if ((Status != EFI_INVALID_PARAMETER) || (Status != EFI_DEVICE_ERROR)) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Internal function that performs a Usb Control Transfer to set the flow control

+  on the Usb Serial Device.

+

+  @param  UsbIo[in]                  Usb Io Protocol instance pointer

+  @param  FlowControlEnable[in]      Data on the Enable/Disable status of Flow

+                                     Control on the Usb Serial Device

+

+  @retval EFI_SUCCESS                The flow control was set on the Usb Serial

+                                     device

+  @retval EFI_INVALID_PARAMETER      An invalid flow control value was used

+  @retval EFI_EFI_UNSUPPORTED        The operation is not supported

+  @retval EFI_DEVICE_ERROR           The device is not functioning correctly

+

+**/

+EFI_STATUS

+EFIAPI

+SetFlowControlInternal (

+  IN EFI_USB_IO_PROTOCOL  *UsbIo,

+  IN BOOLEAN              FlowControlEnable

+  )

+{

+  EFI_STATUS               Status;

+  EFI_USB_DEVICE_REQUEST   DevReq;

+  UINT32                   ReturnValue;

+  UINT8                    ConfigurationValue;

+

+  //

+  // set DevReq.Value based on the value of FlowControlEnable

+  //

+  if (!FlowControlEnable) {

+    DevReq.Value = NO_FLOW_CTRL;

+  }

+  if (FlowControlEnable) {

+    DevReq.Value = XON_XOFF_CTRL;

+  }

+  //

+  // set the remaining DevReq parameters and perform the usb control transfer to

+  // set the flow control on the device

+  //

+  DevReq.Request      = FTDI_COMMAND_SET_FLOW_CTRL;

+  DevReq.RequestType  = USB_REQ_TYPE_VENDOR;

+  DevReq.Index        = FTDI_PORT_IDENTIFIER;

+  DevReq.Length       = 0; // indicates that this transfer has no data phase

+  Status              = UsbIo->UsbControlTransfer (

+                                 UsbIo,

+                                 &DevReq,

+                                 EfiUsbDataOut,

+                                 WDR_TIMEOUT,

+                                 &ConfigurationValue,

+                                 1,

+                                 &ReturnValue

+                                 );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+

+  return Status;

+

+StatusError:

+  if ((Status != EFI_INVALID_PARAMETER) ||

+      (Status != EFI_DEVICE_ERROR)      ||

+      (Status != EFI_UNSUPPORTED)          ) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Internal function that performs a Usb Control Transfer to set the Dtr value on

+  the Usb Serial Device.

+

+  @param  UsbIo[in]                  Usb Io Protocol instance pointer

+  @param  DtrEnable[in]              Data on the Enable/Disable status of the

+                                     Dtr for the Usb Serial Device

+

+  @retval EFI_SUCCESS                The Dtr value was set on the Usb Serial

+                                     Device

+  @retval EFI_INVALID_PARAMETER      An invalid Dtr value was used

+  @retval EFI_UNSUPPORTED            The operation is not supported

+  @retval EFI_DEVICE_ERROR           The device is not functioning correctly

+

+**/

+EFI_STATUS

+EFIAPI

+SetDtrInternal (

+  IN EFI_USB_IO_PROTOCOL  *UsbIo,

+  IN BOOLEAN              DtrEnable

+  )

+{

+  EFI_STATUS              Status;

+  EFI_USB_DEVICE_REQUEST  DevReq;

+  UINT32                  ReturnValue;

+  UINT8                   ConfigurationValue;

+

+  //

+  // set the value of DevReq.Value based on the value of DtrEnable

+  //

+  if (!DtrEnable) {

+    DevReq.Value = SET_DTR_LOW;

+  }

+  if (DtrEnable) {

+    DevReq.Value = SET_DTR_HIGH;

+  }

+  //

+  // set the remaining attributes of DevReq and perform the usb control transfer

+  // to set the device

+  //

+  DevReq.Request      = FTDI_COMMAND_MODEM_CTRL;

+  DevReq.RequestType  = USB_REQ_TYPE_VENDOR;

+  DevReq.Index        = FTDI_PORT_IDENTIFIER;

+  DevReq.Length       = 0; // indicates that there is no data phase in this transfer

+

+  Status = UsbIo->UsbControlTransfer (

+                    UsbIo,

+                    &DevReq,

+                    EfiUsbDataOut,

+                    WDR_TIMEOUT,

+                    &ConfigurationValue,

+                    1,

+                    &ReturnValue

+                    );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+  return Status;

+

+StatusError:

+  if ((Status != EFI_INVALID_PARAMETER) ||

+      (Status != EFI_DEVICE_ERROR)      ||

+      (Status != EFI_UNSUPPORTED)          ) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Internal function that performs a Usb Control Transfer to set the Dtr value on

+  the Usb Serial Device.

+  

+  @param  UsbIo[in]                  Usb Io Protocol instance pointer

+  @param  RtsEnable[in]              Data on the Enable/Disable status of the

+                                     Rts for the Usb Serial Device

+

+  @retval EFI_SUCCESS                The Rts value was set on the Usb Serial

+                                     Device

+  @retval EFI_INVALID_PARAMETER      An invalid Rts value was used

+  @retval EFI_UNSUPPORTED            The operation is not supported

+  @retval EFI_DEVICE_ERROR           The device is not functioning correctly

+

+**/

+EFI_STATUS

+EFIAPI

+SetRtsInternal (

+  IN EFI_USB_IO_PROTOCOL  *UsbIo,

+  IN BOOLEAN              RtsEnable

+  )

+{

+  EFI_STATUS              Status;

+  EFI_USB_DEVICE_REQUEST  DevReq;

+  UINT32                  ReturnValue;

+  UINT8                   ConfigurationValue;

+

+  //

+  // set DevReq.Value based on the value of RtsEnable

+  //

+  if (!RtsEnable) {

+    DevReq.Value = SET_RTS_LOW;

+  }

+  if (RtsEnable) {

+    DevReq.Value = SET_RTS_HIGH;

+  }

+

+  //

+  // set the remaining parameters of DevReq and perform the usb control transfer

+  // to set the values on the device

+  //

+  DevReq.Request     = FTDI_COMMAND_MODEM_CTRL;

+  DevReq.RequestType = USB_REQ_TYPE_VENDOR;

+  DevReq.Index       = FTDI_PORT_IDENTIFIER;

+  DevReq.Length      = 0; // indicates that there is no data phase in this request

+

+  Status = UsbIo->UsbControlTransfer (

+                    UsbIo,

+                    &DevReq,

+                    EfiUsbDataOut,

+                    WDR_TIMEOUT,

+                    &ConfigurationValue,

+                    1,

+                    &ReturnValue

+                    );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+

+  return Status;

+

+StatusError:

+  if ((Status != EFI_INVALID_PARAMETER) ||

+      (Status != EFI_DEVICE_ERROR)      ||

+      (Status != EFI_UNSUPPORTED)          ) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Internal function that checks for valid control values and sets the control

+  bits on the Usb Serial Device.

+

+  @param  UsbSerialDevice[in]        Handle to the Usb Serial Device whose

+                                     control bits are being set

+  @param  Control[in]                The control value passed to the function

+                                     that contains the values of the control

+                                     bits that are being set

+

+  @retval EFI_SUCCESS                The control bits were set on the Usb Serial

+                                     Device

+  @retval EFI_INVALID_PARAMETER      An invalid control value was encountered

+  @retval EFI_EFI_UNSUPPORTED        The operation is not supported

+  @retval EFI_DEVICE_ERROR           The device is not functioning correctly

+

+**/

+EFI_STATUS

+EFIAPI

+SetControlBitsInternal (

+  IN USB_SER_DEV   *UsbSerialDevice,

+  IN CONTROL_BITS  *Control

+  )

+{

+  EFI_STATUS                    Status;

+  UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;

+  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath;

+

+  //

+  // check for invalid control parameters hardware and software loopback enabled

+  // must always be set to FALSE

+  //

+  Control->HardwareLoopBack = FALSE;

+  Control->SoftwareLoopBack = FALSE;

+

+  //

+  // set hardware flow control

+  //

+  Status  = SetFlowControlInternal (

+              UsbSerialDevice->UsbIo,

+              Control->HardwareFlowControl

+              );

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+

+  //

+  // set Dtr state

+  //

+  Status = SetDtrInternal (UsbSerialDevice->UsbIo, Control->DtrState);

+  if (EFI_ERROR (Status)) {

+    goto StatusError;

+  }

+

+  //

+  // set Rts state

+  //

+  Status = SetRtsInternal (UsbSerialDevice->UsbIo, Control->RtsState);

+  if (EFI_ERROR (Status)){

+    goto StatusError;

+  }

+

+  //

+  // update the remaining control values for UsbSerialDevice->ControlValues

+  //

+  UsbSerialDevice->ControlValues.DtrState            = Control->DtrState;

+  UsbSerialDevice->ControlValues.RtsState            = Control->RtsState;

+  UsbSerialDevice->ControlValues.HardwareFlowControl = Control->HardwareFlowControl;

+  UsbSerialDevice->ControlValues.HardwareLoopBack    = FALSE;

+  UsbSerialDevice->ControlValues.SoftwareLoopBack    = FALSE;

+

+  Status = EFI_SUCCESS;

+  //

+  // Update the device path to have the correct flow control values

+  //

+  if (UsbSerialDevice->ControllerHandle != NULL) {

+    RemainingDevicePath = UsbSerialDevice->DevicePath;

+    while (!IsDevicePathEnd (RemainingDevicePath)) {

+      FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);

+      if (FlowControl->Header.Type == MESSAGING_DEVICE_PATH &&

+          FlowControl->Header.SubType == MSG_VENDOR_DP &&

+          sizeof (UART_FLOW_CONTROL_DEVICE_PATH) == DevicePathNodeLength ((EFI_DEVICE_PATH *) FlowControl)){

+        if (UsbSerialDevice->ControlValues.HardwareFlowControl == TRUE) {

+          FlowControl->FlowControlMap = UART_FLOW_CONTROL_HARDWARE;

+        } else if (UsbSerialDevice->ControlValues.HardwareFlowControl == FALSE) {

+          FlowControl->FlowControlMap = 0;

+        }

+        break;

+      }

+      RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);

+    }

+  }

+

+  return Status;

+

+StatusError:

+  if ((Status != EFI_INVALID_PARAMETER) ||

+      (Status != EFI_DEVICE_ERROR)      ||

+      (Status != EFI_UNSUPPORTED)          ) {

+    return EFI_DEVICE_ERROR;

+  } else {

+    return Status;

+  }

+}

+

+/**

+  Internal function that calculates the Control value used by GetControlBits()

+  based on the status and control values of the Usb Serial Device.

+

+  @param  UsbSerialDevice[in]        Handle to the Usb Serial Devie whose status

+                                     and control values are being used to set

+                                     Control

+  @param  Control[out]               On output the formated value of Control

+                                     that has been calculated based on the

+                                     control and status values of the Usb Serial

+                                     Device

+

+  @retval EFI_SUCCESS                The value of Control was successfully

+                                     calculated

+

+**/

+EFI_STATUS

+EFIAPI

+GetControlBitsInternal (

+  IN USB_SER_DEV  *UsbSerialDevice,

+  OUT UINT32      *Control

+  )

+{

+  *Control = 0;

+

+  //

+  // Check the values of UsbSerialDevice->Status Values and modify control

+  // accordingly these values correspond to the modem status register

+  //

+  if (UsbSerialDevice->StatusValues.CtsState) {

+    *Control |= EFI_SERIAL_CLEAR_TO_SEND;

+  }

+  if (UsbSerialDevice->StatusValues.DsrState) {

+    *Control |= EFI_SERIAL_DATA_SET_READY;

+  }

+  if (UsbSerialDevice->StatusValues.RiState) {

+    *Control |= EFI_SERIAL_RING_INDICATE;

+  }

+  if (UsbSerialDevice->StatusValues.SdState) {

+    *Control |= EFI_SERIAL_CARRIER_DETECT;

+  }

+

+  //

+  // check the values of UsbSerialDevice->ControlValues and modify control

+  // accordingly these values correspond to the values of the Modem Control

+  // Register

+  //

+  if (UsbSerialDevice->ControlValues.DtrState) {

+    *Control |= EFI_SERIAL_DATA_TERMINAL_READY;

+  }

+  if (UsbSerialDevice->ControlValues.RtsState) {

+    *Control |= EFI_SERIAL_REQUEST_TO_SEND;

+  }

+  if (UsbSerialDevice->ControlValues.HardwareLoopBack) {

+    *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;

+  }

+  if (UsbSerialDevice->ControlValues.HardwareFlowControl) {

+    *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;

+  }

+  //

+  // check if the buffer is empty since only one is being used if it is empty

+  // set both the receive and transmit buffers to empty

+  //

+  if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {

+    *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;

+    *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;

+  }

+  //

+  // check for software loopback enable in UsbSerialDevice->ControlValues

+  //

+  if (UsbSerialDevice->ControlValues.SoftwareLoopBack) {

+    *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Resets the USB Serial Device

+

+  This function is the internal method for reseting the device and is called by

+  SerialReset()

+

+  @param  UsbSerialDevice[in]  A pointer to the USB Serial device

+

+  @retval EFI_SUCCESS          The device was reset

+  @retval EFI_DEVICE_ERROR     The device could not be reset

+

+**/

+EFI_STATUS

+EFIAPI

+ResetInternal (

+  IN USB_SER_DEV  *UsbSerialDevice

+  )

+{

+  EFI_STATUS              Status;

+  EFI_USB_DEVICE_REQUEST  DevReq;

+  UINT8                   ConfigurationValue;

+  UINT32                  ReturnValue;

+

+  DevReq.Request     = FTDI_COMMAND_RESET_PORT;

+  DevReq.RequestType = USB_REQ_TYPE_VENDOR;

+  DevReq.Value       = RESET_PORT_PURGE_RX;

+  DevReq.Index       = FTDI_PORT_IDENTIFIER;

+  DevReq.Length      = 0; //indicates that there is not data phase in this request

+

+  Status = UsbSerialDevice->UsbIo->UsbControlTransfer (

+                                     UsbSerialDevice->UsbIo,

+                                     &DevReq,

+                                     EfiUsbDataIn,

+                                     WDR_TIMEOUT,

+                                     &ConfigurationValue,

+                                     1,

+                                     &ReturnValue

+                                     );

+  if (EFI_ERROR (Status)) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  DevReq.Request     = FTDI_COMMAND_RESET_PORT;

+  DevReq.RequestType = USB_REQ_TYPE_VENDOR;

+  DevReq.Value       = RESET_PORT_PURGE_TX;

+  DevReq.Index       = FTDI_PORT_IDENTIFIER;

+  DevReq.Length      = 0; //indicates that there is no data phase in this request

+

+  Status = UsbSerialDevice->UsbIo->UsbControlTransfer (

+                                     UsbSerialDevice->UsbIo,

+                                     &DevReq,

+                                     EfiUsbDataIn,

+                                     WDR_TIMEOUT,

+                                     &ConfigurationValue,

+                                     1,

+                                     &ReturnValue

+                                     );

+  if (EFI_ERROR (Status)) {

+    return EFI_DEVICE_ERROR;

+  }

+  return Status;

+}

+

+/**

+  Entrypoint of USB Serial Driver.

+

+  This function is the entrypoint of USB Serial Driver. It installs

+  Driver Binding Protocols together with Component Name Protocols.

+

+  @param  ImageHandle[in]       The firmware allocated handle for the EFI image.

+  @param  SystemTable[in]       A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS           The entry point is executed successfully.

+

+**/

+EFI_STATUS

+EFIAPI

+FtdiUsbSerialEntryPoint (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  EFI_STATUS  Status;

+

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             SystemTable,

+             &gUsbSerialDriverBinding,

+             ImageHandle,

+             &gUsbSerialComponentName,

+             &gUsbSerialComponentName2

+             );

+  ASSERT_EFI_ERROR (Status);

+  return EFI_SUCCESS;

+}

+

+/**

+  Unload function for the Usb Serial Driver.

+

+  @param  ImageHandle[in]    The allocated handle for the EFI image

+

+  @retval EFI_SUCCESS        The driver was unloaded successfully

+**/

+EFI_STATUS

+EFIAPI

+FtdiUsbSerialUnload (

+  IN EFI_HANDLE  ImageHandle

+  )

+{

+  EFI_STATUS  Status;

+  EFI_HANDLE  *HandleBuffer;

+  UINTN       HandleCount;

+  UINTN       Index;

+

+  //

+  // Retrieve all handles in the handle database

+  //

+  Status = gBS->LocateHandleBuffer (

+                  AllHandles,

+                  NULL,

+                  NULL,

+                  &HandleCount,

+                  &HandleBuffer

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Disconnect the driver from the handles in the handle database

+  //

+  for (Index = 0; Index < HandleCount; Index++) {

+    Status = gBS->DisconnectController (

+                    HandleBuffer[Index],

+                    gImageHandle,

+                    NULL

+                    );

+  }

+

+  //

+  // Free the handle array

+  //

+  FreePool (HandleBuffer);

+

+  //

+  // Uninstall protocols installed by the driver in its entrypoint

+  //

+  Status = gBS->UninstallMultipleProtocolInterfaces (

+                  ImageHandle,

+                  &gEfiDriverBindingProtocolGuid,

+                  &gUsbSerialDriverBinding,

+                  &gEfiComponentNameProtocolGuid,

+                  &gUsbSerialComponentName,

+                  &gEfiComponentName2ProtocolGuid,

+                  &gUsbSerialComponentName2,

+                  NULL

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Check whether USB Serial driver supports this device.

+

+  @param  This[in]                   The USB Serial driver binding protocol.

+  @param  Controller[in]             The controller handle to check.

+  @param  RemainingDevicePath[in]    The remaining device path.

+

+  @retval EFI_SUCCESS                The driver supports this controller.

+  @retval other                      This device isn't supported.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  )

+{

+  EFI_STATUS           Status;

+  EFI_USB_IO_PROTOCOL  *UsbIo;

+  UART_DEVICE_PATH     *UartNode;

+  UART_FLOW_CONTROL_DEVICE_PATH        *FlowControlNode;

+  UINTN                                Index;

+  UINTN                                EntryCount;

+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;

+  BOOLEAN                              HasFlowControl;

+  EFI_DEVICE_PATH_PROTOCOL             *DevicePath;

+  EFI_DEVICE_PATH_PROTOCOL             *ParentDevicePath;

+

+  if (RemainingDevicePath != NULL) {

+    if (!IsDevicePathEnd (RemainingDevicePath)) {

+      Status = EFI_UNSUPPORTED;

+      UartNode = (UART_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);

+      if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||

+          UartNode->Header.SubType != MSG_UART_DP ||

+          sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH *) UartNode)) {

+        goto Error;

+      }

+      FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);

+      if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {

+        goto Error;

+      }

+    }

+  }

+

+  //

+  // Check if USB I/O Protocol is attached on the controller handle.

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &UsbIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (Status == EFI_ALREADY_STARTED) {

+    if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {

+      return EFI_SUCCESS;

+    }

+    Status = gBS->OpenProtocolInformation (

+                    Controller,

+                    &gEfiUsbIoProtocolGuid,

+                    &OpenInfoBuffer,

+                    &EntryCount

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    for (Index = 0; Index < EntryCount; Index++) {

+      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {

+        Status = gBS->OpenProtocol (

+                        OpenInfoBuffer[Index].ControllerHandle,

+                        &gEfiDevicePathProtocolGuid,

+                        (VOID **) &DevicePath,

+                        This->DriverBindingHandle,

+                        Controller,

+                        EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                        );

+        if (!EFI_ERROR (Status)) {

+          HasFlowControl = ContainsFlowControl (RemainingDevicePath);

+          if (HasFlowControl ^ ContainsFlowControl (DevicePath)) {

+            Status = EFI_UNSUPPORTED;

+          }

+        }

+        break;

+      }

+    }

+    FreePool (OpenInfoBuffer);

+    return Status;

+  }

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiUsbIoProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiDevicePathProtocolGuid,

+                  (VOID **) &ParentDevicePath,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (Status == EFI_ALREADY_STARTED) {

+    return EFI_SUCCESS;

+  }

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Use the USB I/O Protocol interface to check whether Controller is

+  // a USB Serial device that can be managed by this driver.

+  //

+  Status = EFI_SUCCESS;

+

+  if (!IsUsbSerial (UsbIo)) {

+    Status = EFI_UNSUPPORTED;

+    goto Error;

+  }

+

+Error:

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiDevicePathProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+  return Status;

+}

+

+/**

+  Starts the USB Serial device with this driver.

+

+  This function produces initializes the USB Serial device and

+  produces the Serial IO Protocol.

+

+  @param  This[in]                   The USB Serial driver binding instance.

+  @param  Controller[in]             Handle of device to bind driver to.

+  @param  RemainingDevicePath[in]    Optional parameter use to pick a specific

+                                     child device to start.

+

+  @retval EFI_SUCCESS                The controller is controlled by the usb USB

+                                     Serial driver.

+  @retval EFI_UNSUPPORTED            No interrupt endpoint can be found.

+  @retval Other                      This controller cannot be started.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  )

+{

+  EFI_STATUS                          Status;

+  EFI_USB_IO_PROTOCOL                 *UsbIo;

+  USB_SER_DEV                         *UsbSerialDevice;

+  UINT8                               EndpointNumber;

+  EFI_USB_ENDPOINT_DESCRIPTOR         EndpointDescriptor;

+  UINT8                               Index;

+  BOOLEAN                             FoundIn;

+  BOOLEAN                             FoundOut;

+  EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;

+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;

+  UINTN                               EntryCount;

+  EFI_SERIAL_IO_PROTOCOL              *SerialIo;

+  UART_DEVICE_PATH                    *Uart;

+  UART_FLOW_CONTROL_DEVICE_PATH       *FlowControl;

+  UINT32                              FlowControlMap;

+  UINT32                              Control;

+  EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;

+

+  UsbSerialDevice = AllocateZeroPool (sizeof (USB_SER_DEV));

+  ASSERT (UsbSerialDevice != NULL);

+

+  //

+  // Get the Parent Device path

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiDevicePathProtocolGuid,

+                  (VOID **) &ParentDevicePath,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {

+    goto ErrorExit1;

+  }

+

+  //

+  // Open USB I/O Protocol

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &UsbIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {

+    goto ErrorExit1;

+  }

+

+  if (Status == EFI_ALREADY_STARTED) {

+    if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {

+      FreePool (UsbSerialDevice);

+      return EFI_SUCCESS;

+    }

+

+    //

+    // Check to see if a child handle exists

+    //

+    Status = gBS->OpenProtocolInformation (

+                    Controller,

+                    &gEfiSerialIoProtocolGuid,

+                    &OpenInfoBuffer,

+                    &EntryCount

+                    );

+    if (EFI_ERROR (Status)) {

+      goto ErrorExit1;

+    }

+

+    Status = EFI_ALREADY_STARTED;

+    for (Index = 0; Index < EntryCount; Index++) {

+      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {

+        Status = gBS->OpenProtocol (

+                        OpenInfoBuffer[Index].ControllerHandle,

+                        &gEfiSerialIoProtocolGuid,

+                        (VOID **) &SerialIo,

+                        This->DriverBindingHandle,

+                        Controller,

+                        EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                        );

+        if (EFI_ERROR (Status)) {

+        }

+        if (!EFI_ERROR (Status)) {

+          Uart = (UART_DEVICE_PATH *) RemainingDevicePath;

+          Status = SerialIo->SetAttributes (

+                               SerialIo,

+                               Uart->BaudRate,

+                               SerialIo->Mode->ReceiveFifoDepth,

+                               SerialIo->Mode->Timeout,

+                               (EFI_PARITY_TYPE) Uart->Parity,

+                               Uart->DataBits,

+                               (EFI_STOP_BITS_TYPE) Uart->StopBits

+                               );

+          FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);

+          if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {

+            Status = SerialIo->GetControl (

+                                 SerialIo,

+                                 &Control

+                                 );

+            if (!EFI_ERROR (Status)) {

+              if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {

+                Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;

+              } else {

+                Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;

+              }

+              //

+              // Clear bits that are not allowed to be passed to SetControl

+              //

+              Control &= (EFI_SERIAL_REQUEST_TO_SEND | 

+                          EFI_SERIAL_DATA_TERMINAL_READY |

+                          EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE |

+                          EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |

+                          EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);

+              Status = SerialIo->SetControl (SerialIo, Control);

+            }

+          }

+        }

+        break;

+      }

+    }

+    FreePool (OpenInfoBuffer);

+    return Status;

+  }

+

+  if (RemainingDevicePath != NULL) {

+    if (IsDevicePathEnd (RemainingDevicePath)) {

+      return EFI_SUCCESS;

+    }

+  }

+

+  UsbSerialDevice->UsbIo = UsbIo;

+

+  //

+  // Get interface & endpoint descriptor

+  //

+  UsbIo->UsbGetInterfaceDescriptor (

+           UsbIo,

+           &UsbSerialDevice->InterfaceDescriptor

+           );

+

+  EndpointNumber = UsbSerialDevice->InterfaceDescriptor.NumEndpoints;

+

+  //

+  // Traverse endpoints to find the IN and OUT endpoints that will send and

+  // receive data.

+  //

+  FoundIn = FALSE;

+  FoundOut = FALSE;

+  for (Index = 0; Index < EndpointNumber; Index++) {

+

+    Status = UsbIo->UsbGetEndpointDescriptor (

+                      UsbIo,

+                      Index,

+                      &EndpointDescriptor

+                      );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    if (EndpointDescriptor.EndpointAddress == FTDI_ENDPOINT_ADDRESS_OUT) {

+      //

+      // Set the Out endpoint device

+      //

+      CopyMem (

+        &UsbSerialDevice->OutEndpointDescriptor,

+        &EndpointDescriptor,

+        sizeof(EndpointDescriptor)

+        );

+      FoundOut = TRUE;

+    }

+

+    if (EndpointDescriptor.EndpointAddress == FTDI_ENDPOINT_ADDRESS_IN) {

+      //

+      // Set the In endpoint device

+      //

+      CopyMem (

+        &UsbSerialDevice->InEndpointDescriptor,

+        &EndpointDescriptor,

+        sizeof(EndpointDescriptor)

+        );

+      FoundIn = TRUE;

+    }

+  }

+

+  if (!FoundIn || !FoundOut) {

+    //

+    // No interrupt endpoint found, then return unsupported.

+    //

+    Status = EFI_UNSUPPORTED;

+    goto ErrorExit;

+  }

+  //

+  // set the initial values of UsbSerialDevice->LastSettings to the default

+  // values

+  //

+  UsbSerialDevice->LastSettings.BaudRate         = 115200;

+  UsbSerialDevice->LastSettings.DataBits         = 8;

+  UsbSerialDevice->LastSettings.Parity           = NoParity;

+  UsbSerialDevice->LastSettings.ReceiveFifoDepth = FTDI_MAX_RECEIVE_FIFO_DEPTH;

+  UsbSerialDevice->LastSettings.StopBits         = OneStopBit;

+  UsbSerialDevice->LastSettings.Timeout          = FTDI_TIMEOUT;

+

+  //

+  // set the initial values of UsbSerialDevice->ControlValues

+  //

+  UsbSerialDevice->ControlValues.DtrState            = FALSE;

+  UsbSerialDevice->ControlValues.RtsState            = FALSE;

+  UsbSerialDevice->ControlValues.HardwareFlowControl = FALSE;

+  UsbSerialDevice->ControlValues.HardwareLoopBack    = FALSE;

+  UsbSerialDevice->ControlValues.SoftwareLoopBack    = FALSE;

+

+  //

+  // set the values of UsbSerialDevice->UartDevicePath

+  //

+  UsbSerialDevice->UartDevicePath.Header.Type    = MESSAGING_DEVICE_PATH;

+  UsbSerialDevice->UartDevicePath.Header.SubType = MSG_UART_DP;

+  UsbSerialDevice->UartDevicePath.Header.Length[0] = (UINT8) (sizeof (UART_DEVICE_PATH));

+  UsbSerialDevice->UartDevicePath.Header.Length[1] = (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8);

+

+  //

+  // set the values of UsbSerialDevice->FlowControlDevicePath

+  UsbSerialDevice->FlowControlDevicePath.Header.Type = MESSAGING_DEVICE_PATH;

+  UsbSerialDevice->FlowControlDevicePath.Header.SubType = MSG_VENDOR_DP;

+  UsbSerialDevice->FlowControlDevicePath.Header.Length[0] = (UINT8) (sizeof (UART_FLOW_CONTROL_DEVICE_PATH));

+  UsbSerialDevice->FlowControlDevicePath.Header.Length[1] = (UINT8) ((sizeof (UART_FLOW_CONTROL_DEVICE_PATH)) >> 8);

+  UsbSerialDevice->FlowControlDevicePath.FlowControlMap = 0;

+

+  Status = SetAttributesInternal (

+             UsbSerialDevice, 

+             UsbSerialDevice->LastSettings.BaudRate,

+             UsbSerialDevice->LastSettings.ReceiveFifoDepth, 

+             UsbSerialDevice->LastSettings.Timeout,

+             UsbSerialDevice->LastSettings.Parity, 

+             UsbSerialDevice->LastSettings.DataBits,

+             UsbSerialDevice->LastSettings.StopBits

+             );

+

+  ASSERT_EFI_ERROR (Status);

+

+  Status = SetControlBitsInternal (

+             UsbSerialDevice,

+             &(UsbSerialDevice->ControlValues)

+             );

+

+  ASSERT_EFI_ERROR (Status);

+

+  //

+  // Publish Serial GUID and protocol

+  //

+

+  UsbSerialDevice->Signature              = USB_SER_DEV_SIGNATURE;

+  UsbSerialDevice->SerialIo.Reset         = SerialReset;

+  UsbSerialDevice->SerialIo.SetControl    = SetControlBits;

+  UsbSerialDevice->SerialIo.SetAttributes = SetAttributes;

+  UsbSerialDevice->SerialIo.GetControl    = GetControlBits;

+  UsbSerialDevice->SerialIo.Read          = ReadSerialIo;

+  UsbSerialDevice->SerialIo.Write         = WriteSerialIo;

+

+  //

+  // Set the static Serial IO modes that will display when running

+  // "sermode" within the UEFI shell.

+  //

+

+  UsbSerialDevice->SerialIo.Mode->Timeout  = 0;

+  UsbSerialDevice->SerialIo.Mode->BaudRate = 115200;

+  UsbSerialDevice->SerialIo.Mode->DataBits = 8;

+  UsbSerialDevice->SerialIo.Mode->Parity   = 1;

+  UsbSerialDevice->SerialIo.Mode->StopBits = 1;

+

+  UsbSerialDevice->ParentDevicePath = ParentDevicePath;

+  UsbSerialDevice->ControllerHandle = NULL;

+  FlowControl                       = NULL;

+  FlowControlMap                    = 0;

+

+  //

+  // Allocate space for the receive buffer

+  //

+  UsbSerialDevice->DataBuffer = AllocateZeroPool (SW_FIFO_DEPTH);

+

+  //

+  // Initialize data buffer pointers.

+  // Head==Tail = true means buffer is empty.

+  //

+  UsbSerialDevice->DataBufferHead = 0;

+  UsbSerialDevice->DataBufferTail = 0;

+

+  UsbSerialDevice->ControllerNameTable = NULL;

+  AddUnicodeString2 (

+    "eng",

+    gUsbSerialComponentName.SupportedLanguages,

+    &UsbSerialDevice->ControllerNameTable,

+    L"FTDI USB Serial Adapter",

+    TRUE

+    );

+  AddUnicodeString2 (

+    "en",

+    gUsbSerialComponentName2.SupportedLanguages,

+    &UsbSerialDevice->ControllerNameTable,

+    L"FTDI USB Serial Adapter",

+    FALSE

+    );

+

+  Status = SetInitialStatus (UsbSerialDevice);

+  ASSERT_EFI_ERROR (Status);

+

+  //

+  // Create a polling loop to check for input

+  //

+

+  gBS->CreateEvent (

+         EVT_TIMER | EVT_NOTIFY_SIGNAL,

+         TPL_CALLBACK,

+         UsbSerialDriverCheckInput,

+         UsbSerialDevice,

+         &(UsbSerialDevice->PollingLoop)

+         );

+  //

+  // add code to set trigger time based on baud rate

+  // setting to 0.5s for now

+  //

+  gBS->SetTimer (

+         UsbSerialDevice->PollingLoop,

+         TimerPeriodic,

+         EFI_TIMER_PERIOD_MILLISECONDS (500)

+         );

+

+  //

+  // Check if the remaining device path is null. If it is not null change the settings

+  // of the device to match those on the device path

+  //

+  if (RemainingDevicePath != NULL) {

+    CopyMem (

+      &UsbSerialDevice->UartDevicePath,

+      RemainingDevicePath,

+      sizeof (UART_DEVICE_PATH)

+      );

+    FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);

+    if (IsUartFlowControlNode (FlowControl)) {

+      UsbSerialDevice->FlowControlDevicePath.FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);

+    } else {

+      FlowControl = NULL;

+    }

+  }

+

+  //

+  // Build the device path by appending the UART node to the parent device path

+  //

+  UsbSerialDevice->DevicePath = AppendDevicePathNode (

+                                  ParentDevicePath,

+                                  (EFI_DEVICE_PATH_PROTOCOL *) &UsbSerialDevice->UartDevicePath

+                                  );

+  //

+  // Continue building the device path by appending the flow control node

+  //

+  TempDevicePath = UsbSerialDevice->DevicePath;

+  UsbSerialDevice->DevicePath = AppendDevicePathNode (

+                                  TempDevicePath,

+                                  (EFI_DEVICE_PATH_PROTOCOL *) &UsbSerialDevice->FlowControlDevicePath

+                                  );

+  FreePool (TempDevicePath);

+

+  if (UsbSerialDevice->DevicePath == NULL) {

+    Status = EFI_OUT_OF_RESOURCES;

+    goto ErrorExit;

+  }

+

+  //

+  // Install protocol interfaces for the device

+  //

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                  &UsbSerialDevice->ControllerHandle,

+                  &gEfiDevicePathProtocolGuid,

+                  UsbSerialDevice->DevicePath,

+                  &gEfiSerialIoProtocolGuid,

+                  &UsbSerialDevice->SerialIo,

+                  NULL

+                  );

+  if (EFI_ERROR (Status)){

+    goto ErrorExit;

+  }

+

+  //

+  // Open for child device

+  //

+  Status = gBS->OpenProtocol (

+                 Controller,

+                 &gEfiUsbIoProtocolGuid,

+                 (VOID **) &UsbIo,

+                 This->DriverBindingHandle,

+                 UsbSerialDevice->ControllerHandle,

+                 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER

+                 );

+

+  UsbSerialDevice->Shutdown = FALSE;

+

+  return EFI_SUCCESS;

+

+ErrorExit:

+  //

+  // Error handler

+  //

+

+  Status = gBS->UninstallMultipleProtocolInterfaces (

+                  Controller,

+                  &gEfiSerialIoProtocolGuid,

+                  &UsbSerialDevice->SerialIo,

+                  NULL

+                  );

+  if (EFI_ERROR (Status)) {

+    goto ErrorExit1;

+  }

+

+  FreePool (UsbSerialDevice->DataBuffer);

+  FreePool (UsbSerialDevice);

+

+  UsbSerialDevice = NULL;

+  gBS->CloseProtocol (

+         Controller,

+         &gEfiUsbIoProtocolGuid,

+         This->DriverBindingHandle,

+         Controller

+         );

+

+ErrorExit1:

+  return Status;

+}

+

+/**

+  Stop the USB Serial device handled by this driver.

+

+  @param  This[in]                   The USB Serial driver binding protocol.

+  @param  Controller[in]             The controller to release.

+  @param  NumberOfChildren[in]       The number of handles in ChildHandleBuffer.

+  @param  ChildHandleBuffer[in]      The array of child handle.

+

+  @retval EFI_SUCCESS                The device was stopped.

+  @retval EFI_UNSUPPORTED            Serial IO Protocol is not installed on

+                                     Controller.

+  @retval EFI_DEVICE_ERROR           The device could not be stopped due to a

+                                     device error.

+  @retval Others                     Fail to uninstall protocols attached on the

+                                     device.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN  EFI_HANDLE                   Controller,

+  IN  UINTN                        NumberOfChildren,

+  IN  EFI_HANDLE                   *ChildHandleBuffer

+  )

+{

+  EFI_STATUS                Status;

+  EFI_SERIAL_IO_PROTOCOL    *SerialIo;

+  EFI_USB_IO_PROTOCOL       *UsbIo;

+  USB_SER_DEV               *UsbSerialDevice;

+  UINTN                     Index;

+  BOOLEAN                   AllChildrenStopped;

+

+  Status = EFI_SUCCESS;

+  UsbSerialDevice = NULL;

+

+  if (NumberOfChildren == 0) {

+    //

+    // Close the driver

+    //

+    Status = gBS->CloseProtocol (

+                    Controller,

+                    &gEfiUsbIoProtocolGuid,

+                    This->DriverBindingHandle,

+                    Controller

+                    );

+    Status = gBS->CloseProtocol (

+                    Controller,

+                    &gEfiDevicePathProtocolGuid,

+                    This->DriverBindingHandle,

+                    Controller

+                    );

+    return Status;

+  }

+

+  AllChildrenStopped = TRUE;

+

+  for (Index = 0; Index < NumberOfChildren ;Index++) {

+    Status = gBS->OpenProtocol (

+                    ChildHandleBuffer[Index],

+                    &gEfiSerialIoProtocolGuid,

+                    (VOID **) &SerialIo,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (Status == EFI_SUCCESS) {//!EFI_ERROR (Status)) {

+      UsbSerialDevice = USB_SER_DEV_FROM_THIS (SerialIo);

+      Status = gBS->CloseProtocol (

+                      Controller,

+                      &gEfiUsbIoProtocolGuid,

+                      This->DriverBindingHandle,

+                      ChildHandleBuffer[Index]

+                      );

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      ChildHandleBuffer[Index],

+                      &gEfiDevicePathProtocolGuid,

+                      UsbSerialDevice->DevicePath,

+                      &gEfiSerialIoProtocolGuid,

+                      &UsbSerialDevice->SerialIo,

+                      NULL

+                      );

+

+      if (EFI_ERROR (Status)) {

+        gBS->OpenProtocol (

+               Controller,

+               &gEfiUsbIoProtocolGuid,

+               (VOID **) &UsbIo,

+               This->DriverBindingHandle,

+               ChildHandleBuffer[Index],

+               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER

+               );

+      } else {

+        if (UsbSerialDevice->DevicePath != NULL) {

+          gBS->FreePool (UsbSerialDevice->DevicePath);

+        }

+        gBS->SetTimer (

+               UsbSerialDevice->PollingLoop,

+               TimerCancel,

+               0

+               );

+        gBS->CloseEvent (UsbSerialDevice->PollingLoop);

+        UsbSerialDevice->Shutdown = TRUE;

+        FreeUnicodeStringTable (UsbSerialDevice->ControllerNameTable);

+        FreePool (UsbSerialDevice->DataBuffer);

+        FreePool (UsbSerialDevice);

+      }

+    }

+    if (EFI_ERROR (Status)) {

+      AllChildrenStopped = FALSE;

+    }

+  }

+

+  if (!AllChildrenStopped) {

+    return EFI_DEVICE_ERROR;

+  }

+  return EFI_SUCCESS;

+}

+

+//

+// Serial IO Member Functions

+//

+

+/**

+  Reset the serial device.

+

+  @param  This[in]              Protocol instance pointer.

+

+  @retval EFI_SUCCESS           The device was reset.

+  @retval EFI_DEVICE_ERROR      The serial device could not be reset.

+

+**/

+EFI_STATUS

+EFIAPI

+SerialReset (

+  IN EFI_SERIAL_IO_PROTOCOL  *This

+  )

+{

+  EFI_STATUS    Status;

+  USB_SER_DEV  *UsbSerialDevice;

+

+  UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);

+  Status          = ResetInternal (UsbSerialDevice);

+  if (EFI_ERROR (Status)){

+    return EFI_DEVICE_ERROR;

+  }

+  return Status;

+}

+

+/**

+  Set the control bits on a serial device.

+

+  @param  This[in]             Protocol instance pointer.

+  @param  Control[in]          Set the bits of Control that are settable.

+

+  @retval EFI_SUCCESS          The new control bits were set on the serial device.

+  @retval EFI_UNSUPPORTED      The serial device does not support this operation.

+  @retval EFI_DEVICE_ERROR     The serial device is not functioning correctly.

+

+**/

+EFI_STATUS

+EFIAPI

+SetControlBits (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN UINT32                  Control

+  )

+{

+  EFI_STATUS    Status;

+  USB_SER_DEV   *UsbSerialDevice;

+  CONTROL_BITS  ControlBits;

+  

+  UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);

+  

+  //

+  // check for invalid control parameters 

+  //

+  if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND          |

+                    EFI_SERIAL_DATA_TERMINAL_READY      |

+                    EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE |

+                    EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |

+                    EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0 ) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // check the control parameters and set the correct setting for

+  // the paramerts of ControlBits

+  // both loopback enables are always set to FALSE

+  //

+  ControlBits.HardwareLoopBack = FALSE;

+  ControlBits.SoftwareLoopBack = FALSE;

+  //

+  // check for hardware flow control

+  //

+  if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {

+    ControlBits.HardwareFlowControl = TRUE;

+  } else {

+    ControlBits.HardwareFlowControl = FALSE;

+  }

+  //

+  // check for DTR enabled

+  //

+  if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {

+    ControlBits.DtrState = TRUE;

+  } else {

+    ControlBits.DtrState = FALSE;

+  }

+  //

+  // check for RTS enabled

+  //

+  if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {

+    ControlBits.RtsState = TRUE;

+  } else {

+    ControlBits.RtsState = FALSE;

+  }

+

+  //

+  // set the control values with a call to SetControlBitsInternal()

+  //

+  Status = SetControlBitsInternal (UsbSerialDevice, &ControlBits);

+

+  return Status;

+}

+

+/**

+  calls SetAttributesInternal() to set the baud rate, receive FIFO depth,

+  transmit/receive time out, parity, data buts, and stop bits on a serial

+  device.

+

+  @param  This[in]             Protocol instance pointer.

+  @param  BaudRate[in]         The requested baud rate. A BaudRate value of 0

+                               will use the device's default interface speed.

+  @param  ReveiveFifoDepth[in] The requested depth of the FIFO on the receive

+                               side of the serial interface. A ReceiveFifoDepth

+                               value of 0 will use the device's default FIFO

+                               depth.

+  @param  Timeout[in]          The requested time out for a single character in

+                               microseconds.This timeout applies to both the

+                               transmit and receive side of the interface. A

+                               Timeout value of 0 will use the device's default

+                               time out value.

+  @param  Parity[in]           The type of parity to use on this serial device.

+                               A Parity value of DefaultParity will use the

+                               device's default parity value.

+  @param  DataBits[in]         The number of data bits to use on the serial

+                               device. A DataBit vaule of 0 will use the

+                               device's default data bit setting.

+  @param  StopBits[in]         The number of stop bits to use on this serial

+                               device. A StopBits value of DefaultStopBits will

+                               use the device's default number of stop bits.

+

+  @retval EFI_SUCCESS          The attributes were set

+  @retval EFI_DEVICE_ERROR     The attributes were not able to be

+

+**/

+EFI_STATUS

+EFIAPI

+SetAttributes (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN UINT64                  BaudRate,

+  IN UINT32                  ReceiveFifoDepth,

+  IN UINT32                  Timeout,

+  IN EFI_PARITY_TYPE         Parity,

+  IN UINT8                   DataBits,

+  IN EFI_STOP_BITS_TYPE      StopBits

+  )

+{

+

+  EFI_STATUS   Status;

+  USB_SER_DEV  *UsbSerialDevice;

+

+  UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);

+

+  Status = SetAttributesInternal (

+             UsbSerialDevice,

+             BaudRate,

+             ReceiveFifoDepth,

+             Timeout,

+             Parity,

+             DataBits,

+             StopBits

+             );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  return Status;

+}

+

+

+/**

+  Retrieves the status of the control bits on a serial device.

+

+  @param  This[in]               Protocol instance pointer.

+  @param  Control[out]           A pointer to return the current Control signals

+                                 from the serial device.

+

+  @retval EFI_SUCCESS            The control bits were read from the serial

+                                 device.

+  @retval EFI_DEVICE_ERROR       The serial device is not functioning correctly.

+

+**/

+EFI_STATUS

+EFIAPI

+GetControlBits (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  OUT UINT32                 *Control

+  )

+{

+  USB_SER_DEV  *UsbSerialDevice;

+  EFI_STATUS   Status;

+

+  UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);

+

+  *Control        = 0;

+

+  Status = GetControlBitsInternal (UsbSerialDevice, Control);

+

+  if (EFI_ERROR (Status)) {

+    return EFI_DEVICE_ERROR;

+  }

+  return Status;

+}

+

+/**

+  Reads data from a serial device.

+

+  @param  This[in]                   Protocol instance pointer.

+  @param  BufferSize[in, out]        On input, the size of the Buffer. On output,

+                                     the amount of data returned in Buffer.

+  @param  Buffer[out]                The buffer to return the data into.

+

+  @retval EFI_SUCCESS                The data was read.

+  @retval EFI_DEVICE_ERROR           The device reported an error.

+  @retval EFI_TIMEOUT                The data write was stopped due to a timeout.

+

+**/

+EFI_STATUS

+EFIAPI

+ReadSerialIo (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN OUT UINTN               *BufferSize,

+  OUT VOID                   *Buffer

+  )

+{

+  UINTN        Index;

+  UINTN        RemainingCallerBufferSize;

+  USB_SER_DEV  *UsbSerialDevice;

+  EFI_STATUS   Status;

+

+

+  if (*BufferSize == 0) {

+    return EFI_SUCCESS;

+  }

+

+  if (Buffer == NULL) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  Status          = EFI_SUCCESS;

+  UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);

+

+  //

+  // Clear out any data that we already have in our internal buffer

+  //

+  for (Index = 0; Index < *BufferSize; Index++) {

+    if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {

+      break;

+    }

+

+    //

+    // Still have characters in the buffer to return

+    //

+    ((UINT8 *)Buffer)[Index] = UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferHead];

+    UsbSerialDevice->DataBufferHead = (UsbSerialDevice->DataBufferHead + 1) % SW_FIFO_DEPTH;

+  }

+

+  //

+  // If we haven't filled the caller's buffer using data that we already had on

+  // hand We need to generate an additional USB request to try and fill the

+  // caller's buffer

+  //

+  if (Index != *BufferSize) {

+    RemainingCallerBufferSize = *BufferSize - Index;

+    Status = ReadDataFromUsb (

+               UsbSerialDevice,

+               &RemainingCallerBufferSize,

+               (VOID *)(((CHAR8 *)Buffer) + Index)

+               );

+    if (!EFI_ERROR (Status)) {

+      *BufferSize = RemainingCallerBufferSize + Index;

+    } else {

+      *BufferSize = Index;

+    }

+  }

+

+  if (UsbSerialDevice->DataBufferHead == UsbSerialDevice->DataBufferTail) {

+    //

+    // Data buffer has no data, set the EFI_SERIAL_INPUT_BUFFER_EMPTY flag

+    //

+    UsbSerialDevice->ControlBits |= EFI_SERIAL_INPUT_BUFFER_EMPTY;

+  } else {

+    //

+    // There is some leftover data, clear EFI_SERIAL_INPUT_BUFFER_EMPTY flag

+    //

+    UsbSerialDevice->ControlBits &= ~(EFI_SERIAL_INPUT_BUFFER_EMPTY);

+  }

+  return Status;

+}

+

+/**

+  Writes data to a serial device.

+

+  @param  This[in]                   Protocol instance pointer.

+  @param  BufferSize[in, out]        On input, the size of the Buffer. On output,

+                                     the amount of data actually written.

+  @param  Buffer[in]                 The buffer of data to write

+

+  @retval EFI_SUCCESS                The data was written.

+  @retval EFI_DEVICE_ERROR           The device reported an error.

+  @retval EFI_TIMEOUT                The data write was stopped due to a timeout.

+

+**/

+EFI_STATUS

+EFIAPI

+WriteSerialIo (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN OUT UINTN               *BufferSize,

+  IN VOID                    *Buffer

+  )

+{

+  EFI_STATUS   Status;

+  USB_SER_DEV  *UsbSerialDevice;

+  EFI_TPL      Tpl;

+

+  UsbSerialDevice = USB_SER_DEV_FROM_THIS (This);

+

+  if (UsbSerialDevice->Shutdown) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  Tpl = gBS->RaiseTPL (TPL_NOTIFY);

+

+  Status = UsbSerialDataTransfer (

+             UsbSerialDevice,

+             EfiUsbDataOut,

+             Buffer,

+             BufferSize,

+             FTDI_TIMEOUT

+             );

+

+  gBS->RestoreTPL (Tpl);

+  if (EFI_ERROR (Status)) {

+    if (Status == EFI_TIMEOUT){

+      return Status;

+    } else {

+      return EFI_DEVICE_ERROR;

+    }

+  }

+

+  return EFI_SUCCESS;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h
new file mode 100644
index 0000000..07f4133
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h
@@ -0,0 +1,595 @@
+/** @file

+  Header file for USB Serial Driver's Data Structures.

+

+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.

+Portions Copyright 2012 Ashley DeSimone

+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.

+

+**/

+

+#ifndef _FTDI_USB_SERIAL_DRIVER_H_

+#define _FTDI_USB_SERIAL_DRIVER_H_

+

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiLib.h>

+#include <Library/DevicePathLib.h>

+

+#include <Protocol/DevicePath.h>

+#include <Protocol/UsbIo.h>

+#include <Protocol/SerialIo.h>

+

+//

+// US English LangID

+//

+#define USB_US_LANG_ID  0x0409

+

+//

+// Supported Vendor Ids

+//

+#define VID_FTDI    0x0403

+

+//

+// Supported product ids

+//

+#define DID_FTDI_FT232    0x6001

+

+//

+// FTDI Commands

+//

+#define FTDI_COMMAND_RESET_PORT          0

+#define FTDI_COMMAND_MODEM_CTRL          1

+#define FTDI_COMMAND_SET_FLOW_CTRL       2

+#define FTDI_COMMAND_SET_BAUDRATE        3

+#define FTDI_COMMAND_SET_DATA            4

+#define FTDI_COMMAND_GET_MODEM_STATUS    5

+#define FTDI_COMMAND_SET_EVENT_CHAR      6

+#define FTDI_COMMAND_SET_ERROR_CHAR      7

+#define FTDI_COMMAND_SET_LATENCY_TIMER   9

+#define FTDI_COMMAND_GET_LATENCY_TIMER   10

+

+//

+// FTDI_PORT_IDENTIFIER

+// Used in the usb control transfers that issue FTDI commands as the index value.

+//

+#define FTDI_PORT_IDENTIFIER    0x1 // For FTDI USB serial adapter the port

+                                    // identifier is always 1.

+

+//

+// RESET_PORT

+//

+#define RESET_PORT_RESET        0x0 // Purges RX and TX, clears DTR and RTS sets

+                                    // flow control to none, disables event

+                                    // trigger, sets the event char to 0x0d and

+                                    // does nothing to baudrate or data settings

+#define RESET_PORT_PURGE_RX     0x1

+#define RESET_PORT_PURGE_TX     0x2

+

+//

+// SET_FLOW_CONTROL

+//

+#define NO_FLOW_CTRL                     0x0

+#define XON_XOFF_CTRL                    0x4

+

+//

+// SET_BAUD_RATE

+// To set baud rate, one must calculate an encoding of the baud rate from

+// UINT32 to UINT16.See EncodeBaudRateForFtdi() for details

+//

+#define FTDI_UART_FREQUENCY              3000000

+#define FTDI_MIN_DIVISOR                 0x20

+#define FTDI_MAX_DIVISOR                 0x3FFF8

+//

+// Special case baudrate values

+// 300,000 and 200,000 are special cases for calculating the encoded baudrate

+//

+#define FTDI_SPECIAL_CASE_300_MIN        (3000000 * 100) / 103 // minimum adjusted

+                                                               // value for 300,000

+#define FTDI_SPECIAL_CASE_300_MAX        (3000000 * 100) / 97  // maximum adjusted

+                                                               // value for 300,000

+#define FTDI_SPECIAL_CASE_200_MIN        (2000000 * 100) / 103 // minimum adjusted

+                                                               // value for 200,000

+#define FTDI_SPECIAL_CASE_200_MAX        (2000000 * 100) / 97  // maximum adjusted

+                                                               // value for 200,000

+//

+// Min and max frequency values that the FTDI chip can attain

+//.all generated frequencies must be between these values

+//

+#define FTDI_MIN_FREQUENCY              46601941 // (3MHz * 1600) / 103 = 46601941

+#define FTDI_MAX_FREQUENCY              49484536 // (3MHz * 1600) / 97 = 49484536

+

+//

+// SET_DATA_BITS

+//

+#define SET_DATA_BITS(n)                 (n)

+

+//

+// SET_PARITY

+//

+#define SET_PARITY_NONE                   0x0

+#define SET_PARITY_ODD                    BIT8 // (0x1 << 8)

+#define SET_PARITY_EVEN                   BIT9 // (0x2 << 8)

+#define SET_PARITY_MARK                   BIT9 | BIT8 // (0x3 << 8)

+#define SET_PARITY_SPACE                  BIT10 // (0x4 << 8)

+

+//

+// SET_STOP_BITS

+//

+#define SET_STOP_BITS_1                   0x0

+#define SET_STOP_BITS_15                  BIT11 // (0x1 << 11)

+#define SET_STOP_BITS_2                   BIT12 // (0x2 << 11)

+

+//

+// SET_MODEM_CTRL

+// SET_DTR_HIGH = (1 | (1 << 8)), SET_DTR_LOW = (0 | (1 << 8)

+// SET_RTS_HIGH = (2 | (2 << 8)), SET_RTS_LOW = (0 | (2 << 8)

+//

+#define SET_DTR_HIGH                     (BIT8 | BIT0)

+#define SET_DTR_LOW                      (BIT8)

+#define SET_RTS_HIGH                     (BIT9 | BIT1)

+#define SET_RTS_LOW                      (BIT9)

+

+//

+// MODEM_STATUS

+//

+#define CTS_MASK                         BIT4

+#define DSR_MASK                         BIT5

+#define RI_MASK                          BIT6

+#define SD_MASK                          BIT7

+#define MSR_MASK                         (CTS_MASK | DSR_MASK | RI_MASK | SD_MASK)

+

+//

+// Macro used to check for USB transfer errors

+//

+#define USB_IS_ERROR(Result, Error)           (((Result) & (Error)) != 0)

+

+//

+// USB request timeouts

+//

+#define WDR_TIMEOUT        5000  // default urb timeout in ms

+#define WDR_SHORT_TIMEOUT  1000  // shorter urb timeout in ms

+

+//

+// FTDI timeout

+//

+#define FTDI_TIMEOUT       16

+

+//

+// FTDI FIFO depth

+//

+#define FTDI_MAX_RECEIVE_FIFO_DEPTH  384

+

+//

+// FTDI Endpoint Descriptors

+//

+#define FTDI_ENDPOINT_ADDRESS_IN   0x81 //the endpoint address for the in enpoint generated by the device

+#define FTDI_ENDPOINT_ADDRESS_OUT  0x02 //the endpoint address for the out endpoint generated by the device

+

+//

+// Max buffer size for USB transfers

+//

+#define SW_FIFO_DEPTH 1024

+

+//

+// struct to define a usb device as a vendor and product id pair

+//

+typedef struct {

+  UINTN     VendorId;

+  UINTN     DeviceId;

+} USB_DEVICE;

+

+//

+//struct to describe the control bits of the device

+//true indicates enabled

+//false indicates disabled

+// 

+typedef struct {

+  BOOLEAN    HardwareFlowControl;

+  BOOLEAN    DtrState;

+  BOOLEAN    RtsState;

+  BOOLEAN    HardwareLoopBack;

+  BOOLEAN    SoftwareLoopBack;

+} CONTROL_BITS;

+

+//

+//struct to describe the status bits of the device 

+//true indicates enabled

+//false indicated disabled

+//

+typedef struct {

+  BOOLEAN    CtsState;

+  BOOLEAN    DsrState;

+  BOOLEAN    RiState;

+  BOOLEAN    SdState;

+} STATUS_BITS;

+

+//

+// Structure to describe the last attributes of the Usb Serial device

+//

+typedef struct {

+  UINT64              BaudRate;

+  UINT32              ReceiveFifoDepth;

+  UINT32              Timeout;

+  EFI_PARITY_TYPE     Parity;

+  UINT8               DataBits;

+  EFI_STOP_BITS_TYPE  StopBits;

+} PREVIOUS_ATTRIBUTES;

+

+//

+// Structure to describe USB serial device

+//

+#define USB_SER_DEV_SIGNATURE  SIGNATURE_32 ('u', 's', 'b', 's')

+

+typedef struct {

+  UINTN                         Signature;

+  EFI_HANDLE                    ControllerHandle;

+  EFI_DEVICE_PATH_PROTOCOL      *DevicePath;

+  EFI_DEVICE_PATH_PROTOCOL      *ParentDevicePath;

+  UART_DEVICE_PATH              UartDevicePath;

+  UART_FLOW_CONTROL_DEVICE_PATH FlowControlDevicePath;

+  EFI_USB_IO_PROTOCOL           *UsbIo;

+  EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;

+  EFI_USB_ENDPOINT_DESCRIPTOR   InEndpointDescriptor;

+  EFI_USB_ENDPOINT_DESCRIPTOR   OutEndpointDescriptor;

+  EFI_UNICODE_STRING_TABLE      *ControllerNameTable;

+  UINT32                        DataBufferHead;

+  UINT32                        DataBufferTail;

+  UINT8                         *DataBuffer;

+  EFI_SERIAL_IO_PROTOCOL        SerialIo;

+  BOOLEAN                       Shutdown;

+  EFI_EVENT                     PollingLoop;

+  UINT32                        ControlBits;

+  PREVIOUS_ATTRIBUTES           LastSettings;

+  CONTROL_BITS                  ControlValues;

+  STATUS_BITS                   StatusValues;

+  UINT8                         ReadBuffer[512];

+} USB_SER_DEV;

+

+#define USB_SER_DEV_FROM_THIS(a) \

+  CR(a, USB_SER_DEV, SerialIo, USB_SER_DEV_SIGNATURE)

+

+//

+// Global Variables

+//

+extern EFI_DRIVER_BINDING_PROTOCOL   gUsbSerialDriverBinding;

+extern EFI_COMPONENT_NAME_PROTOCOL   gUsbSerialComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL  gUsbSerialComponentName2;

+

+//

+// Functions of Driver Binding Protocol

+//

+/**

+  Check whether USB Serial driver supports this device.

+

+  @param  This[in]                   The USB Serial driver binding protocol.

+  @param  Controller[in]             The controller handle to check.

+  @param  RemainingDevicePath[in]    The remaining device path.

+

+  @retval EFI_SUCCESS                The driver supports this controller.

+  @retval other                      This device isn't supported.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+/**

+  Starts the Serial device with this driver.

+

+  This function produces Serial IO Protocol and initializes the USB

+  Serial device to manage this USB Serial device.

+

+  @param  This[in]                   The USB Serial driver binding instance.

+  @param  Controller[in]             Handle of device to bind driver to.

+  @param  RemainingDevicePath[in]    Optional parameter use to pick a specific

+                                     child device to start.

+

+  @retval EFI_SUCCESS                The controller is controlled by the USB

+                                     Serial driver.

+  @retval EFI_UNSUPPORTED            No interrupt endpoint can be found.

+  @retval Other                      This controller cannot be started.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+/**

+  Stop the USB Serial device handled by this driver.

+

+  @param  This[in]                   The USB Serial driver binding protocol.

+  @param  Controller[in]             The controller to release.

+  @param  NumberOfChildren[in]       The number of handles in ChildHandleBuffer.

+  @param  ChildHandleBuffer[in]      The array of child handle.

+

+  @retval EFI_SUCCESS                The device was stopped.

+  @retval EFI_UNSUPPORTED            Simple Text In Protocol or Simple Text In Ex

+                                     Protocol is not installed on Controller.

+  @retval EFI_DEVICE_ERROR           The device could not be stopped due to a

+                                     device error.

+  @retval Others                     Fail to uninstall protocols attached on the

+                                     device.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN  EFI_HANDLE                   Controller,

+  IN  UINTN                        NumberOfChildren,

+  IN  EFI_HANDLE                   *ChildHandleBuffer

+  );

+

+//

+// Serial IO Member Functions

+//

+

+/**

+  Writes data to a serial device.

+

+  @param  This[in]                   Protocol instance pointer.

+  @param  BufferSize[in, out]        On input, the size of the Buffer. On output,

+                                     the amount of data actually written.

+  @param  Buffer[in]                 The buffer of data to write

+

+  @retval EFI_SUCCESS                The data was written.

+  @retval EFI_DEVICE_ERROR           The device reported an error.

+  @retval EFI_TIMEOUT                The data write was stopped due to a timeout.

+

+**/

+EFI_STATUS

+EFIAPI

+WriteSerialIo (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN OUT UINTN               *BufferSize,

+  IN VOID                    *Buffer

+  );

+

+/**

+  Reads data from a serial device.

+

+  @param  This[in]                   Protocol instance pointer.

+  @param  BufferSize[in, out]        On input, the size of the Buffer. On output,

+                                     the amount of data returned in Buffer.

+  @param  Buffer[out]                The buffer to return the data into.

+

+  @retval EFI_SUCCESS                The data was read.

+  @retval EFI_DEVICE_ERROR           The device reported an error.

+  @retval EFI_TIMEOUT                The data write was stopped due to a timeout.

+

+**/

+EFI_STATUS

+EFIAPI

+ReadSerialIo (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN OUT UINTN               *BufferSize,

+  OUT VOID                   *Buffer

+  );

+

+/**

+  Retrieves the status of the control bits on a serial device.

+

+  @param  This[in]               Protocol instance pointer.

+  @param  Control[out]           A pointer to return the current Control signals

+                                 from the serial device.

+

+  @retval EFI_SUCCESS            The control bits were read from the serial

+                                 device.

+  @retval EFI_DEVICE_ERROR       The serial device is not functioning correctly.

+

+**/

+EFI_STATUS

+EFIAPI

+GetControlBits (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  OUT UINT32                 *Control

+  );

+

+/**

+  Set the control bits on a serial device.

+

+  @param  This[in]             Protocol instance pointer.

+  @param  Control[in]          Set the bits of Control that are settable.

+

+  @retval EFI_SUCCESS          The new control bits were set on the serial device.

+  @retval EFI_UNSUPPORTED      The serial device does not support this operation.

+  @retval EFI_DEVICE_ERROR     The serial device is not functioning correctly.

+

+**/

+EFI_STATUS

+EFIAPI

+SetControlBits (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN UINT32                  Control

+  );

+

+/**

+  Calls SetAttributesInternal() to set the baud rate, receive FIFO depth,

+  transmit/receice time out, parity, data buts, and stop bits on a serial device.

+

+  @param  This[in]             Protocol instance pointer.

+  @param  BaudRate[in]         The requested baud rate. A BaudRate value of 0

+                               will use the device's default interface speed.

+  @param  ReveiveFifoDepth[in] The requested depth of the FIFO on the receive

+                               side of the serial interface. A ReceiveFifoDepth

+                               value of 0 will use the device's default FIFO

+                               depth.

+  @param  Timeout[in]          The requested time out for a single character in

+                               microseconds.This timeout applies to both the

+                               transmit and receive side of the interface.A

+                               Timeout value of 0 will use the device's default

+                               time out value.

+  @param  Parity[in]           The type of parity to use on this serial device.A

+                               Parity value of DefaultParity will use the

+                               device's default parity value.

+  @param  DataBits[in]         The number of data bits to use on the serial

+                               device. A DataBits value of 0 will use the

+                               device's default data bit setting.

+  @param  StopBits[in]         The number of stop bits to use on this serial

+                               device. A StopBits value of DefaultStopBits will

+                               use the device's default number of stop bits.

+

+  @retval EFI_SUCCESS          The attributes were set

+  @retval EFI_DEVICE_ERROR     The attributes were not able to be

+

+**/

+EFI_STATUS

+EFIAPI

+SetAttributes (

+  IN EFI_SERIAL_IO_PROTOCOL  *This,

+  IN UINT64                  BaudRate,

+  IN UINT32                  ReceiveFifoDepth,

+  IN UINT32                  Timeout,

+  IN EFI_PARITY_TYPE         Parity,

+  IN UINT8                   DataBits,

+  IN EFI_STOP_BITS_TYPE      StopBits

+  );

+

+/**

+  Reset the serial device.

+

+  @param  This              Protocol instance pointer.

+

+  @retval EFI_SUCCESS       The device was reset.

+  @retval EFI_DEVICE_ERROR  The serial device could not be reset.

+

+**/

+EFI_STATUS

+EFIAPI

+SerialReset (

+  IN EFI_SERIAL_IO_PROTOCOL  *This

+  );

+

+//

+// EFI Component Name Functions

+//

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]                   A pointer to the EFI_COMPONENT_NAME2_PROTOCOL

+                                     or EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param  Language[in]               A pointer to a Null-terminated ASCII string

+                                     array indicating the language. This is the

+                                     language of the driver name that the caller

+                                     is requesting, and it must match one of the

+                                     languages specified in SupportedLanguages.

+                                     The number of languages supported by a

+                                     driver is up to the driver writer. Language

+                                     is specified in RFC 4646 or ISO 639-2

+                                     language code format.

+  @param  DriverName[out]            A pointer to the Unicode string to return.

+                                     This Unicode string is the name of the

+                                     driver specified by This in the language

+                                     specified by Language.

+

+  @retval EFI_SUCCESS                The Unicode string for the Driver specified

+                                     by This and the language specified by

+                                     Language was returned in DriverName.

+  @retval EFI_INVALID_PARAMETER      Language is NULL.

+  @retval EFI_INVALID_PARAMETER      DriverName is NULL.

+  @retval EFI_UNSUPPORTED            The driver specified by This does not

+                                     support the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,

+  IN  CHAR8                         *Language,

+  OUT CHAR16                        **DriverName

+  );

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]                   A pointer to the EFI_COMPONENT_NAME2_PROTOCOL

+                                     or EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param  ControllerHandle[in]       The handle of a controller that the driver

+                                     specified by This is managing.  This handle

+                                     specifies the controller whose name is to

+                                     be returned.

+  @param  ChildHandle[in]            The handle of the child controller to

+                                     retrieve the name of. This is an optional

+                                     parameter that may be NULL. It will be NULL

+                                     for device drivers. It will also be NULL

+                                     for a bus drivers that wish to retrieve the

+                                     name of the bus controller. It will not be

+                                     NULL for a bus driver that wishes to

+                                     retrieve the name of a child controller.

+  @param  Language[in]               A pointer to a Null-terminated ASCII string

+                                     array indicating the language.  This is the

+                                     language of the driver name that the caller

+                                     is requesting, and it must match one of the

+                                     languages specified in SupportedLanguages.

+                                     The number of languages supported by a

+                                     driver is up to the driver writer. Language

+                                     is specified in RFC 4646 or ISO 639-2

+                                     language code format.

+  @param  ControllerName[out]        A pointer to the Unicode string to return.

+                                     This Unicode string is the name of the

+                                     controller specified by ControllerHandle

+                                     and ChildHandle in the language specified

+                                     by Language from the point of view of the

+                                     driver specified by This.

+

+  @retval EFI_SUCCESS                The Unicode string for the user readable

+                                     name in the language specified by Language

+                                     for the driver specified by This was

+                                     returned in DriverName.

+  @retval EFI_INVALID_PARAMETER      ControllerHandle is not a valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER      ChildHandle is not NULL and it is not a

+                                     valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER      Language is NULL.

+  @retval EFI_INVALID_PARAMETER      ControllerName is NULL.

+  @retval EFI_UNSUPPORTED            The driver specified by This is not

+                                     currently managing the controller specified

+                                     by ControllerHandle and ChildHandle.

+  @retval EFI_UNSUPPORTED            The driver specified by This does not

+                                     support the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UsbSerialComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,

+  IN  EFI_HANDLE                    ControllerHandle,

+  IN  EFI_HANDLE                    ChildHandle      OPTIONAL,

+  IN  CHAR8                         *Language,

+  OUT CHAR16                        **ControllerName

+  );

+

+#endif

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf
new file mode 100644
index 0000000..e0381b1
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf
@@ -0,0 +1,61 @@
+## @file

+#  USB Serial Driver that manages USB Serial device and produces Serial IO

+#  Protocol.

+#

+#  USB Serial Driver consumes USB I/O Protocol and Device Path Protocol, and

+#  produces Serial IO Protocol on USB Serial devices.

+#  It manages the USB Serial device via USB Bulk Transfer of USB I/O Protocol.

+#  This module refers to following specifications:

+#  1. UEFI Specification, v2.1

+#

+# Copyright (c) 2006 - 2013, 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.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = FtdiUsbSerialDxe

+  FILE_GUID                      = A8154B55-2021-4D40-AE81-2E23A02dCC46

+  MODULE_TYPE                    = UEFI_DRIVER

+  VERSION_STRING                 = 1.0

+  ENTRY_POINT                    = FtdiUsbSerialEntryPoint

+  UNLOAD_IMAGE                   = FtdiUsbSerialUnload

+

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+

+[Sources]

+  FtdiUsbSerialDriver.c

+  FtdiUsbSerialDriver.h

+  ComponentName.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+

+[LibraryClasses]

+  UefiDriverEntryPoint

+  BaseMemoryLib

+  DebugLib

+  MemoryAllocationLib

+  UefiBootServicesTableLib

+  UefiLib

+  DevicePathLib

+

+[Guids]

+  gEfiUartDevicePathGuid

+

+[Protocols]

+  ## TO_START

+  ## BY_START

+  gEfiDevicePathProtocolGuid

+  gEfiUsbIoProtocolGuid                         ## TO_START

+  gEfiSerialIoProtocolGuid                      ## BY_START

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt
new file mode 100644
index 0000000..d8ca227
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt
@@ -0,0 +1,32 @@
+

+=== FTDI USB SERIAL OVERVIEW ===

+

+This is a bus driver that enables the EfiSerialIoProtocol interface

+for FTDI8U232AM based USB-to-Serial adapters.

+

+=== STATUS ===

+

+Serial Input: Functional on real hardware.

+Serial Output: Functional on real hardware.

+

+Operating Modes: Currently the user is able to change all operating modes

+except timeout and FIFO depth.

+The default operating mode is:

+	Baudrate:     115200

+	Parity:       None

+	Flow Control: None

+	Data Bits:    8

+	Stop Bits:    1

+Notes: 

+	Data Bits setting of 6,7,8 can not be combined with a Stop Bits setting of 1.5

+

+        At baudrates less than 9600 some of the characters may be transmitted incorrectly.

+

+=== COMPATIBILITY ===

+

+Tested with:

+An FTDI8U232AM based USB-To-Serial adapter, the UEFI Shell, and the SerialTest application 

+using a PuTTY Terminal

+

+See CompatibleDevices.txt for a list of devices which have been confirmed to work with this 

+driver.
\ No newline at end of file
diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c
new file mode 100644
index 0000000..dd18a95
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c
@@ -0,0 +1,1326 @@
+/** @file

+  Implement the interface to the AX88772 Ethernet controller.

+

+  This module implements the interface to the ASIX AX88772

+  USB to Ethernet MAC with integrated 10/100 PHY.  Note that this implementation

+  only supports the integrated PHY since no other test cases were available.

+

+  Copyright (c) 2011, 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.

+

+**/

+

+#include "Ax88772.h"

+

+

+/**

+  Compute the CRC

+

+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.

+

+  @returns The CRC-32 value associated with this MAC address

+

+**/

+UINT32

+Ax88772Crc (

+  IN UINT8 * pMacAddress

+  )

+{

+  UINT32 BitNumber;

+  INT32 Carry;

+  INT32 Crc;

+  UINT32 Data;

+  UINT8 * pEnd;

+

+  DBG_ENTER ( );

+

+  //

+  //  Walk the MAC address

+  //

+  Crc = -1;

+  pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];

+  while ( pEnd > pMacAddress ) {

+    Data = *pMacAddress++;

+    

+    

+    //

+    //  CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1

+    //

+    //          1 0000 0100 1100 0001 0001 1101 1011 0111

+    //

+    for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) {

+      Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 );

+      Crc <<= 1;

+      if ( 0 != Carry ) {

+        Crc ^= 0x04c11db7;

+      }

+      Data >>= 1;

+    }

+  }

+

+  //

+  //  Return the CRC value

+  //

+  DBG_EXIT_HEX ( Crc );

+  return (UINT32) Crc;

+}

+

+

+/**

+  Get the MAC address

+

+  This routine calls ::Ax88772UsbCommand to request the MAC

+  address from the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772MacAddressGet (

+  IN NIC_DEVICE * pNicDevice,

+  OUT UINT8 * pMacAddress

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  //  Set the register address.

+  //

+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                       | USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_MAC_ADDRESS_READ;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;

+

+  //

+  //  Read the PHY register

+  //

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               pMacAddress );

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Set the MAC address

+

+  This routine calls ::Ax88772UsbCommand to set the MAC address

+  in the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772MacAddressSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  //  Set the register address.

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;

+  

+  //

+  //  Read the PHY register

+  //

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               pMacAddress );

+  

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Clear the multicast hash table

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+**/

+VOID

+Ax88772MulticastClear (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  DBG_ENTER ( );

+

+  //

+  // Clear the multicast hash table

+  //

+  pNicDevice->MulticastHash[0] = 0;

+  pNicDevice->MulticastHash[1] = 0;

+

+  DBG_EXIT ( );

+}

+

+

+/**

+  Enable a multicast address in the multicast hash table

+

+  This routine calls ::Ax88772Crc to compute the hash bit for

+  this MAC address.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.

+

+**/

+VOID

+Ax88772MulticastSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  )

+{

+  UINT32 BitNumber;

+  UINT32 Crc;

+  UINT32 Mask;

+

+  DBG_ENTER ( );

+

+  //

+  //  Compute the CRC on the destination address

+  //

+  Crc = Ax88772Crc ( pMacAddress );

+

+  //

+  //  Set the bit corresponding to the destination address

+  //

+  BitNumber = Crc >> 26;

+  if ( 32 > BitNumber ) {

+    Mask = 1 << BitNumber;

+    pNicDevice->MulticastHash[0] |= Mask;

+  }

+  else {

+    Mask = 1 << ( BitNumber - 32 );

+    pNicDevice->MulticastHash[1] |= Mask;

+  }

+

+  //

+  //  Display the multicast address

+  //

+  DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,

+            "Enable multicast: 0x%02x-%02x-%02x-%02x-%02x-%02x, CRC: 0x%08x, Bit number: 0x%02x\r\n",

+            pMacAddress[0],

+            pMacAddress[1],

+            pMacAddress[2],

+            pMacAddress[3],

+            pMacAddress[4],

+            pMacAddress[5],

+            Crc,

+            BitNumber ));

+

+  DBG_EXIT ( );

+}

+

+

+/**

+  Start the link negotiation

+

+  This routine calls ::Ax88772PhyWrite to start the PHY's link

+  negotiation.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The link negotiation was started.

+  @retval other                Failed to start the link negotiation.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkStart (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  UINT16 Control;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // Set the supported capabilities.

+  //

+  Status = Ax88772PhyWrite ( pNicDevice,

+                             PHY_ANAR,

+                             AN_CSMA_CD

+                             | AN_TX_FDX | AN_TX_HDX

+                             | AN_10_FDX | AN_10_HDX );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    // Set the link speed and duplex

+    //

+    Control = BMCR_AUTONEGOTIATION_ENABLE

+            | BMCR_RESTART_AUTONEGOTIATION;

+    if ( pNicDevice->b100Mbps ) {

+      Control |= BMCR_100MBPS;

+    }

+    if ( pNicDevice->bFullDuplex ) {

+      Control |= BMCR_FULL_DUPLEX;

+    }

+    Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Complete the negotiation of the PHY link

+

+  This routine calls ::Ax88772PhyRead to determine if the

+  link negotiation is complete.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in, out] pPollCount  Address of number of times this routine was polled

+  @param [out] pbComplete      Address of boolean to receive complate status.

+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.

+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.

+  @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkComplete (

+  IN NIC_DEVICE * pNicDevice,

+  IN OUT UINTN * pPollCount,

+  OUT BOOLEAN * pbComplete,

+  OUT BOOLEAN * pbLinkUp,

+  OUT BOOLEAN * pbHiSpeed,

+  OUT BOOLEAN * pbFullDuplex

+  )

+{

+  UINT16 Mask;

+  UINT16 PhyData;

+  EFI_STATUS  Status;

+

+  DBG_ENTER ( );

+  

+  //

+  //  Determine if the link is up.

+  //

+  *pbComplete = FALSE;

+

+  //

+  //  Get the link status

+  //

+  Status = Ax88772PhyRead ( pNicDevice,

+                            PHY_BMSR,

+                            &PhyData );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  Determine if the autonegotiation is complete.

+    //

+    *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));

+    *pbComplete = *pbLinkUp;

+    if ( 0 != *pbComplete ) {

+      //

+      //  Get the partners capabilities.

+      //

+      Status = Ax88772PhyRead ( pNicDevice,

+                                PHY_ANLPAR,

+                                &PhyData );

+      if ( !EFI_ERROR ( Status )) {

+        //

+        //  Autonegotiation is complete

+        //  Determine the link speed.

+        //

+        *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));

+

+        //

+        //  Determine the link duplex.

+        //

+        Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;

+        *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));

+      }

+    }

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Read a register from the PHY

+

+  This routine calls ::Ax88772UsbCommand to read a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in, out] pPhyData    Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data is available.

+  @retval other                The PHY data is not valid.

+

+**/

+EFI_STATUS

+Ax88772PhyRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN OUT UINT16 * pPhyData

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Request access to the PHY

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               NULL );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  Read the PHY register address.

+    //

+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                         | USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_PHY_REG_READ;

+    SetupMsg.Value = pNicDevice->PhyId;

+    SetupMsg.Index = RegisterAddress;

+    SetupMsg.Length = sizeof ( *pPhyData );

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 pPhyData );

+    if ( !EFI_ERROR ( Status )) {

+      DEBUG (( DEBUG_PHY | DEBUG_INFO,

+                "PHY %d: 0x%02x --> 0x%04x\r\n",

+                pNicDevice->PhyId,

+                RegisterAddress,

+                *pPhyData ));

+

+      //

+      //  Release the PHY to the hardware

+      //

+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;

+      SetupMsg.Value = 0;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = 0;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   NULL );

+    }

+  }

+

+  //

+  //  Return the operation status.

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Write to a PHY register

+

+  This routine calls ::Ax88772UsbCommand to write a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in] PhyData          Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data was written.

+  @retval other                Failed to wwrite the PHY register.

+

+**/

+EFI_STATUS

+Ax88772PhyWrite (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN UINT16 PhyData

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  //  Request access to the PHY

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               NULL );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  Write the PHY register

+    //

+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_PHY_REG_WRITE;

+    SetupMsg.Value = pNicDevice->PhyId;

+    SetupMsg.Index = RegisterAddress;

+    SetupMsg.Length = sizeof ( PhyData );

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 &PhyData );

+    if ( !EFI_ERROR ( Status )) {

+      DEBUG (( DEBUG_PHY | DEBUG_INFO,

+                "PHY %d: 0x%02x <-- 0x%04x\r\n",

+                pNicDevice->PhyId,

+                RegisterAddress,

+                PhyData ));

+

+      //

+      //  Release the PHY to the hardware

+      //

+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;

+      SetupMsg.Value = 0;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = 0;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   NULL );

+    }

+  }

+

+  //

+  //  Return the operation status.

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Reset the AX88772

+

+  This routine uses ::Ax88772UsbCommand to reset the network

+  adapter.  This routine also uses ::Ax88772PhyWrite to reset

+  the PHY.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772Reset (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+

+  //

+  //  Turn off the MAC

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_RX_CONTROL_WRITE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               NULL );

+  if ( !EFI_ERROR ( Status )) {

+    DEBUG (( DEBUG_PHY | DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST

+              | DEBUG_RX_UNICAST | DEBUG_TX | DEBUG_INFO,

+              "MAC reset\r\n" ));

+

+    //

+    //  The link is now idle

+    //

+    pNicDevice->bLinkIdle = TRUE;

+

+    //

+    //  Delay for a bit

+    //

+    gBS->Stall ( RESET_MSEC );

+

+    //

+    //  Select the internal PHY

+    //

+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_PHY_SELECT;

+    SetupMsg.Value = SPHY_PSEL;

+    SetupMsg.Index = 0;

+    SetupMsg.Length = 0;

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 NULL );

+    if ( !EFI_ERROR ( Status )) {

+      //

+      //  Delay for a bit

+      //

+      gBS->Stall ( PHY_RESET_MSEC );

+

+      //

+      //  Clear the internal PHY reset

+      //

+      SetupMsg.Request = CMD_RESET;

+      SetupMsg.Value = SRR_IPRL | SRR_PRL;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   NULL );

+      if ( !EFI_ERROR ( Status )) {

+        //

+        //  Reset the PHY

+        //

+        Status = Ax88772PhyWrite ( pNicDevice,

+                                   PHY_BMCR,

+                                   BMCR_RESET );

+        if ( !EFI_ERROR ( Status )) {

+          //

+          //  Set the gaps

+          //

+          SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                               | USB_TARGET_DEVICE;

+          SetupMsg.Request = CMD_GAPS_WRITE;

+          SetupMsg.Value = 0x0c15;

+          SetupMsg.Index = 0x0e;

+          SetupMsg.Length = 0;

+          Status = Ax88772UsbCommand ( pNicDevice,

+                                       &SetupMsg,

+                                       NULL );

+        }

+      }

+    }

+  }

+

+  //

+  //  Return the operation status.

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+VOID 

+FillPkt2Queue (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINTN BufLength)

+{

+

+  UINT16 * pLength;

+  UINT16 * pLengthBar;

+  UINT8* pData;

+  UINT32 offset;

+  RX_TX_PACKET * pRxPacket;

+  UINTN LengthInBytes;

+  EFI_STATUS Status;

+  

+  for ( offset = 0; offset < BufLength; ){

+    pLength = (UINT16*) (pNicDevice->pBulkInBuff + offset);

+    pLengthBar = (UINT16*) (pNicDevice->pBulkInBuff + offset +2);

+    

+    *pLength &= 0x7ff;

+    *pLengthBar &= 0x7ff;

+    *pLengthBar |= 0xf800;

+      

+    if ((*pLength ^ *pLengthBar ) != 0xFFFF) {

+      DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength = %d\n", BufLength));

+      return;

+    }

+      

+    pRxPacket = pNicDevice->pRxFree;

+    LengthInBytes = sizeof ( *pRxPacket ) - sizeof ( pRxPacket->pNext );

+    if ( NULL == pRxPacket ) {

+      Status = gBS->AllocatePool ( EfiRuntimeServicesData,

+                                   sizeof( RX_TX_PACKET ),

+                                   (VOID **) &pRxPacket );

+      if ( !EFI_ERROR ( Status )) {

+        //

+        //  Add this packet to the free packet list

+        //

+        pNicDevice->pRxFree = pRxPacket;

+        pRxPacket->pNext = NULL;

+      }

+      else {

+        //

+        //  Use the discard packet buffer

+        //

+        //pRxPacket = &Packet;

+      }

+    }

+      

+

+    pData = pNicDevice->pBulkInBuff + offset + 4;

+    pRxPacket->Length = *pLength;

+    pRxPacket->LengthBar = *(UINT16*) (pNicDevice->pBulkInBuff + offset +2);

+    CopyMem (&pRxPacket->Data[0], pData, *pLength);

+    //DEBUG((DEBUG_INFO, "Packet [%d]\n", *pLength));

+    

+    pNicDevice->pRxFree = pRxPacket->pNext;

+    pRxPacket->pNext = NULL;

+    

+    if ( NULL == pNicDevice->pRxTail ) {

+      pNicDevice->pRxHead = pRxPacket;

+    }

+    else {

+      pNicDevice->pRxTail->pNext = pRxPacket;

+    }

+    pNicDevice->pRxTail = pRxPacket;

+    offset += (*pLength + 4);

+              

+  }

+}

+

+

+

+/**

+  Receive a frame from the network.

+

+  This routine polls the USB receive interface for a packet.  If a packet

+  is available, this routine adds the receive packet to the list of

+  pending receive packets.

+

+  This routine calls ::Ax88772NegotiateLinkComplete to verify

+  that the link is up.  This routine also calls ::SN_Reset to

+  reset the network adapter when necessary.  Finally this

+  routine attempts to receive one or more packets from the

+  network adapter.

+

+  @param [in] pNicDevice  Pointer to the NIC_DEVICE structure

+  @param [in] bUpdateLink TRUE = Update link status

+

+**/

+VOID

+Ax88772Rx (

+  IN NIC_DEVICE * pNicDevice,

+  IN BOOLEAN bUpdateLink

+  )

+{

+  BOOLEAN bFullDuplex;

+  BOOLEAN bLinkUp;

+  BOOLEAN bRxPacket;

+  BOOLEAN bSpeed100;

+  UINTN LengthInBytes;

+  RX_TX_PACKET Packet;

+  RX_TX_PACKET * pRxPacket;

+  EFI_USB_IO_PROTOCOL *pUsbIo;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  UINT32 TransferStatus;

+

+  //

+  //  Synchronize with Ax88772Timer

+  //

+  VERIFY_TPL ( TPL_AX88772 );

+  TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );

+  DEBUG (( DEBUG_TPL | DEBUG_INFO,

+            "%d: TPL\r\n",

+            TPL_AX88772 ));

+

+  //

+  //  Get the link status

+  //

+  if ( bUpdateLink ) {

+    bLinkUp = pNicDevice->bLinkUp;

+    bSpeed100 = pNicDevice->b100Mbps;

+    bFullDuplex = pNicDevice->bFullDuplex;

+    Status = Ax88772NegotiateLinkComplete ( pNicDevice,

+                                            &pNicDevice->PollCount,

+                                            &pNicDevice->bComplete,

+                                            &pNicDevice->bLinkUp,

+                                            &pNicDevice->b100Mbps,

+                                            &pNicDevice->bFullDuplex );

+

+    //

+    // Determine if the autonegotiation is complete

+    //

+    if ( pNicDevice->bComplete ) {

+      if ( pNicDevice->bLinkUp ) {

+        if (( bSpeed100 && ( !pNicDevice->b100Mbps ))

+          || (( !bSpeed100 ) && pNicDevice->b100Mbps )

+          || ( bFullDuplex && ( !pNicDevice->bFullDuplex ))

+          || (( !bFullDuplex ) && pNicDevice->bFullDuplex )) {

+          pNicDevice->PollCount = 0;

+          DEBUG (( DEBUG_LINK | DEBUG_INFO,

+                    "Reset to establish proper link setup: %d Mbps, %s duplex\r\n",

+                    pNicDevice->b100Mbps ? 100 : 10,

+                    pNicDevice->bFullDuplex ? L"Full" : L"Half" ));

+          Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );

+        }

+        if (( !bLinkUp ) && pNicDevice->bLinkUp ) {

+          //

+          // Display the autonegotiation status

+          //

+          DEBUG (( DEBUG_LINK | DEBUG_INFO,

+                    "Link: Up, %d Mbps, %s duplex\r\n",

+                    pNicDevice->b100Mbps ? 100 : 10,

+                    pNicDevice->bFullDuplex ? L"Full" : L"Half" ));

+        }

+      }

+    }

+

+    //

+    //  Update the link status

+    //

+    if ( bLinkUp && ( !pNicDevice->bLinkUp )) {

+      DEBUG (( DEBUG_LINK | DEBUG_INFO, "Link: Down\r\n" ));

+    }

+  }

+

+  //

+  //  Loop until all the packets are emptied from the receiver

+  //

+  do {

+    bRxPacket = FALSE;

+

+    //

+    //  Locate a packet for use

+    //

+    pRxPacket = pNicDevice->pRxFree;

+    LengthInBytes = MAX_BULKIN_SIZE;

+    if ( NULL == pRxPacket ) {

+      Status = gBS->AllocatePool ( EfiRuntimeServicesData,

+                                   sizeof ( *pRxPacket ),

+                                   (VOID **) &pRxPacket );

+      if ( !EFI_ERROR ( Status )) {

+        //

+        //  Add this packet to the free packet list

+        //

+        pNicDevice->pRxFree = pRxPacket;

+        pRxPacket->pNext = NULL;

+      }

+      else {

+        //

+        //  Use the discard packet buffer

+        //

+        pRxPacket = &Packet;

+      }

+    }

+

+    //

+    //  Attempt to receive a packet

+    //

+    SetMem (&pNicDevice->pBulkInBuff[0], MAX_BULKIN_SIZE, 0);

+    pUsbIo = pNicDevice->pUsbIo;

+    Status = pUsbIo->UsbBulkTransfer ( pUsbIo,

+                                       USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,

+                                       &pNicDevice->pBulkInBuff[0],

+                                       &LengthInBytes,

+                                       2,

+                                       &TransferStatus );

+    if ( LengthInBytes > 0 ) {

+      FillPkt2Queue(pNicDevice, LengthInBytes);

+    }

+    pRxPacket = pNicDevice->pRxHead;

+    if (( !EFI_ERROR ( Status ))

+      && ( 0 < pRxPacket->Length )

+      && ( pRxPacket->Length <= sizeof ( pRxPacket->Data ))

+      && ( LengthInBytes > 0)) {

+

+      //

+      //  Determine if the packet should be received

+      //

+      bRxPacket = TRUE;

+      LengthInBytes = pRxPacket->Length;

+      pNicDevice->bLinkIdle = FALSE;

+      if ( pNicDevice->pRxFree == pRxPacket ) {

+        //

+        //  Display the received packet

+        //

+        if ( 0 != ( pRxPacket->Data[0] & 1 )) {

+          if (( 0xff == pRxPacket->Data[0])

+            && ( 0xff == pRxPacket->Data[1])

+            && ( 0xff == pRxPacket->Data[2])

+            && ( 0xff == pRxPacket->Data[3])

+            && ( 0xff == pRxPacket->Data[4])

+            && ( 0xff == pRxPacket->Data[5])) {

+            DEBUG (( DEBUG_RX_BROADCAST | DEBUG_INFO,

+                      "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",

+                      pRxPacket->Data[0],

+                      pRxPacket->Data[1],

+                      pRxPacket->Data[2],

+                      pRxPacket->Data[3],

+                      pRxPacket->Data[4],

+                      pRxPacket->Data[5],

+                      pRxPacket->Data[6],

+                      pRxPacket->Data[7],

+                      pRxPacket->Data[8],

+                      pRxPacket->Data[9],

+                      pRxPacket->Data[10],

+                      pRxPacket->Data[11],

+                      pRxPacket->Data[12],

+                      pRxPacket->Data[13],

+                      LengthInBytes ));

+          }

+          else {

+            DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,

+                      "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",

+                      pRxPacket->Data[0],

+                      pRxPacket->Data[1],

+                      pRxPacket->Data[2],

+                      pRxPacket->Data[3],

+                      pRxPacket->Data[4],

+                      pRxPacket->Data[5],

+                      pRxPacket->Data[6],

+                      pRxPacket->Data[7],

+                      pRxPacket->Data[8],

+                      pRxPacket->Data[9],

+                      pRxPacket->Data[10],

+                      pRxPacket->Data[11],

+                      pRxPacket->Data[12],

+                      pRxPacket->Data[13],

+                      LengthInBytes ));

+          }

+        }

+        else {

+          DEBUG (( DEBUG_RX_UNICAST | DEBUG_INFO,

+                    "RX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",

+                    pRxPacket->Data[0],

+                    pRxPacket->Data[1],

+                    pRxPacket->Data[2],

+                    pRxPacket->Data[3],

+                    pRxPacket->Data[4],

+                    pRxPacket->Data[5],

+                    pRxPacket->Data[6],

+                    pRxPacket->Data[7],

+                    pRxPacket->Data[8],

+                    pRxPacket->Data[9],

+                    pRxPacket->Data[10],

+                    pRxPacket->Data[11],

+                    pRxPacket->Data[12],

+                    pRxPacket->Data[13],

+                    LengthInBytes ));

+        }

+        

+      }

+      else {

+        //

+        //  Error, not enough buffers for this packet, discard packet

+        //

+        DEBUG (( DEBUG_WARN | DEBUG_INFO,

+                  "WARNING - No buffer, discarding RX packet: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",

+                  pRxPacket->Data[0],

+                  pRxPacket->Data[1],

+                  pRxPacket->Data[2],

+                  pRxPacket->Data[3],

+                  pRxPacket->Data[4],

+                  pRxPacket->Data[5],

+                  pRxPacket->Data[6],

+                  pRxPacket->Data[7],

+                  pRxPacket->Data[8],

+                  pRxPacket->Data[9],

+                  pRxPacket->Data[10],

+                  pRxPacket->Data[11],

+                  pRxPacket->Data[12],

+                  pRxPacket->Data[13],

+                  LengthInBytes ));

+      }

+    }

+  }while ( bRxPacket );

+

+  //

+  //  Release the synchronization withhe Ax88772Timer

+  //

+  gBS->RestoreTPL ( TplPrevious );

+  DEBUG (( DEBUG_TPL | DEBUG_INFO,

+            "%d: TPL\r\n",

+            TplPrevious ));

+}

+

+

+/**

+  Enable or disable the receiver

+

+  This routine calls ::Ax88772UsbCommand to update the

+  receiver state.  This routine also calls ::Ax88772MacAddressSet

+  to establish the MAC address for the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RxFilter         Simple network RX filter mask value

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772RxControl (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 RxFilter

+  )

+{

+  UINT16 MediumStatus;

+  INT32 MulticastHash[2];

+  UINT16 RxControl;

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Disable all multicast

+  //

+  MulticastHash[0] = 0;

+  MulticastHash[1] = 0;

+

+  //

+  // Enable the receiver if something is to be received

+  //

+  Status = EFI_SUCCESS;

+  RxControl = RXC_SO | RXC_MFB_16384;

+  if ( 0 != RxFilter ) {

+    //

+    //  Enable the receiver

+    //

+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                         | USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_MEDIUM_STATUS_READ;

+    SetupMsg.Value = 0;

+    SetupMsg.Index = 0;

+    SetupMsg.Length = sizeof ( MediumStatus );

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 &MediumStatus );

+    if ( !EFI_ERROR ( Status )) {

+      if ( 0 == ( MediumStatus & MS_RE )) {

+        MediumStatus |= MS_RE | MS_ONE;

+        if ( pNicDevice->bFullDuplex ) {

+          MediumStatus |= MS_TFC | MS_RFC;

+        }

+        SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                             | USB_TARGET_DEVICE;

+        SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;

+        SetupMsg.Value = MediumStatus;

+        SetupMsg.Index = 0;

+        SetupMsg.Length = 0;

+        Status = Ax88772UsbCommand ( pNicDevice,

+                                     &SetupMsg,

+                                     NULL );

+        if ( EFI_ERROR ( Status )) {

+          DEBUG (( DEBUG_ERROR | DEBUG_INFO,

+                    "ERROR - Failed to enable receiver, Status: %r\r\n",

+                    Status ));

+        }

+      }

+    }

+    else {

+      DEBUG (( DEBUG_ERROR | DEBUG_INFO,

+                "ERROR - Failed to read receiver status, Status: %r\r\n",

+                Status ));

+    }

+

+    //

+    //  Enable multicast if requested

+    //

+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {

+      RxControl |= RXC_AM;

+      MulticastHash[0] = pNicDevice->MulticastHash[0];

+      MulticastHash[1] = pNicDevice->MulticastHash[1];

+    }

+

+    //

+    //  Enable all multicast if requested

+    //

+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {

+      RxControl |= RXC_AMALL;

+      MulticastHash[0] = -1;

+      MulticastHash[1] = -1;

+    }

+

+    //

+    //  Enable broadcast if requested

+    //

+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {

+      RxControl |= RXC_AB;

+    }

+

+    //

+    //  Enable promiscuous mode if requested

+    //

+    if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {

+      RxControl |= RXC_PRO;

+      MulticastHash[0] = -1;

+      MulticastHash[1] = -1;

+    }

+  }

+

+  //

+  //  Update the MAC address

+  //

+  if ( !EFI_ERROR ( Status )) {

+    Status = Ax88772MacAddressSet ( pNicDevice, &pNicDevice->SimpleNetworkData.CurrentAddress.Addr[0]);

+  }

+

+  //

+  //  Update the receiver control

+  //

+  if ( !EFI_ERROR ( Status )) {

+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_RX_CONTROL_WRITE;

+    SetupMsg.Value = RxControl;

+    SetupMsg.Index = 0;

+    SetupMsg.Length = 0;

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 NULL );

+    if ( !EFI_ERROR ( Status )) {

+      DEBUG (( DEBUG_RX_BROADCAST | DEBUG_RX_MULTICAST | DEBUG_RX_UNICAST | DEBUG_INFO,

+                "RxControl: 0x%04x\r\n",

+                RxControl ));

+

+      //

+      //  Update the multicast hash table

+      //

+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;

+      SetupMsg.Value = 0;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   &pNicDevice->MulticastHash );

+      if ( !EFI_ERROR ( Status )) {

+        DEBUG (( DEBUG_RX_MULTICAST | DEBUG_INFO,

+                  "Multicast Hash: 0x%02x %02x %02x %02x %02x %02x %02x %02x\r\n",

+                  (UINT8) MulticastHash[0],

+                  (UINT8)( MulticastHash[0] >> 8 ),

+                  (UINT8)( MulticastHash[0] >> 16 ),

+                  (UINT8)( MulticastHash[0] >> 24 ),

+                  (UINT8) MulticastHash[1],

+                  (UINT8)( MulticastHash[1] >> 8 ),

+                  (UINT8)( MulticastHash[1] >> 16 ),

+                  (UINT8)( MulticastHash[1] >> 24 )));

+      }

+      else {

+        DEBUG (( DEBUG_ERROR | DEBUG_INFO,

+                  "ERROR - Failed to update multicast hash table, Status: %r\r\n",

+                  Status ));

+      }

+    }

+    else {

+      DEBUG (( DEBUG_ERROR | DEBUG_INFO,

+                "ERROR - Failed to set receiver control, Status: %r\r\n",

+                Status ));

+    }

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Read an SROM location

+

+  This routine calls ::Ax88772UsbCommand to read data from the

+  SROM.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] Address          SROM address

+  @param [out] pData           Buffer to receive the data

+

+  @retval EFI_SUCCESS          The read was successful

+  @retval other                The read failed

+

+**/

+EFI_STATUS

+Ax88772SromRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 Address,

+  OUT UINT16 * pData

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Read a value from the SROM

+  //

+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                       | USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_SROM_READ;

+  SetupMsg.Value = (UINT16) Address;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = sizeof ( *pData );

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               pData );

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This routine is called at a regular interval to poll for

+  receive packets.

+

+  This routine polls the link state and gets any receive packets

+  by calling ::Ax88772Rx.

+

+  @param [in] Event            Timer event

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+**/

+VOID

+Ax88772Timer (

+  IN EFI_EVENT Event,

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  //

+  //  Use explicit DEBUG messages since the output frequency is too

+  //  high for DEBUG_INFO to keep up and have spare cycles for the

+  //  shell

+  //

+  DEBUG (( DEBUG_TIMER, "Entering Ax88772Timer\r\n" ));

+

+  //

+  //  Poll the link state and get any receive packets

+  //

+  Ax88772Rx ( pNicDevice, FALSE );

+

+  DEBUG (( DEBUG_TIMER, "Exiting Ax88772Timer\r\n" ));

+}

+

+

+/**

+  Send a command to the USB device.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pRequest         Pointer to the request structure

+  @param [in, out] pBuffer     Data buffer address

+

+  @retval EFI_SUCCESS          The USB transfer was successful

+  @retval other                The USB transfer failed

+

+**/

+EFI_STATUS

+Ax88772UsbCommand (

+  IN NIC_DEVICE * pNicDevice,

+  IN USB_DEVICE_REQUEST * pRequest,

+  IN OUT VOID * pBuffer

+  )

+{

+  UINT32 CmdStatus;

+  EFI_USB_DATA_DIRECTION Direction;

+  EFI_USB_IO_PROTOCOL * pUsbIo;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // Determine the transfer direction

+  //

+  Direction = EfiUsbNoData;

+  if ( 0 != pRequest->Length ) {

+    Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))

+              ? EfiUsbDataIn : EfiUsbDataOut;

+  }

+

+  //

+  // Issue the command

+  //

+  pUsbIo = pNicDevice->pUsbIo;

+  Status = pUsbIo->UsbControlTransfer ( pUsbIo,

+                                        pRequest,

+                                        Direction,

+                                        USB_BUS_TIMEOUT,

+                                        pBuffer,

+                                        pRequest->Length,

+                                        &CmdStatus );

+

+  //

+  // Determine the operation status

+  //

+  if ( !EFI_ERROR ( Status )) {

+    Status = CmdStatus;

+  }

+  else {

+    //

+    // Display any errors

+    //

+    DEBUG (( DEBUG_INFO,

+              "Ax88772UsbCommand - Status: %r\n",

+              Status ));

+

+    //

+    // Only use status values associated with the Simple Network protocol

+    //

+    if ( EFI_TIMEOUT == Status ) {

+      Status = EFI_DEVICE_ERROR;

+    }

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h
new file mode 100644
index 0000000..3c02725
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h
@@ -0,0 +1,976 @@
+/** @file

+  Definitions for ASIX AX88772 Ethernet adapter.

+

+  Copyright (c) 2011, 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.

+

+**/

+

+#ifndef _AX88772_H_

+#define _AX88772_H_

+

+#include <Uefi.h>

+

+#include <Guid/EventGroup.h>

+#include <Guid/NicIp4ConfigNvData.h>

+

+#include <IndustryStandard/Pci.h>

+

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/DevicePathLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/UefiLib.h>

+#include <Library/UefiRuntimeLib.h>

+

+#include <Protocol/DevicePath.h>

+#include <Protocol/LoadedImage.h>

+#include <Protocol/NetworkInterfaceIdentifier.h>

+#include <Protocol/SimpleNetwork.h>

+#include <Protocol/UsbIo.h>

+

+//------------------------------------------------------------------------------

+//  Macros

+//------------------------------------------------------------------------------

+//

+//Too many output debug info hangs system in Debug tip

+//

+//#if defined(_MSC_VER)           /* Handle Microsoft VC++ compiler specifics. */

+//#define DBG_ENTER()             DEBUG (( DEBUG_INFO, "Entering " __FUNCTION__ "\n" )) ///<  Display routine entry

+//#define DBG_EXIT()              DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ "\n" ))  ///<  Display routine exit

+//#define DBG_EXIT_DEC(Status)    DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %d\n", Status ))      ///<  Display routine exit with decimal value

+//#define DBG_EXIT_HEX(Status)    DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status ))  ///<  Display routine exit with hex value

+//#define DBG_EXIT_STATUS(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %r\n", Status ))      ///<  Display routine exit with status value

+//#define DBG_EXIT_TF(Status)     DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" ))  ///<  Display routine with TRUE/FALSE value

+//#else   //  _MSC_VER

+#define DBG_ENTER()               ///<  Display routine entry

+#define DBG_EXIT()                ///<  Display routine exit

+#define DBG_EXIT_DEC(Status)      ///<  Display routine exit with decimal value

+#define DBG_EXIT_HEX(Status)      ///<  Display routine exit with hex value

+#define DBG_EXIT_STATUS(Status)   ///<  Display routine exit with status value

+#define DBG_EXIT_TF(Status)       ///<  Display routine with TRUE/FALSE value

+//#endif  //  _MSC_VER

+

+#define USB_IS_IN_ENDPOINT(EndPointAddr)      (((EndPointAddr) & BIT7) != 0)  ///<  Return TRUE/FALSE for IN direction

+#define USB_IS_OUT_ENDPOINT(EndPointAddr)     (((EndPointAddr) & BIT7) == 0)  ///<  Return TRUE/FALSE for OUT direction

+#define USB_IS_BULK_ENDPOINT(Attribute)       (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)      ///<  Return TRUE/FALSE for BULK type

+#define USB_IS_INTERRUPT_ENDPOINT(Attribute)  (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) ///<  Return TRUE/FALSE for INTERRUPT type

+

+//------------------------------------------------------------------------------

+//  Constants

+//------------------------------------------------------------------------------

+

+#define DEBUG_RX_BROADCAST  0x40000000  ///<  Display RX broadcast messages

+#define DEBUG_RX_MULTICAST  0x20000000  ///<  Display RX multicast messages

+#define DEBUG_RX_UNICAST    0x10000000  ///<  Display RX unicast messages

+#define DEBUG_MAC_ADDRESS   0x08000000  ///<  Display the MAC address

+#define DEBUG_LINK          0x04000000  ///<  Display the link status

+#define DEBUG_TX            0x02000000  ///<  Display the TX messages

+#define DEBUG_PHY           0x01000000  ///<  Display the PHY register values

+#define DEBUG_SROM          0x00800000  ///<  Display the SROM contents

+#define DEBUG_TIMER         0x00400000  ///<  Display the timer routine entry/exit

+#define DEBUG_TPL           0x00200000  ///<  Display the timer routine entry/exit

+

+#define AX88772_MAX_PKT_SIZE  ( 2048 - 4 )  ///< Maximum packet size

+#define ETHERNET_HEADER_SIZE  sizeof ( ETHERNET_HEADER )  ///<  Size in bytes of the Ethernet header

+#define MIN_ETHERNET_PKT_SIZE 60    ///<  Minimum packet size including Ethernet header

+#define MAX_ETHERNET_PKT_SIZE 1500  ///<  Ethernet spec 3.1.1: Minimum packet size

+#define MAX_BULKIN_SIZE       2048  ///<  Maximum size of one UsbBulk 

+

+

+#define USB_NETWORK_CLASS   0x09    ///<  USB Network class code

+#define USB_BUS_TIMEOUT     1000    ///<  USB timeout in milliseconds

+

+#define TIMER_MSEC          20              ///<  Polling interval for the NIC

+#define TPL_AX88772         TPL_CALLBACK    ///<  TPL for routine synchronization

+

+/**

+  Verify new TPL value

+

+  This macro which is enabled when debug is enabled verifies that

+  the new TPL value is >= the current TPL value.

+**/

+#ifdef VERIFY_TPL

+#undef VERIFY_TPL

+#endif  //  VERIFY_TPL

+

+#if !defined(MDEPKG_NDEBUG)

+

+#define VERIFY_TPL(tpl)                           \

+{                                                 \

+  EFI_TPL PreviousTpl;                            \

+                                                  \

+  PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \

+  gBS->RestoreTPL ( PreviousTpl );                \

+  if ( PreviousTpl > tpl ) {                      \

+    DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl ));  \

+    ASSERT ( PreviousTpl <= tpl );                \

+  }                                               \

+}

+

+#else   //  MDEPKG_NDEBUG

+

+#define VERIFY_TPL(tpl)

+

+#endif  //  MDEPKG_NDEBUG

+

+//------------------------------------------------------------------------------

+//  Hardware Definition

+//------------------------------------------------------------------------------

+

+#define DEV_SIGNATURE     SIGNATURE_32 ('A','X','8','8')  ///<  Signature of data structures in memory

+

+#define VENDOR_ID         0x0b95  ///<  Vendor ID for Asix

+#define PRODUCT_ID        0x7720  ///<  Product ID for the AX88772 USB 10/100 Ethernet controller

+

+#define RESET_MSEC        1000    ///<  Reset duration

+#define PHY_RESET_MSEC     500    ///<  PHY reset duration

+

+//

+//  RX Control register

+//

+

+#define RXC_PRO           0x0001  ///<  Receive all packets

+#define RXC_AMALL         0x0002  ///<  Receive all multicast packets

+#define RXC_SEP           0x0004  ///<  Save error packets

+#define RXC_AB            0x0008  ///<  Receive broadcast packets

+#define RXC_AM            0x0010  ///<  Use multicast destination address hash table

+#define RXC_AP            0x0020  ///<  Accept physical address from Multicast Filter

+#define RXC_SO            0x0080  ///<  Start operation

+#define RXC_MFB           0x0300  ///<  Maximum frame burst

+#define RXC_MFB_2048      0       ///<  Maximum frame size:  2048 bytes

+#define RXC_MFB_4096      0x0100  ///<  Maximum frame size:  4096 bytes

+#define RXC_MFB_8192      0x0200  ///<  Maximum frame size:  8192 bytes

+#define RXC_MFB_16384     0x0300  ///<  Maximum frame size: 16384 bytes

+

+//

+//  Medium Status register

+//

+

+#define MS_FD             0x0002  ///<  Full duplex

+#define MS_ONE            0x0004  ///<  Must be one

+#define MS_RFC            0x0010  ///<  RX flow control enable

+#define MS_TFC            0x0020  ///<  TX flow control enable

+#define MS_PF             0x0080  ///<  Pause frame enable

+#define MS_RE             0x0100  ///<  Receive enable

+#define MS_PS             0x0200  ///<  Port speed 1=100, 0=10 Mbps

+#define MS_SBP            0x0800  ///<  Stop back pressure

+#define MS_SM             0x1000  ///<  Super MAC support

+

+//

+//  Software PHY Select register

+//

+

+#define SPHY_PSEL         0x01    ///<  Select internal PHY

+#define SPHY_ASEL         0x02    ///<  1=Auto select, 0=Manual select

+

+//

+//  Software Reset register

+//

+

+#define SRR_RR            0x01    ///<  Clear receive frame length error

+#define SRR_RT            0x02    ///<  Clear transmit frame length error

+#define SRR_PRTE          0x04    ///<  External PHY reset pin tri-state enable

+#define SRR_PRL           0x08    ///<  External PHY reset pin level

+#define SRR_BZ            0x10    ///<  Force Bulk to return zero length packet

+#define SRR_IPRL          0x20    ///<  Internal PHY reset control

+#define SRR_IPPD          0x40    ///<  Internal PHY power down

+

+//

+//  PHY ID values

+//

+

+#define PHY_ID_INTERNAL   0x0010  ///<  Internal PHY

+

+//

+//  USB Commands

+//

+

+#define CMD_PHY_ACCESS_SOFTWARE   0x06  ///<  Software in control of PHY

+#define CMD_PHY_REG_READ          0x07  ///<  Read PHY register, Value: PHY, Index: Register, Data: Register value

+#define CMD_PHY_REG_WRITE         0x08  ///<  Write PHY register, Value: PHY, Index: Register, Data: New 16-bit value

+#define CMD_PHY_ACCESS_HARDWARE   0x0a  ///<  Hardware in control of PHY

+#define CMD_SROM_READ             0x0b  ///<  Read SROM register: Value: Address, Data: Value

+#define CMD_RX_CONTROL_WRITE      0x10  ///<  Set the RX control register, Value: New value

+#define CMD_GAPS_WRITE            0x12  ///<  Write the gaps register, Value: New value

+#define CMD_MAC_ADDRESS_READ      0x13  ///<  Read the MAC address, Data: 6 byte MAC address

+#define CMD_MAC_ADDRESS_WRITE     0x14  ///<  Set the MAC address, Data: New 6 byte MAC address

+#define CMD_MULTICAST_HASH_WRITE  0x16  ///<  Write the multicast hash table, Data: New 8 byte value

+#define CMD_MEDIUM_STATUS_READ    0x1a  ///<  Read medium status register, Data: Register value

+#define CMD_MEDIUM_STATUS_WRITE   0x1b  ///<  Write medium status register, Value: New value

+#define CMD_RESET                 0x20  ///<  Reset register, Value: New value

+#define CMD_PHY_SELECT            0x22  ///<  PHY select register, Value: New value

+

+//------------------------------

+//  USB Endpoints

+//------------------------------

+

+#define CONTROL_ENDPOINT                0       ///<  Control endpoint

+#define INTERRUPT_ENDPOINT              1       ///<  Interrupt endpoint

+#define BULK_IN_ENDPOINT                2       ///<  Receive endpoint

+#define BULK_OUT_ENDPOINT               3       ///<  Transmit endpoint

+

+//------------------------------

+//  PHY Registers

+//------------------------------

+

+#define PHY_BMCR                        0       ///<  Control register

+#define PHY_BMSR                        1       ///<  Status register

+#define PHY_ANAR                        4       ///<  Autonegotiation advertisement register

+#define PHY_ANLPAR                      5       ///<  Autonegotiation link parter ability register

+#define PHY_ANER                        6       ///<  Autonegotiation expansion register

+

+//  BMCR - Register 0

+

+#define BMCR_RESET                      0x8000  ///<  1 = Reset the PHY, bit clears after reset

+#define BMCR_LOOPBACK                   0x4000  ///<  1 = Loopback enabled

+#define BMCR_100MBPS                    0x2000  ///<  100 Mbits/Sec

+#define BMCR_10MBPS                     0       ///<  10 Mbits/Sec

+#define BMCR_AUTONEGOTIATION_ENABLE     0x1000  ///<  1 = Enable autonegotiation

+#define BMCR_POWER_DOWN                 0x0800  ///<  1 = Power down

+#define BMCR_ISOLATE                    0x0400  ///<  0 = Isolate PHY

+#define BMCR_RESTART_AUTONEGOTIATION    0x0200  ///<  1 = Restart autonegotiation

+#define BMCR_FULL_DUPLEX                0x0100  ///<  Full duplex operation

+#define BMCR_HALF_DUPLEX                0       ///<  Half duplex operation

+#define BMCR_COLLISION_TEST             0x0080  ///<  1 = Collision test enabled

+

+//  BSMR - Register 1

+

+#define BMSR_100BASET4                  0x8000  ///<  1 = 100BASE-T4 mode

+#define BMSR_100BASETX_FDX              0x4000  ///<  1 = 100BASE-TX full duplex

+#define BMSR_100BASETX_HDX              0x2000  ///<  1 = 100BASE-TX half duplex

+#define BMSR_10BASET_FDX                0x1000  ///<  1 = 10BASE-T full duplex

+#define BMSR_10BASET_HDX                0x0800  ///<  1 = 10BASE-T half duplex

+#define BMSR_MF                         0x0040  ///<  1 = PHY accepts frames with preamble suppressed

+#define BMSR_AUTONEG_CMPLT              0x0020  ///<  1 = Autonegotiation complete

+#define BMSR_RF                         0x0010  ///<  1 = Remote fault

+#define BMSR_AUTONEG                    0x0008  ///<  1 = Able to perform autonegotiation

+#define BMSR_LINKST                     0x0004  ///<  1 = Link up

+#define BMSR_JABBER_DETECT              0x0002  ///<  1 = jabber condition detected

+#define BMSR_EXTENDED_CAPABILITY        0x0001  ///<  1 = Extended register capable

+

+//  ANAR and ANLPAR Registers 4, 5

+

+#define AN_NP                           0x8000  ///<  1 = Next page available

+#define AN_ACK                          0x4000  ///<  1 = Link partner acknowledged

+#define AN_RF                           0x2000  ///<  1 = Remote fault indicated by link partner

+#define AN_FCS                          0x0400  ///<  1 = Flow control ability

+#define AN_T4                           0x0200  ///<  1 = 100BASE-T4 support

+#define AN_TX_FDX                       0x0100  ///<  1 = 100BASE-TX Full duplex

+#define AN_TX_HDX                       0x0080  ///<  1 = 100BASE-TX support

+#define AN_10_FDX                       0x0040  ///<  1 = 10BASE-T Full duplex

+#define AN_10_HDX                       0x0020  ///<  1 = 10BASE-T support

+#define AN_CSMA_CD                      0x0001  ///<  1 = IEEE 802.3 CSMA/CD support

+

+//------------------------------------------------------------------------------

+//  Data Types

+//------------------------------------------------------------------------------

+

+/**

+  Ethernet header layout

+

+  IEEE 802.3-2002 Part 3 specification, section 3.1.1.

+**/

+#pragma pack(1)

+typedef struct {

+  UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];  ///<  Destination LAN address

+  UINT8 src_addr[PXE_HWADDR_LEN_ETHER];   ///<  Source LAN address

+  UINT16 type;                            ///<  Protocol or length

+} ETHERNET_HEADER;

+#pragma pack()

+

+/**

+  Receive and Transmit packet structure

+**/

+#pragma pack(1)

+typedef struct _RX_TX_PACKET {

+  struct _RX_TX_PACKET * pNext;       ///<  Next receive packet

+  UINT16 Length;                      ///<  Packet length

+  UINT16 LengthBar;                   ///<  Complement of the length

+  UINT8 Data[ AX88772_MAX_PKT_SIZE ]; ///<  Received packet data

+} RX_TX_PACKET;

+#pragma pack()

+

+/**

+  AX88772 control structure

+

+  The driver uses this structure to manage the Asix AX88772 10/100

+  Ethernet controller.

+**/

+typedef struct {

+  UINTN Signature;          ///<  Structure identification

+

+  //

+  //  USB data

+  //

+  EFI_HANDLE Controller;        ///<  Controller handle

+  EFI_USB_IO_PROTOCOL * pUsbIo; ///<  USB driver interface

+

+  //

+  //  Simple network protocol data

+  //

+  EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork;  ///<  Driver's network stack interface

+  EFI_SIMPLE_NETWORK_MODE SimpleNetworkData;  ///<  Data for simple network

+

+  //

+  // Ethernet controller data

+  //

+  BOOLEAN bInitialized;     ///<  Controller initialized

+  VOID * pTxBuffer;         ///<  Last transmit buffer

+  UINT16 PhyId;             ///<  PHY ID

+

+  //

+  //  Link state

+  //

+  BOOLEAN b100Mbps;         ///<  Current link speed, FALSE = 10 Mbps

+  BOOLEAN bComplete;        ///<  Current state of auto-negotiation

+  BOOLEAN bFullDuplex;      ///<  Current duplex

+  BOOLEAN bLinkUp;          ///<  Current link state

+  BOOLEAN bLinkIdle;        ///<  TRUE = No received traffic

+  EFI_EVENT Timer;          ///<  Timer to monitor link state and receive packets

+  UINTN PollCount;          ///<  Number of times the autonegotiation status was polled

+

+  //

+  //  Receive buffer list

+  //

+  RX_TX_PACKET * pRxHead;   ///<  Head of receive packet list

+  RX_TX_PACKET * pRxTail;   ///<  Tail of receive packet list

+  RX_TX_PACKET * pRxFree;   ///<  Free packet list

+  INT32 MulticastHash[2];   ///<  Hash table for multicast destination addresses

+  UINT8 * pBulkInBuff;      ///<  Buffer for Usb Bulk

+} NIC_DEVICE;

+

+#define DEV_FROM_SIMPLE_NETWORK(a)  CR (a, NIC_DEVICE, SimpleNetwork, DEV_SIGNATURE)  ///< Locate NIC_DEVICE from Simple Network Protocol

+

+//------------------------------------------------------------------------------

+// Simple Network Protocol

+//------------------------------------------------------------------------------

+

+/**

+  Reset the network adapter.

+

+  Resets a network adapter and reinitializes it with the parameters that

+  were provided in the previous call to Initialize ().  The transmit and

+  receive queues are cleared.  Receive filters, the station address, the

+  statistics, and the multicast-IP-to-HW MAC addresses are not reset by

+  this call.

+

+  This routine calls ::Ax88772Reset to perform the adapter specific

+  reset operation.  This routine also starts the link negotiation

+  by calling ::Ax88772NegotiateLinkStart.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bExtendedVerification  Indicates that the driver may perform a more

+                                exhaustive verification operation of the device

+                                during reset.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Reset (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bExtendedVerification

+  );

+

+/**

+  Initialize the simple network protocol.

+

+  This routine calls ::Ax88772MacAddressGet to obtain the

+  MAC address.

+

+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer

+

+  @retval EFI_SUCCESS     Setup was successful

+

+**/

+EFI_STATUS

+SN_Setup (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  This routine starts the network interface.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_ALREADY_STARTED   The network interface was already started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Start (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  );

+

+/**

+  Set the MAC address.

+  

+  This function modifies or resets the current station address of a

+  network interface.  If Reset is TRUE, then the current station address

+  is set ot the network interface's permanent address.  If Reset if FALSE

+  then the current station address is changed to the address specified by

+  pNew.

+

+  This routine calls ::Ax88772MacAddressSet to update the MAC address

+  in the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Flag used to reset the station address to the

+                                network interface's permanent address.

+  @param [in] pNew              New station address to be used for the network

+                                interface.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_StationAddress (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN EFI_MAC_ADDRESS * pNew

+  );

+

+/**

+  This function resets or collects the statistics on a network interface.

+  If the size of the statistics table specified by StatisticsSize is not

+  big enough for all of the statistics that are collected by the network

+  interface, then a partial buffer of statistics is returned in

+  StatisticsTable.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.

+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output

+                                the size, in bytes, of the resulting table of statistics.

+  @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that

+                                conains the statistics.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_BUFFER_TOO_SMALL  The pStatisticsTable is NULL or the buffer is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Statistics (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN OUT UINTN * pStatisticsSize,

+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable

+  );

+

+/**

+  This function stops a network interface.  This call is only valid

+  if the network interface is in the started state.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Stop (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  );

+

+/**

+  This function releases the memory buffers assigned in the Initialize() call.

+  Pending transmits and receives are lost, and interrupts are cleared and disabled.

+  After this call, only Initialize() and Stop() calls may be used.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Shutdown (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  );

+

+/**

+  Send a packet over the network.

+

+  This function places the packet specified by Header and Buffer on

+  the transmit queue.  This function performs a non-blocking transmit

+  operation.  When the transmit is complete, the buffer is returned

+  via the GetStatus() call.

+

+  This routine calls ::Ax88772Rx to empty the network adapter of

+  receive packets.  The routine then passes the transmit packet

+  to the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by

+                                the Transmit() function.  If HeaderSize is non-zero, then

+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize

+                                and DestAddr and Protocol parameters must not be NULL.

+  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and

+                                data) to be transmitted through the network interface.

+  @param [in] pBuffer           A pointer to the packet (media header followed by data) to

+                                to be transmitted.  This parameter can not be NULL.  If

+                                HeaderSize is zero, then the media header is Buffer must

+                                already be filled in by the caller.  If HeaderSize is nonzero,

+                                then the media header will be filled in by the Transmit()

+                                function.

+  @param [in] pSrcAddr          The source HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.  If HeaderSize is nonzero and

+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress

+                                is used for the source HW MAC address.

+  @param [in] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.

+  @param [in] pProtocol         The type of header to build.  If HeaderSize is zero, then

+                                this parameter is ignored.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.

+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Transmit (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN HeaderSize,

+  IN UINTN BufferSize,

+  IN VOID * pBuffer,

+  IN EFI_MAC_ADDRESS * pSrcAddr,

+  IN EFI_MAC_ADDRESS * pDestAddr,

+  IN UINT16 * pProtocol

+  );

+

+//------------------------------------------------------------------------------

+// Support Routines

+//------------------------------------------------------------------------------

+

+/**

+  Get the MAC address

+

+  This routine calls ::Ax88772UsbCommand to request the MAC

+  address from the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772MacAddressGet (

+  IN NIC_DEVICE * pNicDevice,

+  OUT UINT8 * pMacAddress

+  );

+

+/**

+  Set the MAC address

+

+  This routine calls ::Ax88772UsbCommand to set the MAC address

+  in the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772MacAddressSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  );

+

+/**

+  Clear the multicast hash table

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+**/

+VOID

+Ax88772MulticastClear (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  Enable a multicast address in the multicast hash table

+

+  This routine calls ::Ax88772Crc to compute the hash bit for

+  this MAC address.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.

+

+**/

+VOID

+Ax88772MulticastSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  );

+

+/**

+  Start the link negotiation

+

+  This routine calls ::Ax88772PhyWrite to start the PHY's link

+  negotiation.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The link negotiation was started.

+  @retval other                Failed to start the link negotiation.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkStart (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  Complete the negotiation of the PHY link

+

+  This routine calls ::Ax88772PhyRead to determine if the

+  link negotiation is complete.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in, out] pPollCount  Address of number of times this routine was polled

+  @param [out] pbComplete      Address of boolean to receive complate status.

+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.

+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.

+  @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkComplete (

+  IN NIC_DEVICE * pNicDevice,

+  IN OUT UINTN * pPollCount,

+  OUT BOOLEAN * pbComplete,

+  OUT BOOLEAN * pbLinkUp,

+  OUT BOOLEAN * pbHiSpeed,

+  OUT BOOLEAN * pbFullDuplex

+  );

+

+/**

+  Read a register from the PHY

+

+  This routine calls ::Ax88772UsbCommand to read a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in, out] pPhyData    Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data is available.

+  @retval other                The PHY data is not valid.

+

+**/

+EFI_STATUS

+Ax88772PhyRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN OUT UINT16 * pPhyData

+  );

+

+/**

+  Write to a PHY register

+

+  This routine calls ::Ax88772UsbCommand to write a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in] PhyData          Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data was written.

+  @retval other                Failed to wwrite the PHY register.

+

+**/

+EFI_STATUS

+Ax88772PhyWrite (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN UINT16 PhyData

+  );

+

+/**

+  Reset the AX88772

+

+  This routine uses ::Ax88772UsbCommand to reset the network

+  adapter.  This routine also uses ::Ax88772PhyWrite to reset

+  the PHY.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772Reset (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  Receive a frame from the network.

+

+  This routine polls the USB receive interface for a packet.  If a packet

+  is available, this routine adds the receive packet to the list of

+  pending receive packets.

+

+  This routine calls ::Ax88772NegotiateLinkComplete to verify

+  that the link is up.  This routine also calls ::SN_Reset to

+  reset the network adapter when necessary.  Finally this

+  routine attempts to receive one or more packets from the

+  network adapter.

+

+  @param [in] pNicDevice  Pointer to the NIC_DEVICE structure

+  @param [in] bUpdateLink TRUE = Update link status

+

+**/

+VOID

+Ax88772Rx (

+  IN NIC_DEVICE * pNicDevice,

+  IN BOOLEAN bUpdateLink

+  );

+

+/**

+  Enable or disable the receiver

+

+  This routine calls ::Ax88772UsbCommand to update the

+  receiver state.  This routine also calls ::Ax88772MacAddressSet

+  to establish the MAC address for the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RxFilter         Simple network RX filter mask value

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772RxControl (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 RxFilter

+  );

+

+/**

+  Read an SROM location

+

+  This routine calls ::Ax88772UsbCommand to read data from the

+  SROM.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] Address          SROM address

+  @param [out] pData           Buffer to receive the data

+

+  @retval EFI_SUCCESS          The read was successful

+  @retval other                The read failed

+

+**/

+EFI_STATUS

+Ax88772SromRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 Address,

+  OUT UINT16 * pData

+  );

+

+/**

+  This routine is called at a regular interval to poll for

+  receive packets.

+

+  This routine polls the link state and gets any receive packets

+  by calling ::Ax88772Rx.

+

+  @param [in] Event            Timer event

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+**/

+VOID

+Ax88772Timer (

+  IN EFI_EVENT Event,

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  Send a command to the USB device.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pRequest         Pointer to the request structure

+  @param [in, out] pBuffer     Data buffer address

+

+  @retval EFI_SUCCESS          The USB transfer was successful

+  @retval other                The USB transfer failed

+

+**/

+EFI_STATUS

+Ax88772UsbCommand (

+  IN NIC_DEVICE * pNicDevice,

+  IN USB_DEVICE_REQUEST * pRequest,

+  IN OUT VOID * pBuffer

+  );

+

+//------------------------------------------------------------------------------

+// EFI Component Name Protocol Support

+//------------------------------------------------------------------------------

+

+extern EFI_COMPONENT_NAME_PROTOCOL   gComponentName;  ///<  Component name protocol declaration

+extern EFI_COMPONENT_NAME2_PROTOCOL  gComponentName2; ///<  Component name 2 protocol declaration

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppDriverName     A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppDriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] ControllerHandle  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+  @param [in] ChildHandle       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppControllerName A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  EFI_HANDLE ControllerHandle,

+  IN OPTIONAL EFI_HANDLE ChildHandle,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppControllerName

+  );

+

+//------------------------------------------------------------------------------

+

+#endif  //  _AX88772_H_

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf
new file mode 100644
index 0000000..5507cbb
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf
@@ -0,0 +1,67 @@
+## @file

+# Component description file for ASIX AX88772 USB/Ethernet driver.

+#

+# This module provides support for the ASIX AX88772 USB/Ethernet adapter.

+# Copyright (c) 2011-2013, 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.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010018

+  BASE_NAME                      = Ax88772

+  FILE_GUID                      = B15239D6-6A01-4808-A0F7-B7F20F073555

+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER

+  VERSION_STRING                 = 1.0

+

+  ENTRY_POINT                    = EntryPoint

+

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+

+[Sources.common]

+  Ax88772.h

+  Ax88772.c

+  ComponentName.c

+  DriverBinding.c

+  SimpleNetwork.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+[LibraryClasses]

+  UefiLib

+  UefiBootServicesTableLib

+  BaseMemoryLib

+  DebugLib

+  UefiRuntimeLib

+  UefiDriverEntryPoint

+

+[Protocols]

+  gEfiDevicePathProtocolGuid           ## BY_START

+  gEfiSimpleNetworkProtocolGuid        ## BY_START

+  gEfiUsbIoProtocolGuid                ## TO_START

+

+[Depex]

+  gEfiBdsArchProtocolGuid AND

+  gEfiCpuArchProtocolGuid AND

+  gEfiMetronomeArchProtocolGuid AND

+  gEfiMonotonicCounterArchProtocolGuid AND

+  gEfiRealTimeClockArchProtocolGuid AND

+  gEfiResetArchProtocolGuid AND

+  gEfiRuntimeArchProtocolGuid AND

+  gEfiSecurityArchProtocolGuid AND

+  gEfiTimerArchProtocolGuid AND

+  gEfiVariableWriteArchProtocolGuid AND

+  gEfiVariableArchProtocolGuid AND

+  gEfiWatchdogTimerArchProtocolGuid

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName.c
new file mode 100644
index 0000000..8fceb60
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName.c
@@ -0,0 +1,184 @@
+/** @file

+  UEFI Component Name(2) protocol implementation.

+

+  Copyright (c) 2011, 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.

+

+**/

+

+#include "Ax88772.h"

+

+/**

+  EFI Component Name Protocol declaration

+**/

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gComponentName = {

+  GetDriverName,

+  GetControllerName,

+  "eng"

+};

+

+/**

+  EFI Component Name 2 Protocol declaration

+**/

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GetControllerName,

+  "en"

+};

+

+

+/**

+  Driver name table declaration

+**/

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE

+mDriverNameTable[] = {

+  {"eng;en", L"AX88772 Ethernet Driver"},

+  {NULL,  NULL}

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppDriverName     A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppDriverName

+  )

+{

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+  Status = LookupUnicodeString2 (

+             pLanguage,

+             pThis->SupportedLanguages,

+             mDriverNameTable,

+             ppDriverName,

+             (BOOLEAN)(pThis == &gComponentName)

+             );

+  DBG_EXIT_HEX ( Status );

+  return Status;

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] ControllerHandle  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+  @param [in] ChildHandle       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppControllerName A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  EFI_HANDLE ControllerHandle,

+  IN OPTIONAL EFI_HANDLE ChildHandle,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppControllerName

+  )

+{

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // Set the controller name

+  //

+  *ppControllerName = L"AX88772 10/100 Ethernet";

+  Status = EFI_SUCCESS;

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_HEX ( Status );

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c
new file mode 100644
index 0000000..a04abee
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c
@@ -0,0 +1,513 @@
+/** @file

+  Implement the driver binding protocol for Asix AX88772 Ethernet driver.

+

+  Copyright (c) 2011-2013, 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.

+

+**/

+

+#include "Ax88772.h"

+

+/**

+  Verify the controller type

+

+  @param [in] pThis                Protocol instance pointer.

+  @param [in] Controller           Handle of device to test.

+  @param [in] pRemainingDevicePath Not used.

+

+  @retval EFI_SUCCESS          This driver supports this device.

+  @retval other                This driver does not support this device.

+

+**/

+EFI_STATUS

+EFIAPI

+DriverSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL * pThis,

+  IN EFI_HANDLE Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath

+  )

+{

+  EFI_USB_DEVICE_DESCRIPTOR Device;

+  EFI_USB_IO_PROTOCOL * pUsbIo;

+  EFI_STATUS Status;

+

+  //

+  //  Connect to the USB stack

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &pUsbIo,

+                  pThis->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (!EFI_ERROR ( Status )) {

+

+    //

+    //  Get the interface descriptor to check the USB class and find a transport

+    //  protocol handler.

+    //

+    Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );

+    if (!EFI_ERROR ( Status )) {

+

+      //

+      //  Validate the adapter

+      //

+      if (( VENDOR_ID != Device.IdVendor )

+        || ( PRODUCT_ID != Device.IdProduct )) {

+        Status = EFI_UNSUPPORTED;

+      }

+    }

+

+    //

+    //  Done with the USB stack

+    //

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiUsbIoProtocolGuid,

+           pThis->DriverBindingHandle,

+           Controller

+           );

+  }

+

+  //

+  //  Return the device supported status

+  //

+  return Status;

+}

+

+

+/**

+  Start this driver on Controller by opening UsbIo and DevicePath protocols.

+  Initialize PXE structures, create a copy of the Controller Device Path with the

+  NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol

+  on the newly created Device Path.

+

+  @param [in] pThis                Protocol instance pointer.

+  @param [in] Controller           Handle of device to work with.

+  @param [in] pRemainingDevicePath Not used, always produce all possible children.

+

+  @retval EFI_SUCCESS          This driver is added to Controller.

+  @retval other                This driver does not support this device.

+

+**/

+EFI_STATUS

+EFIAPI

+DriverStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL * pThis,

+  IN EFI_HANDLE Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath

+  )

+{

+  EFI_STATUS Status;

+  NIC_DEVICE * pNicDevice;

+  UINTN LengthInBytes;

+

+  DBG_ENTER ( );

+

+  //

+  //  Allocate the device structure

+  //

+  LengthInBytes = sizeof ( *pNicDevice );

+  Status = gBS->AllocatePool (

+                  EfiRuntimeServicesData,

+                  LengthInBytes,

+                  (VOID **) &pNicDevice

+                  );

+  if ( !EFI_ERROR ( Status )) {

+    DEBUG (( DEBUG_POOL | DEBUG_INIT,

+              "0x%08x: Allocate pNicDevice, %d bytes\r\n",

+              pNicDevice,

+              sizeof ( *pNicDevice )));

+

+    //

+    //  Set the structure signature

+    //

+    ZeroMem ( pNicDevice, LengthInBytes );

+    pNicDevice->Signature = DEV_SIGNATURE;

+

+    //

+    //  Connect to the USB I/O protocol

+    //

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiUsbIoProtocolGuid,

+                    (VOID **) &pNicDevice->pUsbIo,

+                    pThis->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_BY_DRIVER

+                    );

+

+    if ( !EFI_ERROR ( Status )) {

+      //

+      //  Allocate the necessary events

+      //

+      Status = gBS->CreateEvent ( EVT_TIMER,

+                                  TPL_AX88772,

+                                  (EFI_EVENT_NOTIFY)Ax88772Timer,

+                                  pNicDevice,

+                                  (VOID **)&pNicDevice->Timer );

+      if ( !EFI_ERROR ( Status )) {

+        DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+                  "0x%08x: Allocated timer\r\n",

+                  pNicDevice->Timer ));

+

+        //

+        //  Initialize the simple network protocol

+        //

+        pNicDevice->Controller = Controller;

+        SN_Setup ( pNicDevice );

+

+        //

+        //  Start the timer

+        //

+        Status = gBS->SetTimer ( pNicDevice->Timer,

+                                 TimerPeriodic,

+                                 TIMER_MSEC );

+        if ( !EFI_ERROR ( Status )) {

+          //

+          //  Install both the simple network and device path protocols.

+          //

+          Status = gBS->InstallMultipleProtocolInterfaces (

+                          &Controller,

+                          &gEfiCallerIdGuid,

+                          pNicDevice,

+                          &gEfiSimpleNetworkProtocolGuid,

+                          &pNicDevice->SimpleNetwork,

+                          NULL

+                          );

+

+          if ( !EFI_ERROR ( Status )) {

+            DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+                      "Installed: gEfiCallerIdGuid on   0x%08x\r\n",

+                      Controller ));

+            DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+                      "Installed: gEfiSimpleNetworkProtocolGuid on   0x%08x\r\n",

+                      Controller ));

+            DBG_EXIT_STATUS ( Status );

+            return Status;

+          }

+          DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,

+                    "ERROR - Failed to install gEfiSimpleNetworkProtocol on 0x%08x\r\n",

+                    Controller ));

+        }

+        else {

+          DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,

+                    "ERROR - Failed to start the timer, Status: %r\r\n",

+                    Status ));

+        }

+      }

+      else {

+        DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,

+                  "ERROR - Failed to create timer event, Status: %r\r\n",

+                  Status ));

+      }

+

+      //

+      //  Done with the USB stack

+      //

+      gBS->CloseProtocol (

+             Controller,

+             &gEfiUsbIoProtocolGuid,

+             pThis->DriverBindingHandle,

+             Controller

+             );

+    }

+

+    //

+    //  Done with the device

+    //

+    gBS->FreePool ( pNicDevice );

+  }

+

+  //

+  //  Display the driver start status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and

+  closing the DevicePath and PciIo protocols on Controller.

+

+  @param [in] pThis                Protocol instance pointer.

+  @param [in] Controller           Handle of device to stop driver on.

+  @param [in] NumberOfChildren     How many children need to be stopped.

+  @param [in] pChildHandleBuffer   Not used.

+

+  @retval EFI_SUCCESS          This driver is removed Controller.

+  @retval EFI_DEVICE_ERROR     The device could not be stopped due to a device error.

+  @retval other                This driver was not removed from this device.

+

+**/

+EFI_STATUS

+EFIAPI

+DriverStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL * pThis,

+  IN  EFI_HANDLE Controller,

+  IN  UINTN NumberOfChildren,

+  IN  EFI_HANDLE * pChildHandleBuffer

+  )

+{

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Determine if this driver is already attached

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiCallerIdGuid,

+                  (VOID **) &pNicDevice,

+                  pThis->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                  );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  AX88772 driver is no longer running on this device

+    //

+    gBS->UninstallMultipleProtocolInterfaces (

+              Controller,

+              &gEfiSimpleNetworkProtocolGuid,

+              &pNicDevice->SimpleNetwork,

+              &gEfiCallerIdGuid,

+              pNicDevice,

+              NULL );

+    DEBUG (( DEBUG_POOL | DEBUG_INIT,

+                "Removed:   gEfiSimpleNetworkProtocolGuid from 0x%08x\r\n",

+                Controller ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT,

+                "Removed:   gEfiCallerIdGuid from 0x%08x\r\n",

+                Controller ));

+

+    //

+    //  Stop the timer

+    //

+    if ( NULL != pNicDevice->Timer ) {

+      gBS->SetTimer ( pNicDevice->Timer, TimerCancel, 0 );

+      gBS->CloseEvent ( pNicDevice->Timer );

+      DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+                "0x%08x: Released timer\r\n",

+                pNicDevice->Timer ));

+    }

+

+    //

+    //  Done with the device context

+    //

+    DEBUG (( DEBUG_POOL | DEBUG_INIT,

+              "0x%08x: Free pNicDevice, %d bytes\r\n",

+              pNicDevice,

+              sizeof ( *pNicDevice )));

+    gBS->FreePool ( pNicDevice );

+  }

+

+  //

+  //  Return the shutdown status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Driver binding protocol declaration

+**/

+EFI_DRIVER_BINDING_PROTOCOL  gDriverBinding = {

+  DriverSupported,

+  DriverStart,

+  DriverStop,

+  0xa,

+  NULL,

+  NULL

+};

+

+

+/**

+  Ax88772 driver unload routine.

+

+  @param [in] ImageHandle       Handle for the image.

+

+  @retval EFI_SUCCESS           Image may be unloaded

+

+**/

+EFI_STATUS

+EFIAPI

+DriverUnload (

+  IN EFI_HANDLE ImageHandle

+  )

+{

+  UINTN BufferSize;

+  UINTN Index;

+  UINTN Max;

+  EFI_HANDLE * pHandle;

+  EFI_STATUS Status;

+

+  //

+  //  Determine which devices are using this driver

+  //

+  BufferSize = 0;

+  pHandle = NULL;

+  Status = gBS->LocateHandle (

+                  ByProtocol,

+                  &gEfiCallerIdGuid,

+                  NULL,

+                  &BufferSize,

+                  NULL );

+  if ( EFI_BUFFER_TOO_SMALL == Status ) {

+    for ( ; ; ) {

+      //

+      //  One or more block IO devices are present

+      //

+      Status = gBS->AllocatePool (

+                      EfiRuntimeServicesData,

+                      BufferSize,

+                      (VOID **) &pHandle

+                      );

+      if ( EFI_ERROR ( Status )) {

+        DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+                  "Insufficient memory, failed handle buffer allocation\r\n" ));

+        break;

+      }

+

+      //

+      //  Locate the block IO devices

+      //

+      Status = gBS->LocateHandle (

+                      ByProtocol,

+                      &gEfiCallerIdGuid,

+                      NULL,

+                      &BufferSize,

+                      pHandle );

+      if ( EFI_ERROR ( Status )) {

+        //

+        //  Error getting handles

+        //

+        DEBUG (( DEBUG_ERROR | DEBUG_INIT | DEBUG_INFO,

+                "Failure getting Telnet handles\r\n" ));

+        break;

+      }

+      

+      //

+      //  Remove any use of the driver

+      //

+      Max = BufferSize / sizeof ( pHandle[ 0 ]);

+      for ( Index = 0; Max > Index; Index++ ) {

+        Status = DriverStop ( &gDriverBinding,

+                              pHandle[ Index ],

+                              0,

+                              NULL );

+        if ( EFI_ERROR ( Status )) {

+          DEBUG (( DEBUG_WARN | DEBUG_INIT | DEBUG_INFO,

+                    "WARNING - Failed to shutdown the driver on handle %08x\r\n", pHandle[ Index ]));

+          break;

+        }

+      }

+      break;

+    }

+  }

+  else {

+    if ( EFI_NOT_FOUND == Status ) {

+      //

+      //  No devices were found

+      //

+      Status = EFI_SUCCESS;

+    }

+  }

+

+  //

+  //  Free the handle array

+  //

+  if ( NULL != pHandle ) {

+    gBS->FreePool ( pHandle );

+  }

+

+  //

+  //  Remove the protocols installed by the EntryPoint routine.

+  //

+  if ( !EFI_ERROR ( Status )) {

+    gBS->UninstallMultipleProtocolInterfaces (

+            ImageHandle,

+            &gEfiDriverBindingProtocolGuid,

+            &gDriverBinding,

+            &gEfiComponentNameProtocolGuid,

+            &gComponentName,

+            &gEfiComponentName2ProtocolGuid,

+            &gComponentName2,

+            NULL

+            );

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+            "Removed:   gEfiComponentName2ProtocolGuid from 0x%08x\r\n",

+            ImageHandle ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Removed:   gEfiComponentNameProtocolGuid from 0x%08x\r\n",

+              ImageHandle ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Removed:   gEfiDriverBindingProtocolGuid from 0x%08x\r\n",

+              ImageHandle ));

+  }

+

+  //

+  //  Return the unload status

+  //

+  return Status;

+}

+

+

+/**

+Ax88772 driver entry point.

+

+@param [in] ImageHandle       Handle for the image.

+@param [in] pSystemTable      Address of the system table.

+

+@retval EFI_SUCCESS           Image successfully loaded.

+

+**/

+EFI_STATUS

+EFIAPI

+EntryPoint (

+  IN EFI_HANDLE ImageHandle,

+  IN EFI_SYSTEM_TABLE * pSystemTable

+  )

+{

+  EFI_STATUS    Status;

+

+  DBG_ENTER ( );

+

+  //

+  //  Add the driver to the list of drivers

+  //

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             pSystemTable,

+             &gDriverBinding,

+             ImageHandle,

+             &gComponentName,

+             &gComponentName2

+             );

+  ASSERT_EFI_ERROR (Status);

+  if ( !EFI_ERROR ( Status )) {

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Installed: gEfiDriverBindingProtocolGuid on   0x%08x\r\n",

+              ImageHandle ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Installed: gEfiComponentNameProtocolGuid on   0x%08x\r\n",

+              ImageHandle ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Installed: gEfiComponentName2ProtocolGuid on   0x%08x\r\n",

+              ImageHandle ));

+  }

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c
new file mode 100644
index 0000000..a341f3b
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c
@@ -0,0 +1,1509 @@
+/** @file

+  Provides the Simple Network functions.

+

+  Copyright (c) 2011, 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.

+

+**/

+

+#include "Ax88772.h"

+

+/**

+  This function updates the filtering on the receiver.

+

+  This support routine calls ::Ax88772MacAddressSet to update

+  the MAC address.  This routine then rebuilds the multicast

+  hash by calling ::Ax88772MulticastClear and ::Ax88772MulticastSet.

+  Finally this routine enables the receiver by calling

+  ::Ax88772RxControl.

+

+  @param [in] pSimpleNetwork    Simple network mode pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+ReceiveFilterUpdate (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+  UINT32 Index;

+

+  DBG_ENTER ( );

+

+  //

+  // Set the MAC address

+  //

+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+  pMode = pSimpleNetwork->Mode;

+  Status = Ax88772MacAddressSet ( pNicDevice,

+                                  &pMode->CurrentAddress.Addr[0]);

+  if ( !EFI_ERROR ( Status )) {

+    //

+    // Clear the multicast hash table

+    //

+    Ax88772MulticastClear ( pNicDevice );

+

+    //

+    // Load the multicast hash table

+    //

+    if ( 0 != ( pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {

+      for ( Index = 0;

+            ( !EFI_ERROR ( Status )) && ( Index < pMode->MCastFilterCount );

+            Index++ ) {

+        //

+        // Enable the next multicast address

+        //

+        Ax88772MulticastSet ( pNicDevice,

+                              &pMode->MCastFilter[ Index ].Addr[0]);

+      }

+    }

+

+    //

+    // Enable the receiver

+    //

+    if ( !EFI_ERROR ( Status )) {

+      Status = Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSetting );

+    }

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function updates the SNP driver status.

+  

+  This function gets the current interrupt and recycled transmit

+  buffer status from the network interface.  The interrupt status

+  and the media status are returned as a bit mask in InterruptStatus.

+  If InterruptStatus is NULL, the interrupt status will not be read.

+  Upon successful return of the media status, the MediaPresent field

+  of EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change

+  of media status.  If TxBuf is not NULL, a recycled transmit buffer

+  address will be retrived.  If a recycled transmit buffer address

+  is returned in TxBuf, then the buffer has been successfully

+  transmitted, and the status for that buffer is cleared.

+

+  This function calls ::Ax88772Rx to update the media status and

+  queue any receive packets.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] pInterruptStatus  A pointer to the bit mask of the current active interrupts.

+                                If this is NULL, the interrupt status will not be read from

+                                the device.  If this is not NULL, the interrupt status will

+                                be read from teh device.  When the interrupt status is read,

+                                it will also be cleared.  Clearing the transmit interrupt

+                                does not empty the recycled transmit buffer array.

+  @param [out] ppTxBuf          Recycled transmit buffer address.  The network interface will

+                                not transmit if its internal recycled transmit buffer array is

+                                full.  Reading the transmit buffer does not clear the transmit

+                                interrupt.  If this is NULL, then the transmit buffer status

+                                will not be read.  If there are not transmit buffers to recycle

+                                and TxBuf is not NULL, *TxBuf will be set to NULL.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_GetStatus (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  OUT UINT32 * pInterruptStatus,

+  OUT VOID ** ppTxBuf

+  )

+{

+  BOOLEAN bLinkIdle;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+

+  DBG_ENTER ( );

+

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Return the transmit buffer

+    //

+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+    if (( NULL != ppTxBuf ) && ( NULL != pNicDevice->pTxBuffer )) {

+      *ppTxBuf = pNicDevice->pTxBuffer;

+      pNicDevice->pTxBuffer = NULL;

+    }

+

+    //

+    // Determine if interface is running

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStopped != pMode->State ) {

+      //

+      //  Synchronize with Ax88772Timer

+      //

+      VERIFY_TPL ( TPL_AX88772 );

+      TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );

+

+      //

+      // Update the link status

+      //

+      bLinkIdle = pNicDevice->bLinkIdle;

+      pNicDevice->bLinkIdle = TRUE;

+      Ax88772Rx ( pNicDevice, bLinkIdle );

+      pMode->MediaPresent = pNicDevice->bLinkUp;

+

+      //

+      //  Release the synchronization with Ax88772Timer

+      //

+      gBS->RestoreTPL ( TplPrevious );

+

+      //

+      // Return the interrupt status

+      //

+      if ( NULL != pInterruptStatus ) {

+        *pInterruptStatus = 0;

+      }

+      Status = EFI_SUCCESS;

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Resets the network adapter and allocates the transmit and receive buffers

+  required by the network interface; optionally, also requests allocation of

+  additional transmit and receive buffers.  This routine must be called before

+  any other routine in the Simple Network protocol is called.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] ExtraRxBufferSize Size in bytes to add to the receive buffer allocation

+  @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buffer allocation

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_OUT_OF_RESORUCES  There was not enough memory for the transmit and receive buffers

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Initialize (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN ExtraRxBufferSize,

+  IN UINTN ExtraTxBufferSize

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+  

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Determine if the interface is already started

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStarted == pMode->State ) {

+      if (( 0 == ExtraRxBufferSize ) && ( 0 == ExtraTxBufferSize )) {

+        //

+        // Start the adapter

+        //

+        Status = SN_Reset ( pSimpleNetwork, FALSE );

+        if ( !EFI_ERROR ( Status )) {

+          //

+          // Update the network state

+          //

+          pMode->State = EfiSimpleNetworkInitialized;

+        }

+      }

+      else {

+        Status = EFI_UNSUPPORTED;

+      }

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function converts a multicast IP address to a multicast HW MAC address

+  for all packet transactions.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bIPv6             Set to TRUE if the multicast IP address is IPv6 [RFC2460].

+                                Set to FALSE if the multicast IP address is IPv4 [RFC 791].

+  @param [in] pIP               The multicast IP address that is to be converted to a

+                                multicast HW MAC address.

+  @param [in] pMAC              The multicast HW MAC address that is to be generated from IP.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_MCastIPtoMAC (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bIPv6,

+  IN EFI_IP_ADDRESS * pIP,

+  IN EFI_MAC_ADDRESS * pMAC

+  )

+{

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // This is not currently supported

+  //

+  Status = EFI_UNSUPPORTED;

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function performs read and write operations on the NVRAM device

+  attached to a network interface.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] ReadWrite         TRUE for read operations, FALSE for write operations.

+  @param [in] Offset            Byte offset in the NVRAM device at which to start the

+                                read or write operation.  This must be a multiple of

+                                NvRamAccessSize and less than NvRamSize.

+  @param [in] BufferSize        The number of bytes to read or write from the NVRAM device.

+                                This must also be a multiple of NvramAccessSize.

+  @param [in, out] pBuffer      A pointer to the data buffer.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_NvData (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN ReadWrite,

+  IN UINTN Offset,

+  IN UINTN BufferSize,

+  IN OUT VOID * pBuffer

+  )

+{

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // This is not currently supported

+  //

+  Status = EFI_UNSUPPORTED;

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Attempt to receive a packet from the network adapter.

+

+  This function retrieves one packet from the receive queue of the network

+  interface.  If there are no packets on the receive queue, then EFI_NOT_READY

+  will be returned.  If there is a packet on the receive queue, and the size

+  of the packet is smaller than BufferSize, then the contents of the packet

+  will be placed in Buffer, and BufferSize will be udpated with the actual

+  size of the packet.  In addition, if SrcAddr, DestAddr, and Protocol are

+  not NULL, then these values will be extracted from the media header and

+  returned.  If BufferSize is smaller than the received packet, then the

+  size of the receive packet will be placed in BufferSize and

+  EFI_BUFFER_TOO_SMALL will be returned.

+

+  This routine calls ::Ax88772Rx to update the media status and

+  empty the network adapter of receive packets.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [out] pHeaderSize      The size, in bytes, of the media header to be filled in by

+                                the Transmit() function.  If HeaderSize is non-zero, then

+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize

+                                and DestAddr and Protocol parameters must not be NULL.

+  @param [out] pBufferSize      The size, in bytes, of the entire packet (media header and

+                                data) to be transmitted through the network interface.

+  @param [out] pBuffer          A pointer to the packet (media header followed by data) to

+                                to be transmitted.  This parameter can not be NULL.  If

+                                HeaderSize is zero, then the media header is Buffer must

+                                already be filled in by the caller.  If HeaderSize is nonzero,

+                                then the media header will be filled in by the Transmit()

+                                function.

+  @param [out] pSrcAddr         The source HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.  If HeaderSize is nonzero and

+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress

+                                is used for the source HW MAC address.

+  @param [out] pDestAddr        The destination HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.

+  @param [out] pProtocol        The type of header to build.  If HeaderSize is zero, then

+                                this parameter is ignored.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_NOT_READY         No packets have been received on the network interface.

+  @retval EFI_BUFFER_TOO_SMALL  The packet is larger than BufferSize bytes.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Receive (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  OUT UINTN                      * pHeaderSize,

+  OUT UINTN                      * pBufferSize,

+  OUT VOID                       * pBuffer,

+  OUT EFI_MAC_ADDRESS            * pSrcAddr,

+  OUT EFI_MAC_ADDRESS            * pDestAddr,

+  OUT UINT16                     * pProtocol

+  )

+{

+  ETHERNET_HEADER * pHeader;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  RX_TX_PACKET * pRxPacket;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  UINT16 Type;

+

+  DBG_ENTER ( );

+

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // The interface must be running

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+      //

+      //  Synchronize with Ax88772Timer

+      //

+      VERIFY_TPL ( TPL_AX88772 );

+      TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );

+

+      //

+      // Update the link status

+      //

+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+      Ax88772Rx ( pNicDevice, FALSE );

+      pMode->MediaPresent = pNicDevice->bLinkUp;

+      if ( pMode->MediaPresent ) {

+        //

+        //  Attempt to receive a packet

+        //

+        pRxPacket = pNicDevice->pRxHead;

+        if ( NULL != pRxPacket ) {

+          pNicDevice->pRxHead = pRxPacket->pNext;

+          if ( NULL == pNicDevice->pRxHead ) {

+            pNicDevice->pRxTail = NULL;

+          }

+

+          //

+          // Copy the received packet into the receive buffer

+          //

+          *pBufferSize = pRxPacket->Length;

+          CopyMem ( pBuffer, &pRxPacket->Data[0], pRxPacket->Length );

+          pHeader = (ETHERNET_HEADER *) &pRxPacket->Data[0];

+          if ( NULL != pHeaderSize ) {

+            *pHeaderSize = sizeof ( *pHeader );

+          }

+          if ( NULL != pDestAddr ) {

+            CopyMem ( pDestAddr, &pHeader->dest_addr, PXE_HWADDR_LEN_ETHER );

+          }

+          if ( NULL != pSrcAddr ) {

+            CopyMem ( pSrcAddr, &pHeader->src_addr, PXE_HWADDR_LEN_ETHER );

+          }

+          if ( NULL != pProtocol ) {

+            Type = pHeader->type;

+            Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));

+            *pProtocol = Type;

+          }

+          Status = EFI_SUCCESS;

+        }

+        else {

+          //

+          //  No receive packets available

+          //

+          Status = EFI_NOT_READY;

+        }

+      }

+      else {

+        //

+        //  Link no up

+        //

+        Status = EFI_NOT_READY;

+      }

+

+      //

+      //  Release the synchronization with Ax88772Timer

+      //

+      gBS->RestoreTPL ( TplPrevious );

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function is used to enable and disable the hardware and software receive

+  filters for the underlying network device.

+

+  The receive filter change is broken down into three steps:

+

+    1.  The filter mask bits that are set (ON) in the Enable parameter

+        are added to the current receive filter settings.

+

+    2.  The filter mask bits that are set (ON) in the Disable parameter

+        are subtracted from the updated receive filter settins.

+

+    3.  If the resulting filter settigns is not supported by the hardware

+        a more liberal setting is selected.

+

+  If the same bits are set in the Enable and Disable parameters, then the bits

+  in the Disable parameter takes precedence.

+

+  If the ResetMCastFilter parameter is TRUE, then the multicast address list

+  filter is disabled (irregardless of what other multicast bits are set in

+  the enable and Disable parameters).  The SNP->Mode->MCastFilterCount field

+  is set to zero.  The SNP->Mode->MCastFilter contents are undefined.

+

+  After enableing or disabling receive filter settings, software should

+  verify the new settings by checking the SNP->Mode->ReceeiveFilterSettings,

+  SNP->Mode->MCastFilterCount and SNP->Mode->MCastFilter fields.

+

+  Note: Some network drivers and/or devices will automatically promote

+  receive filter settings if the requested setting can not be honored.

+  For example, if a request for four multicast addresses is made and

+  the underlying hardware only supports two multicast addresses the

+  driver might set the promiscuous or promiscuous multicast receive filters

+  instead.  The receiving software is responsible for discarding any extra

+  packets that get through the hardware receive filters.

+

+  If ResetMCastFilter is TRUE, then the multicast receive filter list

+  on the network interface will be reset to the default multicast receive

+  filter list.  If ResetMCastFilter is FALSE, and this network interface

+  allows the multicast receive filter list to be modified, then the

+  MCastFilterCnt and MCastFilter are used to update the current multicast

+  receive filter list.  The modified receive filter list settings can be

+  found in the MCastFilter field of EFI_SIMPLE_NETWORK_MODE.

+

+  This routine calls ::ReceiveFilterUpdate to update the receive

+  state in the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] Enable            A bit mask of receive filters to enable on the network interface.

+  @param [in] Disable           A bit mask of receive filters to disable on the network interface.

+                                For backward compatibility with EFI 1.1 platforms, the

+                                EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit must be set

+                                when the ResetMCastFilter parameter is TRUE.

+  @param [in] bResetMCastFilter Set to TRUE to reset the contents of the multicast receive

+                                filters on the network interface to their default values.

+  @param [in] MCastFilterCnt    Number of multicast HW MAC address in the new MCastFilter list.

+                                This value must be less than or equal to the MaxMCastFilterCnt

+                                field of EFI_SIMPLE_NETWORK_MODE.  This field is optional if

+                                ResetMCastFilter is TRUE.

+  @param [in] pMCastFilter      A pointer to a list of new multicast receive filter HW MAC

+                                addresses.  This list will replace any existing multicast

+                                HW MAC address list.  This field is optional if ResetMCastFilter

+                                is TRUE.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_ReceiveFilters (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINT32 Enable,

+  IN UINT32 Disable,

+  IN BOOLEAN bResetMCastFilter,

+  IN UINTN MCastFilterCnt,

+  IN EFI_MAC_ADDRESS * pMCastFilter

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_MAC_ADDRESS * pMulticastAddress;

+  EFI_MAC_ADDRESS * pTableEnd;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // Verify the parameters

+  //

+  Status = EFI_INVALID_PARAMETER;

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    pMode = pSimpleNetwork->Mode;

+

+    //

+    //  Update the multicast list if necessary

+    //

+    if ( !bResetMCastFilter ) {

+      if ( 0 != MCastFilterCnt ) {

+        if (( MAX_MCAST_FILTER_CNT >= MCastFilterCnt )

+          && ( NULL != pMCastFilter )) {

+          //

+          // Verify the multicast addresses

+          //

+          pMulticastAddress = pMCastFilter;

+          pTableEnd = pMulticastAddress + MCastFilterCnt;

+          while ( pTableEnd > pMulticastAddress ) {

+            //

+            // The first digit of the multicast address must have the LSB set

+            //

+            if ( 0 == ( pMulticastAddress->Addr[0] & 1 )) {

+              //

+              // Invalid multicast address

+              //

+              break;

+            }

+            pMulticastAddress += 1;

+          }

+          if ( pTableEnd == pMulticastAddress ) {

+            //

+            // Update the multicast filter list.

+            //

+            CopyMem (&pMode->MCastFilter[0],

+                     pMCastFilter,

+                     MCastFilterCnt * sizeof ( *pMCastFilter ));

+            Status = EFI_SUCCESS;

+          }

+        }

+      }

+      else {

+        Status = EFI_SUCCESS;

+      }

+    }

+    else {

+      //

+      // No multicast address list is specified

+      //

+      MCastFilterCnt = 0;

+      Status = EFI_SUCCESS;

+    }

+    if ( !EFI_ERROR ( Status )) {

+      //

+      // The parameters are valid!

+      //

+      pMode->ReceiveFilterSetting |= Enable;

+      pMode->ReceiveFilterSetting &= ~Disable;

+      pMode->MCastFilterCount = (UINT32)MCastFilterCnt;

+

+      //

+      // Update the receive filters in the adapter

+      //

+      Status = ReceiveFilterUpdate ( pSimpleNetwork );

+    }

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Reset the network adapter.

+

+  Resets a network adapter and reinitializes it with the parameters that

+  were provided in the previous call to Initialize ().  The transmit and

+  receive queues are cleared.  Receive filters, the station address, the

+  statistics, and the multicast-IP-to-HW MAC addresses are not reset by

+  this call.

+

+  This routine calls ::Ax88772Reset to perform the adapter specific

+  reset operation.  This routine also starts the link negotiation

+  by calling ::Ax88772NegotiateLinkStart.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bExtendedVerification  Indicates that the driver may perform a more

+                                exhaustive verification operation of the device

+                                during reset.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Reset (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bExtendedVerification

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  RX_TX_PACKET * pRxPacket;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+

+  DBG_ENTER ( );

+

+  //

+  //  Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    //  Synchronize with Ax88772Timer

+    //

+    VERIFY_TPL ( TPL_AX88772 );

+    TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );

+

+    //

+    //  Update the device state

+    //

+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+    pNicDevice->bComplete = FALSE;

+    pNicDevice->bLinkUp = FALSE;

+

+    pMode = pSimpleNetwork->Mode;

+    pMode->MediaPresent = FALSE;

+

+    //

+    //  Discard any received packets

+    //

+    while ( NULL != pNicDevice->pRxHead ) {

+      //

+      //  Remove the packet from the received packet list

+      //

+      pRxPacket = pNicDevice->pRxHead;

+      pNicDevice->pRxHead = pRxPacket->pNext;

+

+      //

+      //  Queue the packet to the free list

+      //

+      pRxPacket->pNext = pNicDevice->pRxFree;

+      pNicDevice->pRxFree = pRxPacket;

+    }

+    pNicDevice->pRxTail = NULL;

+

+    //

+    //  Reset the device

+    //

+    Status = Ax88772Reset ( pNicDevice );

+    if ( !EFI_ERROR ( Status )) {

+      //

+      //  Update the receive filters in the adapter

+      //

+      Status = ReceiveFilterUpdate ( pSimpleNetwork );

+

+      //

+      //  Try to get a connection to the network

+      //

+      if ( !EFI_ERROR ( Status )) {

+        //

+        //  Start the autonegotiation

+        //

+        Status = Ax88772NegotiateLinkStart ( pNicDevice );

+      }

+    }

+

+    //

+    //  Release the synchronization with Ax88772Timer

+    //

+    gBS->RestoreTPL ( TplPrevious );

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Initialize the simple network protocol.

+

+  This routine calls ::Ax88772MacAddressGet to obtain the

+  MAC address.

+

+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer

+

+  @retval EFI_SUCCESS     Setup was successful

+

+**/

+EFI_STATUS

+SN_Setup (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // Initialize the simple network protocol

+  //

+  pSimpleNetwork = &pNicDevice->SimpleNetwork;

+  pSimpleNetwork->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;

+  pSimpleNetwork->Start = (EFI_SIMPLE_NETWORK_START)SN_Start;

+  pSimpleNetwork->Stop = (EFI_SIMPLE_NETWORK_STOP)SN_Stop;

+  pSimpleNetwork->Initialize = (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize;

+  pSimpleNetwork->Reset = (EFI_SIMPLE_NETWORK_RESET)SN_Reset;

+  pSimpleNetwork->Shutdown = (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown;

+  pSimpleNetwork->ReceiveFilters = (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters;

+  pSimpleNetwork->StationAddress = (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress;

+  pSimpleNetwork->Statistics = (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics;

+  pSimpleNetwork->MCastIpToMac = (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC;

+  pSimpleNetwork->NvData = (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData;

+  pSimpleNetwork->GetStatus = (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus;

+  pSimpleNetwork->Transmit = (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit;

+  pSimpleNetwork->Receive = (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive;

+  pSimpleNetwork->WaitForPacket = NULL;

+  pMode = &pNicDevice->SimpleNetworkData;

+  pSimpleNetwork->Mode = pMode;

+

+  pMode->State = EfiSimpleNetworkStopped;

+  pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;

+  pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );

+  pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;

+  pMode->NvRamSize = 0;

+  pMode->NvRamAccessSize = 0;

+  pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST

+                           | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST

+                           | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST

+                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS

+                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;

+  pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST

+                              | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;

+  pMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;

+  pMode->MCastFilterCount = 0;

+  SetMem ( &pMode->BroadcastAddress,

+           PXE_HWADDR_LEN_ETHER,

+           0xff );

+  pMode->IfType = EfiNetworkInterfaceUndi;

+  pMode->MacAddressChangeable = TRUE;

+  pMode->MultipleTxSupported = TRUE;

+  pMode->MediaPresentSupported = TRUE;

+  pMode->MediaPresent = FALSE;

+

+  //

+  //  Read the MAC address

+  //

+  pNicDevice->PhyId = PHY_ID_INTERNAL;

+  pNicDevice->b100Mbps = TRUE;

+  pNicDevice->bFullDuplex = TRUE;

+

+  Status = gBS->AllocatePool ( EfiRuntimeServicesData, 

+                               MAX_BULKIN_SIZE,

+                               (VOID **) &pNicDevice->pBulkInBuff);

+  if ( EFI_ERROR(Status)) {

+    DEBUG (( EFI_D_ERROR, "Memory are not enough\n"));

+    return Status;

+  }

+        

+  Status = Ax88772MacAddressGet (

+                pNicDevice,

+                &pMode->PermanentAddress.Addr[0]);

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  Display the MAC address

+    //

+    DEBUG (( DEBUG_MAC_ADDRESS | DEBUG_INFO,

+              "MAC: %02x-%02x-%02x-%02x-%02x-%02x\n",

+              pMode->PermanentAddress.Addr[0],

+              pMode->PermanentAddress.Addr[1],

+              pMode->PermanentAddress.Addr[2],

+              pMode->PermanentAddress.Addr[3],

+              pMode->PermanentAddress.Addr[4],

+              pMode->PermanentAddress.Addr[5]));

+

+    //

+    //  Use the hardware address as the current address

+    //

+    CopyMem ( &pMode->CurrentAddress,

+              &pMode->PermanentAddress,

+              PXE_HWADDR_LEN_ETHER );

+  }

+

+  //

+  //  Return the setup status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This routine starts the network interface.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_ALREADY_STARTED   The network interface was already started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Start (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  NIC_DEVICE * pNicDevice;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  // Verify the parameters

+  //

+  Status = EFI_INVALID_PARAMETER;

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStopped == pMode->State ) {

+      //

+      // Initialize the mode structure

+      // NVRAM access is not supported

+      //

+      ZeroMem ( pMode, sizeof ( *pMode ));

+  

+      pMode->State = EfiSimpleNetworkStarted;

+      pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;

+      pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );

+      pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;

+      pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST

+                               | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST

+                               | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST

+                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS

+                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;

+      pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;

+      pMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;

+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+      Status = Ax88772MacAddressGet ( pNicDevice, &pMode->PermanentAddress.Addr[0]);

+      CopyMem ( &pMode->CurrentAddress,

+                &pMode->PermanentAddress,

+                sizeof ( pMode->CurrentAddress ));

+      pMode->BroadcastAddress.Addr[0] = 0xff;

+      pMode->BroadcastAddress.Addr[1] = 0xff;

+      pMode->BroadcastAddress.Addr[2] = 0xff;

+      pMode->BroadcastAddress.Addr[3] = 0xff;

+      pMode->BroadcastAddress.Addr[4] = 0xff;

+      pMode->BroadcastAddress.Addr[5] = 0xff;

+      pMode->IfType = 1;

+      pMode->MacAddressChangeable = TRUE;

+      pMode->MultipleTxSupported = TRUE;

+      pMode->MediaPresentSupported = TRUE;

+      pMode->MediaPresent = FALSE;

+    }

+    else {

+      Status = EFI_ALREADY_STARTED;

+    }

+  }

+  

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Set the MAC address.

+  

+  This function modifies or resets the current station address of a

+  network interface.  If Reset is TRUE, then the current station address

+  is set ot the network interface's permanent address.  If Reset if FALSE

+  then the current station address is changed to the address specified by

+  pNew.

+

+  This routine calls ::Ax88772MacAddressSet to update the MAC address

+  in the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Flag used to reset the station address to the

+                                network interface's permanent address.

+  @param [in] pNew              New station address to be used for the network

+                                interface.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_StationAddress (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN EFI_MAC_ADDRESS * pNew

+  )

+{

+  NIC_DEVICE * pNicDevice;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork )

+    && ( NULL != pSimpleNetwork->Mode )

+    && (( !bReset ) || ( bReset && ( NULL != pNew )))) {

+    //

+    // Verify that the adapter is already started

+    //

+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStarted == pMode->State ) {

+      //

+      // Determine the adapter MAC address

+      //

+      if ( bReset ) {

+        //

+        // Use the permanent address

+        //

+        CopyMem ( &pMode->CurrentAddress,

+                  &pMode->PermanentAddress,

+                  sizeof ( pMode->CurrentAddress ));

+      }

+      else {

+        //

+        // Use the specified address

+        //

+        CopyMem ( &pMode->CurrentAddress,

+                  pNew,

+                  sizeof ( pMode->CurrentAddress ));

+      }

+

+      //

+      // Update the address on the adapter

+      //

+      Status = Ax88772MacAddressSet ( pNicDevice, &pMode->CurrentAddress.Addr[0]);

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function resets or collects the statistics on a network interface.

+  If the size of the statistics table specified by StatisticsSize is not

+  big enough for all of the statistics that are collected by the network

+  interface, then a partial buffer of statistics is returned in

+  StatisticsTable.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.

+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output

+                                the size, in bytes, of the resulting table of statistics.

+  @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that

+                                conains the statistics.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_BUFFER_TOO_SMALL  The pStatisticsTable is NULL or the buffer is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Statistics (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN OUT UINTN * pStatisticsSize,

+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable

+  )

+{

+  EFI_STATUS Status;

+

+  DBG_ENTER ( );

+

+  //

+  // This is not currently supported

+  //

+  Status = EFI_UNSUPPORTED;

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function stops a network interface.  This call is only valid

+  if the network interface is in the started state.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Stop (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Determine if the interface is started

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStopped != pMode->State ) {

+      if ( EfiSimpleNetworkStarted == pMode->State ) {

+        //

+        //  Release the resources acquired in SN_Start

+        //

+

+        //

+        //  Mark the adapter as stopped

+        //

+        pMode->State = EfiSimpleNetworkStopped;

+        Status = EFI_SUCCESS;

+      }

+      else {

+        Status = EFI_UNSUPPORTED;

+      }

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  This function releases the memory buffers assigned in the Initialize() call.

+  Pending transmits and receives are lost, and interrupts are cleared and disabled.

+  After this call, only Initialize() and Stop() calls may be used.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Shutdown (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  UINT32 RxFilter;

+  EFI_STATUS Status;

+  

+  DBG_ENTER ( );

+  

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Determine if the interface is already started

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+      //

+      // Stop the adapter

+      //

+      RxFilter = pMode->ReceiveFilterSetting;

+      pMode->ReceiveFilterSetting = 0;

+      Status = SN_Reset ( pSimpleNetwork, FALSE );

+      pMode->ReceiveFilterSetting = RxFilter;

+      if ( !EFI_ERROR ( Status )) {

+        //

+        // Release the resources acquired by SN_Initialize

+        //

+

+        //

+        // Update the network state

+        //

+        pMode->State = EfiSimpleNetworkStarted;

+      }

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

+

+

+/**

+  Send a packet over the network.

+

+  This function places the packet specified by Header and Buffer on

+  the transmit queue.  This function performs a non-blocking transmit

+  operation.  When the transmit is complete, the buffer is returned

+  via the GetStatus() call.

+

+  This routine calls ::Ax88772Rx to empty the network adapter of

+  receive packets.  The routine then passes the transmit packet

+  to the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by

+                                the Transmit() function.  If HeaderSize is non-zero, then

+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize

+                                and DestAddr and Protocol parameters must not be NULL.

+  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and

+                                data) to be transmitted through the network interface.

+  @param [in] pBuffer           A pointer to the packet (media header followed by data) to

+                                to be transmitted.  This parameter can not be NULL.  If

+                                HeaderSize is zero, then the media header is Buffer must

+                                already be filled in by the caller.  If HeaderSize is nonzero,

+                                then the media header will be filled in by the Transmit()

+                                function.

+  @param [in] pSrcAddr          The source HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.  If HeaderSize is nonzero and

+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress

+                                is used for the source HW MAC address.

+  @param [in] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.

+  @param [in] pProtocol         The type of header to build.  If HeaderSize is zero, then

+                                this parameter is ignored.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.

+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Transmit (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN HeaderSize,

+  IN UINTN BufferSize,

+  IN VOID * pBuffer,

+  IN EFI_MAC_ADDRESS * pSrcAddr,

+  IN EFI_MAC_ADDRESS * pDestAddr,

+  IN UINT16 * pProtocol

+  )

+{

+  RX_TX_PACKET Packet;

+  ETHERNET_HEADER * pHeader;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_USB_IO_PROTOCOL * pUsbIo;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  UINTN TransferLength;

+  UINT32 TransferStatus;

+  UINT16 Type;

+

+  DBG_ENTER ( );

+

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // The interface must be running

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+      //

+      //  Synchronize with Ax88772Timer

+      //

+      VERIFY_TPL ( TPL_AX88772 );

+      TplPrevious = gBS->RaiseTPL ( TPL_AX88772 );

+

+      //

+      // Update the link status

+      //

+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+

+      //

+      //No need to call receive to receive packet

+      //

+      //Ax88772Rx ( pNicDevice, FALSE );

+      pMode->MediaPresent = pNicDevice->bLinkUp;

+

+      //

+      //  Release the synchronization with Ax88772Timer

+      //

+      gBS->RestoreTPL ( TplPrevious );

+      if ( pMode->MediaPresent ) {

+        //

+        //  Copy the packet into the USB buffer

+        //

+        CopyMem ( &Packet.Data[0], pBuffer, BufferSize );

+        Packet.Length = (UINT16) BufferSize;

+

+        //

+        //  Transmit the packet

+        //

+        pHeader = (ETHERNET_HEADER *) &Packet.Data[0];

+        if ( 0 != HeaderSize ) {

+          if ( NULL != pDestAddr ) {

+            CopyMem ( &pHeader->dest_addr, pDestAddr, PXE_HWADDR_LEN_ETHER );

+          }

+          if ( NULL != pSrcAddr ) {

+            CopyMem ( &pHeader->src_addr, pSrcAddr, PXE_HWADDR_LEN_ETHER );

+          }

+          else {

+            CopyMem ( &pHeader->src_addr, &pMode->CurrentAddress.Addr[0], PXE_HWADDR_LEN_ETHER );

+          }

+          if ( NULL != pProtocol ) {

+            Type = *pProtocol;

+          }

+          else {

+            Type = Packet.Length;

+          }

+          Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));

+          pHeader->type = Type;

+        }

+        if ( Packet.Length < MIN_ETHERNET_PKT_SIZE ) {

+          Packet.Length = MIN_ETHERNET_PKT_SIZE;

+          ZeroMem ( &Packet.Data[ BufferSize ],

+                    Packet.Length - BufferSize );

+        }

+        DEBUG (( DEBUG_TX | DEBUG_INFO,

+                  "TX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",

+                  Packet.Data[0],

+                  Packet.Data[1],

+                  Packet.Data[2],

+                  Packet.Data[3],

+                  Packet.Data[4],

+                  Packet.Data[5],

+                  Packet.Data[6],

+                  Packet.Data[7],

+                  Packet.Data[8],

+                  Packet.Data[9],

+                  Packet.Data[10],

+                  Packet.Data[11],

+                  Packet.Data[12],

+                  Packet.Data[13],

+                  Packet.Length ));

+        Packet.LengthBar = ~Packet.Length;

+        TransferLength = sizeof ( Packet.Length )

+                       + sizeof ( Packet.LengthBar )

+                       + Packet.Length;

+

+        //

+        //  Work around USB bus driver bug where a timeout set by receive

+        //  succeeds but the timeout expires immediately after, causing the

+        //  transmit operation to timeout.

+        //

+        pUsbIo = pNicDevice->pUsbIo;

+        Status = pUsbIo->UsbBulkTransfer ( pUsbIo,

+                                           BULK_OUT_ENDPOINT,

+                                           &Packet.Length,

+                                           &TransferLength,

+                                           0xfffffffe,

+                                           &TransferStatus );

+        if ( !EFI_ERROR ( Status )) {

+          Status = TransferStatus;

+        }

+        if (( !EFI_ERROR ( Status ))

+          && ( TransferLength != (UINTN)( Packet.Length + 4 ))) {

+          Status = EFI_WARN_WRITE_FAILURE;

+        }

+        if ( EFI_SUCCESS == Status ) {

+          pNicDevice->pTxBuffer = pBuffer;

+        }

+        else {

+          DEBUG (( DEBUG_ERROR | DEBUG_INFO,

+                    "Ax88772 USB transmit error, TransferLength: %d, Status: %r\r\n",

+                    sizeof ( Packet.Length ) + Packet.Length,

+                    Status ));

+          //

+          //  Reset the controller to fix the error

+          //

+          if ( EFI_DEVICE_ERROR == Status ) {

+            SN_Reset ( pSimpleNetwork, FALSE );

+          }

+        }

+      }

+      else {

+        //

+        // No packets available.

+        //

+        Status = EFI_NOT_READY;

+      }

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    DEBUG (( DEBUG_ERROR | DEBUG_INFO,

+              "Ax88772 invalid transmit parameter\r\n"

+              "  0x%08x: HeaderSize\r\n"

+              "  0x%08x: BufferSize\r\n"

+              "  0x%08x: Buffer\r\n"

+              "  0x%08x: SrcAddr\r\n"

+              "  0x%08x: DestAddr\r\n"

+              "  0x%04x:     Protocol\r\n",

+              HeaderSize,

+              BufferSize,

+              pBuffer,

+              pSrcAddr,

+              pDestAddr,

+              pProtocol ));

+    Status = EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Return the operation status

+  //

+  DBG_EXIT_STATUS ( Status );

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c
new file mode 100644
index 0000000..45ba3e5
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c
@@ -0,0 +1,878 @@
+/** @file

+  Implement the interface to the AX88772 Ethernet controller.

+

+  This module implements the interface to the ASIX AX88772

+  USB to Ethernet MAC with integrated 10/100 PHY.  Note that this implementation

+  only supports the integrated PHY since no other test cases were available.

+

+  Copyright (c) 2011, Intel Corporation

+  All rights reserved. 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.

+

+**/

+

+#include "Ax88772.h"

+

+

+/**

+  Compute the CRC 

+

+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.

+

+  @returns The CRC-32 value associated with this MAC address

+

+**/

+UINT32

+Ax88772Crc (

+  IN UINT8 * pMacAddress

+  )

+{

+  UINT32 BitNumber;

+  INT32 Carry;

+  INT32 Crc;

+  UINT32 Data;

+  UINT8 * pEnd;

+

+  //

+  //  Walk the MAC address

+  //

+  Crc = -1;

+  pEnd = &pMacAddress[ PXE_HWADDR_LEN_ETHER ];

+  while ( pEnd > pMacAddress ) {

+    Data = *pMacAddress++;

+    //

+    //  CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1

+    //

+    //          1 0000 0100 1100 0001 0001 1101 1011 0111

+    //

+    for ( BitNumber = 0; 8 > BitNumber; BitNumber++ ) {

+      Carry = (( Crc >> 31 ) & 1 ) ^ ( Data & 1 );

+      Crc <<= 1;

+      if ( 0 != Carry ) {

+        Crc ^= 0x04c11db7;

+      }

+      Data >>= 1;

+    }

+  }

+  //

+  //  Return the CRC value

+  //

+  return (UINT32) Crc;

+}

+

+

+/**

+  Get the MAC address

+

+  This routine calls ::Ax88772UsbCommand to request the MAC

+  address from the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772MacAddressGet (

+  IN NIC_DEVICE * pNicDevice,

+  OUT UINT8 * pMacAddress

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  //

+  //  Set the register address.

+  //

+  SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                       | USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_MAC_ADDRESS_READ;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;

+

+  //

+  //  Read the PHY register

+  //

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               pMacAddress );

+  return Status;

+}

+

+

+/**

+  Set the MAC address

+

+  This routine calls ::Ax88772UsbCommand to set the MAC address

+  in the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772MacAddressSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  //

+  //  Set the register address.

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_MAC_ADDRESS_WRITE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = PXE_HWADDR_LEN_ETHER;

+  

+  //

+  //  Read the PHY register

+  //

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               pMacAddress );

+  return Status;

+}

+

+/**

+  Clear the multicast hash table

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+**/

+VOID

+Ax88772MulticastClear (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  int i = 0;

+  //

+  // Clear the multicast hash table

+  //

+  for ( i = 0 ; i < 8 ; i ++ )

+     pNicDevice->MulticastHash[0] = 0;

+}

+

+/**

+  Enable a multicast address in the multicast hash table

+

+  This routine calls ::Ax88772Crc to compute the hash bit for

+  this MAC address.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.

+

+**/

+VOID

+Ax88772MulticastSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  )

+{

+  UINT32 Crc;

+

+  //

+  //  Compute the CRC on the destination address

+  //

+  Crc = Ax88772Crc ( pMacAddress ) >> 26;

+

+  //

+  //  Set the bit corresponding to the destination address

+  //

+   pNicDevice->MulticastHash [ Crc >> 3 ] |= ( 1<< (Crc& 7));

+}

+

+/**

+  Start the link negotiation

+

+  This routine calls ::Ax88772PhyWrite to start the PHY's link

+  negotiation.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The link negotiation was started.

+  @retval other                Failed to start the link negotiation.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkStart (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  UINT16 Control;

+  EFI_STATUS Status;

+  int i; 

+  //

+  // Set the supported capabilities.

+  //

+  Status = Ax88772PhyWrite ( pNicDevice,

+                             PHY_ANAR,

+                             AN_CSMA_CD

+                             | AN_TX_FDX | AN_TX_HDX

+                             | AN_10_FDX | AN_10_HDX );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    // Set the link speed and duplex

+    //

+    Control = BMCR_AUTONEGOTIATION_ENABLE

+            | BMCR_RESTART_AUTONEGOTIATION;

+    if ( pNicDevice->b100Mbps ) {

+      Control |= BMCR_100MBPS;

+    }

+    if ( pNicDevice->bFullDuplex ) {

+      Control |= BMCR_FULL_DUPLEX;

+    }

+    Status = Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control );

+  }

+  

+  if (!EFI_ERROR(Status)) {

+    i = 0;

+    do {

+      

+        if (pNicDevice->bComplete && pNicDevice->bLinkUp) {

+            pNicDevice->SimpleNetwork.Mode->MediaPresent 

+               = pNicDevice->bLinkUp & pNicDevice->bComplete;

+           break;

+       }

+       else {

+            gBS->Stall(AUTONEG_DELAY);

+            Status = Ax88772NegotiateLinkComplete ( pNicDevice,

+                                            &pNicDevice->PollCount,

+                                            &pNicDevice->bComplete,

+                                            &pNicDevice->bLinkUp,

+                                            &pNicDevice->b100Mbps,

+                                            &pNicDevice->bFullDuplex );

+            i++;

+        }

+    }while(!pNicDevice->bLinkUp && i < AUTONEG_POLLCNT);

+  }

+  return Status;

+}

+

+

+/**

+  Complete the negotiation of the PHY link

+

+  This routine calls ::Ax88772PhyRead to determine if the

+  link negotiation is complete.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in, out] pPollCount  Address of number of times this routine was polled

+  @param [out] pbComplete      Address of boolean to receive complate status.

+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.

+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.

+  @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkComplete (

+  IN NIC_DEVICE * pNicDevice,

+  IN OUT UINTN * pPollCount,

+  OUT BOOLEAN * pbComplete,

+  OUT BOOLEAN * pbLinkUp,

+  OUT BOOLEAN * pbHiSpeed,

+  OUT BOOLEAN * pbFullDuplex

+  )

+{

+  UINT16 Mask;

+  UINT16 PhyData;

+  EFI_STATUS  Status;

+ 

+  //

+  //  Determine if the link is up.

+  //

+  *pbComplete = FALSE;  

+

+  //

+  //  Get the link status

+  //

+  Status = Ax88772PhyRead ( pNicDevice,

+                            PHY_BMSR,

+                            &PhyData );

+

+  if ( !EFI_ERROR ( Status )) {

+      *pbLinkUp = (BOOLEAN)( 0 != ( PhyData & BMSR_LINKST ));

+      if ( 0 == *pbLinkUp ) {

+        DEBUG (( EFI_D_INFO, "Link Down\n" ));

+      }      

+      else {

+         *pbComplete = (BOOLEAN)( 0 != ( PhyData & 0x20 ));

+         if ( 0 == *pbComplete ) {

+              DEBUG (( EFI_D_INFO, "Autoneg is not yet Complete\n" ));

+        }

+        else {

+          Status = Ax88772PhyRead ( pNicDevice,

+                                PHY_ANLPAR,

+                                &PhyData );

+          if ( !EFI_ERROR ( Status )) {

+            //

+            //  Autonegotiation is complete

+            //  Determine the link speed.

+            //

+            *pbHiSpeed = (BOOLEAN)( 0 != ( PhyData & ( AN_TX_FDX | AN_TX_HDX )));

+

+            //

+            //  Determine the link duplex.

+            //

+            Mask = ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX;

+            *pbFullDuplex = (BOOLEAN)( 0 != ( PhyData & Mask ));

+          }

+        } 

+      }

+  } 

+  else {

+      DEBUG (( EFI_D_ERROR, "Failed to read BMCR\n" ));

+  }

+  return Status;

+}

+

+

+/**

+  Read a register from the PHY

+

+  This routine calls ::Ax88772UsbCommand to read a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in, out] pPhyData    Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data is available.

+  @retval other                The PHY data is not valid.

+

+**/

+EFI_STATUS

+Ax88772PhyRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN OUT UINT16 * pPhyData

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  //

+  //  Request access to the PHY

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;   

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               NULL );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  Read the PHY register address.

+    //

+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                         | USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_PHY_REG_READ;

+    SetupMsg.Value = pNicDevice->PhyId;

+    SetupMsg.Index = RegisterAddress;

+    SetupMsg.Length = sizeof ( *pPhyData );

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 pPhyData );

+    if ( !EFI_ERROR ( Status )) {

+

+      //

+      //  Release the PHY to the hardware

+      //

+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;

+      SetupMsg.Value = 0;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = 0;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   NULL );

+    }

+  }

+  return Status;

+}

+

+

+/**

+  Write to a PHY register

+

+  This routine calls ::Ax88772UsbCommand to write a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in] PhyData          Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data was written.

+  @retval other                Failed to wwrite the PHY register.

+

+**/

+EFI_STATUS

+Ax88772PhyWrite (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN UINT16 PhyData

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+

+  //

+  //  Request access to the PHY

+  //

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                       | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_PHY_ACCESS_SOFTWARE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                               &SetupMsg,

+                               NULL );

+  if ( !EFI_ERROR ( Status )) {

+    //

+    //  Write the PHY register

+    //

+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_PHY_REG_WRITE;

+    SetupMsg.Value = pNicDevice->PhyId;

+    SetupMsg.Index = RegisterAddress;

+    SetupMsg.Length = sizeof ( PhyData );

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 &PhyData );

+    if ( !EFI_ERROR ( Status )) {

+

+      //

+      //  Release the PHY to the hardware

+      //

+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;

+      SetupMsg.Value = 0;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = 0;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   NULL );

+    }

+  }

+

+  return Status;

+}

+

+

+/**

+  Reset the AX88772

+

+  This routine uses ::Ax88772UsbCommand to reset the network

+  adapter.  This routine also uses ::Ax88772PhyWrite to reset

+  the PHY.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772Reset (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+  

+  EFI_USB_IO_PROTOCOL *pUsbIo;

+  EFI_USB_DEVICE_DESCRIPTOR Device;

+  

+  pUsbIo = pNicDevice->pUsbIo;

+  Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );

+

+	if (EFI_ERROR(Status)) goto err; 

+

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_PHY_ACCESS_HARDWARE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                &SetupMsg,

+                                NULL );

+                                   

+  if (EFI_ERROR(Status)) goto err;                                 

+                                   

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_PHY_SELECT;

+      SetupMsg.Value = SPHY_PSEL;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = 0;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                    &SetupMsg,

+                                    NULL );

+                                    

+  if (EFI_ERROR(Status)) goto err;  

+                                     

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;                                

+  SetupMsg.Request = CMD_RESET;

+      SetupMsg.Value = SRR_IPRL ;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = 0;

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   NULL );  

+                                   

+  if (EFI_ERROR(Status)) goto err;  

+                                   

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;                                

+  SetupMsg.Request = CMD_RESET;

+        SetupMsg.Value = SRR_IPPD | SRR_IPRL ;

+        SetupMsg.Index = 0;

+        SetupMsg.Length = 0;

+        Status = Ax88772UsbCommand ( pNicDevice,

+                                    &SetupMsg,

+                                    NULL );

+                                   

+  gBS->Stall ( 200000 );

+    

+  if (EFI_ERROR(Status)) goto err;  

+    

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_RESET;

+  SetupMsg.Value =  SRR_IPRL  ;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                &SetupMsg,

+                                NULL );   

+                                    

+  gBS->Stall ( 200000 ); 

+     

+  if (EFI_ERROR(Status)) goto err;  

+     

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_RESET;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                    &SetupMsg,

+                                    NULL );

+                                    

+  if (EFI_ERROR(Status)) goto err;                                

+                                    

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_PHY_SELECT;

+  SetupMsg.Value = SPHY_PSEL;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                    &SetupMsg,

+                                    NULL ); 

+                                    

+  if (EFI_ERROR(Status)) goto err;                                

+                                    

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                          | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_RESET;

+  SetupMsg.Value =  SRR_IPRL | SRR_BZ | SRR_BZTYPE;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                    &SetupMsg,

+                                    NULL );

+                                    

+  if (EFI_ERROR(Status)) goto err;                                

+                                    

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                        | USB_TARGET_DEVICE;

+  SetupMsg.Request = CMD_RX_CONTROL_WRITE;

+  SetupMsg.Value = 0;

+  SetupMsg.Index = 0;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                  &SetupMsg,

+                                  NULL );

+                                  

+  if (EFI_ERROR(Status)) goto err;  

+

+  SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                        | USB_TARGET_DEVICE; 

+  SetupMsg.Request = CMD_RXQTC;

+  SetupMsg.Value = 0x8000;

+  SetupMsg.Index = 0x8001;

+  SetupMsg.Length = 0;

+  Status = Ax88772UsbCommand ( pNicDevice,

+                                  &SetupMsg,

+                                  NULL ); 

+err:

+  return Status;

+}

+

+/**

+  Enable or disable the receiver

+

+  This routine calls ::Ax88772UsbCommand to update the

+  receiver state.  This routine also calls ::Ax88772MacAddressSet

+  to establish the MAC address for the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RxFilter         Simple network RX filter mask value

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772RxControl (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 RxFilter

+  )

+{

+  UINT16 MediumStatus;

+  UINT16 RxControl;

+  USB_DEVICE_REQUEST SetupMsg;

+  EFI_STATUS Status;

+  EFI_USB_IO_PROTOCOL *pUsbIo;

+  EFI_USB_DEVICE_DESCRIPTOR Device;

+  

+  pUsbIo = pNicDevice->pUsbIo;

+  Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );

+  

+  if (EFI_ERROR(Status)) {

+    DEBUG (( EFI_D_ERROR, "Failed to get device descriptor\n" ));

+    return Status;

+  }

+

+  //

+  // Enable the receiver if something is to be received

+  //

+  

+  if ( 0 != RxFilter ) {

+    //

+    //  Enable the receiver

+    //

+    SetupMsg.RequestType = USB_ENDPOINT_DIR_IN

+                         | USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_MEDIUM_STATUS_READ;    

+    SetupMsg.Value = 0;

+    SetupMsg.Index = 0;

+    SetupMsg.Length = sizeof ( MediumStatus );

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 &MediumStatus );

+    if ( !EFI_ERROR ( Status )) {

+      if ( 0 == ( MediumStatus & MS_RE )) {

+        MediumStatus |= MS_RE | MS_ONE;

+        

+        if ( pNicDevice->bFullDuplex )

+          MediumStatus |= MS_TFC | MS_RFC | MS_FD;

+        else

+          MediumStatus &= ~(MS_TFC | MS_RFC | MS_FD);

+        

+        if ( pNicDevice->b100Mbps )

+          MediumStatus |= MS_PS;

+        else

+          MediumStatus &= ~MS_PS;

+        

+        SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                             | USB_TARGET_DEVICE;

+        SetupMsg.Request = CMD_MEDIUM_STATUS_WRITE;

+        SetupMsg.Value = MediumStatus;

+        SetupMsg.Index = 0;

+        SetupMsg.Length = 0;

+        Status = Ax88772UsbCommand ( pNicDevice,

+                                     &SetupMsg,

+                                     NULL );

+        if ( EFI_ERROR ( Status )) {

+            DEBUG (( EFI_D_ERROR, "Failed to enable receiver, Status: %r\r\n",

+              Status ));

+        }

+      }

+    }

+    else {

+        DEBUG (( EFI_D_ERROR, "Failed to read receiver status, Status: %r\r\n",

+              Status ));

+    }

+  }

+  

+  RxControl = RXC_SO | RXC_RH1M;  

+  //

+  //  Enable multicast if requested

+  //

+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {

+      RxControl |= RXC_AM;

+      //

+      //  Update the multicast hash table

+      //

+      SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                           | USB_TARGET_DEVICE;

+      SetupMsg.Request = CMD_MULTICAST_HASH_WRITE;

+      SetupMsg.Value = 0;

+      SetupMsg.Index = 0;

+      SetupMsg.Length = sizeof ( pNicDevice ->MulticastHash );

+      Status = Ax88772UsbCommand ( pNicDevice,

+                                   &SetupMsg,

+                                   &pNicDevice->MulticastHash );

+  }

+  //

+  //  Enable all multicast if requested

+  //

+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) {

+      RxControl |= RXC_AMALL;

+  }

+

+  //

+  //  Enable broadcast if requested

+  //

+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) {

+      RxControl |= RXC_AB;

+  }

+

+  //

+  //  Enable promiscuous mode if requested

+  //

+  if ( 0 != ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) {

+      RxControl |= RXC_PRO;

+  }

+    

+  //

+  //  Update the receiver control

+  //

+  if (pNicDevice->CurRxControl != RxControl) {

+    SetupMsg.RequestType = USB_REQ_TYPE_VENDOR

+                         | USB_TARGET_DEVICE;

+    SetupMsg.Request = CMD_RX_CONTROL_WRITE;

+    SetupMsg.Value = RxControl;

+    SetupMsg.Index = 0;

+    SetupMsg.Length = 0;

+    Status = Ax88772UsbCommand ( pNicDevice,

+                                 &SetupMsg,

+                                 NULL );

+    if ( !EFI_ERROR ( Status )) {

+      pNicDevice->CurRxControl = RxControl;

+      

+    }

+    else {

+        DEBUG (( EFI_D_ERROR, "ERROR - Failed to set receiver control, Status: %r\r\n",

+            Status ));

+    }

+  }

+  return Status;

+}

+

+

+/**

+  Read an SROM location

+

+  This routine calls ::Ax88772UsbCommand to read data from the

+  SROM.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] Address          SROM address

+  @param [out] pData           Buffer to receive the data

+

+  @retval EFI_SUCCESS          The read was successful

+  @retval other                The read failed

+

+**/

+EFI_STATUS

+Ax88772SromRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 Address,

+  OUT UINT16 * pData

+  )

+{ 

+  return EFI_UNSUPPORTED;

+}

+

+/**

+  Send a command to the USB device.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pRequest         Pointer to the request structure

+  @param [in, out] pBuffer     Data buffer address

+

+  @retval EFI_SUCCESS          The USB transfer was successful

+  @retval other                The USB transfer failed

+

+**/

+EFI_STATUS

+Ax88772UsbCommand (

+  IN NIC_DEVICE * pNicDevice,

+  IN USB_DEVICE_REQUEST * pRequest,

+  IN OUT VOID * pBuffer

+  )

+{

+  UINT32 CmdStatus;

+  EFI_USB_DATA_DIRECTION Direction;

+  EFI_USB_IO_PROTOCOL * pUsbIo;

+  EFI_STATUS Status;

+

+  //

+  // Determine the transfer direction

+  //

+  Direction = EfiUsbNoData;

+  if ( 0 != pRequest->Length ) {

+    Direction = ( 0 != ( pRequest->RequestType & USB_ENDPOINT_DIR_IN ))

+              ? EfiUsbDataIn : EfiUsbDataOut;

+  }

+

+  //

+  // Issue the command

+  //

+  pUsbIo = pNicDevice->pUsbIo;

+  Status = pUsbIo->UsbControlTransfer ( pUsbIo,

+                                        pRequest,

+                                        Direction,

+                                        USB_BUS_TIMEOUT,

+                                        pBuffer,

+                                        pRequest->Length,

+                                        &CmdStatus );

+  //

+  // Determine the operation status

+  //

+  if ( !EFI_ERROR ( Status )) {

+    Status = CmdStatus;

+  }

+  else {

+    //

+    // Only use status values associated with the Simple Network protocol

+    //

+    if ( EFI_TIMEOUT == Status ) {

+      Status = EFI_DEVICE_ERROR;

+    }

+  }

+  return Status;

+}

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h
new file mode 100644
index 0000000..5382e44
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h
@@ -0,0 +1,1023 @@
+/** @file

+  Definitions for ASIX AX88772 Ethernet adapter.

+

+  Copyright (c) 2011, Intel Corporation

+  All rights reserved. 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.

+

+**/

+

+#ifndef _AX88772_H_

+#define _AX88772_H_

+

+#include <Uefi.h>

+

+#include <Guid/EventGroup.h>

+#include <Guid/NicIp4ConfigNvData.h>

+

+#include <IndustryStandard/Pci.h>

+

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/DevicePathLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/UefiLib.h>

+#include <Library/UefiRuntimeLib.h>

+

+#include <Protocol/DevicePath.h>

+#include <Protocol/LoadedImage.h>

+#include <Protocol/NetworkInterfaceIdentifier.h>

+#include <Protocol/SimpleNetwork.h>

+#include <Protocol/UsbIo.h>

+

+#define MAX_QUEUE_SIZE 50

+#define MAX_BULKIN_SIZE 16384

+#define HW_HDR_LENGTH 8

+

+

+#define MAX_LINKIDLE_THRESHOLD  20000

+

+

+

+//------------------------------------------------------------------------------

+//  Macros

+//------------------------------------------------------------------------------

+

+#if defined(_MSC_VER)           /* Handle Microsoft VC++ compiler specifics. */

+#define DBG_ENTER()             DEBUG (( 0xffffffff, "Entering " __FUNCTION__ "\n" )) ///<  Display routine entry

+#define DBG_EXIT()              DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ "\n" ))  ///<  Display routine exit

+#define DBG_EXIT_DEC(Status)    DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: %d\n", Status ))      ///<  Display routine exit with decimal value

+#define DBG_EXIT_HEX(Status)    DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status ))  ///<  Display routine exit with hex value

+#define DBG_EXIT_STATUS(Status) DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", Status: %r\n", Status ))      ///<  Display routine exit with status value

+#define DBG_EXIT_TF(Status)     DEBUG (( 0xffffffff, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" ))  ///<  Display routine with TRUE/FALSE value

+#else   //  _MSC_VER

+#define DBG_ENTER()               ///<  Display routine entry

+#define DBG_EXIT()                ///<  Display routine exit

+#define DBG_EXIT_DEC(Status)      ///<  Display routine exit with decimal value

+#define DBG_EXIT_HEX(Status)      ///<  Display routine exit with hex value

+#define DBG_EXIT_STATUS(Status)   ///<  Display routine exit with status value

+#define DBG_EXIT_TF(Status)       ///<  Display routine with TRUE/FALSE value

+#endif  //  _MSC_VER

+

+#define USB_IS_IN_ENDPOINT(EndPointAddr)      (((EndPointAddr) & BIT7) != 0)  ///<  Return TRUE/FALSE for IN direction

+#define USB_IS_OUT_ENDPOINT(EndPointAddr)     (((EndPointAddr) & BIT7) == 0)  ///<  Return TRUE/FALSE for OUT direction

+#define USB_IS_BULK_ENDPOINT(Attribute)       (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)      ///<  Return TRUE/FALSE for BULK type

+#define USB_IS_INTERRUPT_ENDPOINT(Attribute)  (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) ///<  Return TRUE/FALSE for INTERRUPT type

+

+

+#define PRINT(_L_STR) (gST->ConOut->OutputString(gST->ConOut,(_L_STR)))

+//------------------------------------------------------------------------------

+//  Constants

+//------------------------------------------------------------------------------

+

+#define DEBUG_RX_BROADCAST  0x40000000  ///<  Display RX broadcast messages

+#define DEBUG_RX_MULTICAST  0x20000000  ///<  Display RX multicast messages

+#define DEBUG_RX_UNICAST    0x10000000  ///<  Display RX unicast messages

+#define DEBUG_MAC_ADDRESS   0x08000000  ///<  Display the MAC address

+#define DEBUG_LINK          0x04000000  ///<  Display the link status

+#define DEBUG_TX            0x02000000  ///<  Display the TX messages

+#define DEBUG_PHY           0x01000000  ///<  Display the PHY register values

+#define DEBUG_SROM          0x00800000  ///<  Display the SROM contents

+#define DEBUG_TIMER         0x00400000  ///<  Display the timer routine entry/exit

+#define DEBUG_TPL           0x00200000  ///<  Display the timer routine entry/exit

+

+#define AX88772_MAX_PKT_SIZE  2048  ///< Maximum packet size

+

+#define ETHERNET_HEADER_SIZE  sizeof ( ETHERNET_HEADER )  ///<  Size in bytes of the Ethernet header

+#define MIN_ETHERNET_PKT_SIZE 60    ///<  Minimum packet size including Ethernet header

+#define MAX_ETHERNET_PKT_SIZE 1500  ///<  Ethernet spec 3.1.1: Minimum packet size

+

+#define USB_NETWORK_CLASS   0x09    ///<  USB Network class code

+#define USB_BUS_TIMEOUT     1000    ///<  USB timeout in milliseconds

+

+#define TIMER_MSEC          20              ///<  Polling interval for the NIC

+//#define TPL_AX88772         TPL_CALLBACK    ///<  TPL for routine synchronization

+

+#define HC_DEBUG  0

+#define BULKIN_TIMEOUT  20

+#define AUTONEG_DELAY   500000

+#define AUTONEG_POLLCNT 20

+

+/**

+  Verify new TPL value

+

+  This macro which is enabled when debug is enabled verifies that

+  the new TPL value is >= the current TPL value.

+**/

+#ifdef VERIFY_TPL

+#undef VERIFY_TPL

+#endif  //  VERIFY_TPL

+

+#if !defined(MDEPKG_NDEBUG)

+

+#define VERIFY_TPL(tpl)                           \

+{                                                 \

+  EFI_TPL PreviousTpl;                            \

+                                                  \

+  PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \

+  gBS->RestoreTPL ( PreviousTpl );                \

+  if ( PreviousTpl > tpl ) {                      \

+    DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl ));  \

+    ASSERT ( PreviousTpl <= tpl );                \

+  }                                               \

+}

+

+#else   //  MDEPKG_NDEBUG

+

+#define VERIFY_TPL(tpl)

+

+#endif  //  MDEPKG_NDEBUG

+

+//------------------------------------------------------------------------------

+//  Hardware Definition

+//------------------------------------------------------------------------------

+

+#define FreeQueueSize     10

+

+#define DEV_SIGNATURE     SIGNATURE_32 ('A','X','8','8')  ///<  Signature of data structures in memory

+

+#define VENDOR_ID         0x0B95  ///<  Vendor ID for Asix

+#define PRODUCT_ID        0x772B  ///<  Product ID for the AX88772 USB 10/100 Ethernet controller

+

+#define RESET_MSEC        1000    ///<  Reset duration

+#define PHY_RESET_MSEC     500    ///<  PHY reset duration

+

+//

+//  RX Control register

+//

+

+#define RXC_PRO           0x0001  ///<  Receive all packets

+#define RXC_AMALL         0x0002  ///<  Receive all multicast packets

+#define RXC_SEP           0x0004  ///<  Save error packets

+#define RXC_AB            0x0008  ///<  Receive broadcast packets

+#define RXC_AM            0x0010  ///<  Use multicast destination address hash table

+#define RXC_AP            0x0020  ///<  Accept physical address from Multicast Filter

+#define RXC_SO            0x0080  ///<  Start operation

+#define RXC_MFB           0x0300  ///<  Maximum frame burst

+#define RXC_MFB_2048      0       ///<  Maximum frame size:  2048 bytes

+#define RXC_MFB_4096      0x0100  ///<  Maximum frame size:  4096 bytes

+#define RXC_MFB_8192      0x0200  ///<  Maximum frame size:  8192 bytes

+#define RXC_MFB_16384     0x0300  ///<  Maximum frame size: 16384 bytes

+

+/*Freddy*/

+#define RXC_RH1M          0x0100  ///<  Rx header 1

+#define RXC_RH2M          0x0200  ///<  Rx header 2

+#define RXC_RH3M          0x0400  ///<  Rx header 3

+/*Freddy*/

+

+//

+//  Medium Status register

+//

+

+#define MS_FD             0x0002  ///<  Full duplex

+#define MS_ONE            0x0004  ///<  Must be one

+#define MS_RFC            0x0010  ///<  RX flow control enable

+#define MS_TFC            0x0020  ///<  TX flow control enable

+#define MS_PF             0x0080  ///<  Pause frame enable

+#define MS_RE             0x0100  ///<  Receive enable

+#define MS_PS             0x0200  ///<  Port speed 1=100, 0=10 Mbps

+#define MS_SBP            0x0800  ///<  Stop back pressure

+#define MS_SM             0x1000  ///<  Super MAC support

+

+//

+//  Software PHY Select register

+//

+

+#define SPHY_PSEL         (1 << 0)    ///<  Select internal PHY

+#define SPHY_SSMII        (1 << 2)

+#define SPHY_SSEN         (1 << 4)

+#define SPHY_ASEL         0x02    ///<  1=Auto select, 0=Manual select

+

+//

+//  Software Reset register

+//

+

+#define SRR_RR            0x01    ///<  Clear receive frame length error

+#define SRR_RT            0x02    ///<  Clear transmit frame length error

+#define SRR_BZTYPE        0x04    ///<  External PHY reset pin tri-state enable

+#define SRR_PRL           0x08    ///<  External PHY reset pin level

+#define SRR_BZ            0x10    ///<  Force Bulk to return zero length packet

+#define SRR_IPRL          0x20    ///<  Internal PHY reset control

+#define SRR_IPPD          0x40    ///<  Internal PHY power down

+

+//

+//  PHY ID values

+//

+

+#define PHY_ID_INTERNAL   0x0010  ///<  Internal PHY

+

+//

+//  USB Commands

+//

+

+#define CMD_PHY_ACCESS_SOFTWARE   0x06  ///<  Software in control of PHY

+#define CMD_PHY_REG_READ          0x07  ///<  Read PHY register, Value: PHY, Index: Register, Data: Register value

+#define CMD_PHY_REG_WRITE         0x08  ///<  Write PHY register, Value: PHY, Index: Register, Data: New 16-bit value

+#define CMD_PHY_ACCESS_HARDWARE   0x0a  ///<  Hardware in control of PHY

+#define CMD_SROM_READ             0x0b  ///<  Read SROM register: Value: Address, Data: Value

+#define CMD_RX_CONTROL_WRITE      0x10  ///<  Set the RX control register, Value: New value

+#define CMD_GAPS_WRITE            0x12  ///<  Write the gaps register, Value: New value

+#define CMD_MAC_ADDRESS_READ      0x13  ///<  Read the MAC address, Data: 6 byte MAC address

+#define CMD_MAC_ADDRESS_WRITE     0x14  ///<  Set the MAC address, Data: New 6 byte MAC address

+#define CMD_MULTICAST_HASH_WRITE  0x16  ///<  Write the multicast hash table, Data: New 8 byte value

+#define CMD_MULTICAST_HASH_READ  0x16  ///<  Read the multicast hash table

+#define CMD_MEDIUM_STATUS_READ    0x1a  ///<  Read medium status register, Data: Register value

+#define CMD_MEDIUM_STATUS_WRITE   0x1b  ///<  Write medium status register, Value: New value

+#define CMD_WRITE_GPIOS           0x1f

+#define CMD_RESET                 0x20  ///<  Reset register, Value: New value

+#define CMD_PHY_SELECT            0x22  ///<  PHY select register, Value: New value

+

+/*Freddy*/

+#define CMD_RXQTC                 0x2a  ///<  RX Queue Cascade Threshold Control Register

+/*Freddy*/

+

+//------------------------------

+//  USB Endpoints

+//------------------------------

+

+#define CONTROL_ENDPOINT                0       ///<  Control endpoint

+#define INTERRUPT_ENDPOINT              1       ///<  Interrupt endpoint

+#define BULK_IN_ENDPOINT                2       ///<  Receive endpoint

+#define BULK_OUT_ENDPOINT               3       ///<  Transmit endpoint

+

+//------------------------------

+//  PHY Registers

+//------------------------------

+

+#define PHY_BMCR                        0       ///<  Control register

+#define PHY_BMSR                        1       ///<  Status register

+#define PHY_ANAR                        4       ///<  Autonegotiation advertisement register

+#define PHY_ANLPAR                      5       ///<  Autonegotiation link parter ability register

+#define PHY_ANER                        6       ///<  Autonegotiation expansion register

+

+//  BMCR - Register 0

+

+#define BMCR_RESET                      0x8000  ///<  1 = Reset the PHY, bit clears after reset

+#define BMCR_LOOPBACK                   0x4000  ///<  1 = Loopback enabled

+#define BMCR_100MBPS                    0x2000  ///<  100 Mbits/Sec

+#define BMCR_10MBPS                     0       ///<  10 Mbits/Sec

+#define BMCR_AUTONEGOTIATION_ENABLE     0x1000  ///<  1 = Enable autonegotiation

+#define BMCR_POWER_DOWN                 0x0800  ///<  1 = Power down

+#define BMCR_ISOLATE                    0x0400  ///<  0 = Isolate PHY

+#define BMCR_RESTART_AUTONEGOTIATION    0x0200  ///<  1 = Restart autonegotiation

+#define BMCR_FULL_DUPLEX                0x0100  ///<  Full duplex operation

+#define BMCR_HALF_DUPLEX                0       ///<  Half duplex operation

+#define BMCR_COLLISION_TEST             0x0080  ///<  1 = Collision test enabled

+

+//  BSMR - Register 1

+

+#define BMSR_100BASET4                  0x8000  ///<  1 = 100BASE-T4 mode

+#define BMSR_100BASETX_FDX              0x4000  ///<  1 = 100BASE-TX full duplex

+#define BMSR_100BASETX_HDX              0x2000  ///<  1 = 100BASE-TX half duplex

+#define BMSR_10BASET_FDX                0x1000  ///<  1 = 10BASE-T full duplex

+#define BMSR_10BASET_HDX                0x0800  ///<  1 = 10BASE-T half duplex

+#define BMSR_MF                         0x0040  ///<  1 = PHY accepts frames with preamble suppressed

+#define BMSR_AUTONEG_CMPLT              0x0020  ///<  1 = Autonegotiation complete

+#define BMSR_RF                         0x0010  ///<  1 = Remote fault

+#define BMSR_AUTONEG                    0x0008  ///<  1 = Able to perform autonegotiation

+#define BMSR_LINKST                     0x0004  ///<  1 = Link up

+#define BMSR_JABBER_DETECT              0x0002  ///<  1 = jabber condition detected

+#define BMSR_EXTENDED_CAPABILITY        0x0001  ///<  1 = Extended register capable

+

+//  ANAR and ANLPAR Registers 4, 5

+

+#define AN_NP                           0x8000  ///<  1 = Next page available

+#define AN_ACK                          0x4000  ///<  1 = Link partner acknowledged

+#define AN_RF                           0x2000  ///<  1 = Remote fault indicated by link partner

+#define AN_FCS                          0x0400  ///<  1 = Flow control ability

+#define AN_T4                           0x0200  ///<  1 = 100BASE-T4 support

+#define AN_TX_FDX                       0x0100  ///<  1 = 100BASE-TX Full duplex

+#define AN_TX_HDX                       0x0080  ///<  1 = 100BASE-TX support

+#define AN_10_FDX                       0x0040  ///<  1 = 10BASE-T Full duplex

+#define AN_10_HDX                       0x0020  ///<  1 = 10BASE-T support

+#define AN_CSMA_CD                      0x0001  ///<  1 = IEEE 802.3 CSMA/CD support

+

+

+

+//------------------------------------------------------------------------------

+//  Data Types

+//------------------------------------------------------------------------------

+

+/**

+  Ethernet header layout

+

+  IEEE 802.3-2002 Part 3 specification, section 3.1.1.

+**/

+#pragma pack(1)

+typedef struct {

+  UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];  ///<  Destination LAN address

+  UINT8 src_addr[PXE_HWADDR_LEN_ETHER];   ///<  Source LAN address

+  UINT16 type;                            ///<  Protocol or length

+} ETHERNET_HEADER;

+#pragma pack()

+

+/**

+  Receive and Transmit packet structure

+**/

+#pragma pack(1)

+typedef struct _RX_TX_PACKET {

+  struct _RX_TX_PACKET * pNext;       ///<  Next receive packet

+  UINT16 Length;                      ///<  Packet length

+  UINT16 LengthBar;                   ///<  Complement of the length

+  UINT8 Data[ AX88772_MAX_PKT_SIZE ]; ///<  Received packet data

+} RX_TX_PACKET;

+#pragma pack()

+

+

+#pragma pack(1)

+typedef struct _RX_PKT {

+  struct _RX_PKT *pNext;

+  BOOLEAN f_Used;

+  UINT16 Length;

+  UINT8 Data [AX88772_MAX_PKT_SIZE] ;

+} RX_PKT;

+#pragma pack()

+

+/**

+  AX88772 control structure

+

+  The driver uses this structure to manage the Asix AX88772 10/100

+  Ethernet controller.

+**/

+typedef struct {

+  UINTN Signature;          ///<  Structure identification

+

+  //

+  //  USB data

+  //

+  EFI_HANDLE Controller;        ///<  Controller handle

+  EFI_USB_IO_PROTOCOL * pUsbIo;  ///<  USB driver interface

+

+  //

+  //  Simple network protocol data

+  //

+  EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork;  ///<  Driver's network stack interface

+  EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork_Backup;

+  EFI_SIMPLE_NETWORK_MODE SimpleNetworkData;  ///<  Data for simple network

+

+  //

+  // Ethernet controller data

+  //

+  BOOLEAN bInitialized;     ///<  Controller initialized

+  VOID * pTxBuffer;         ///<  Last transmit buffer

+  UINT16 PhyId;             ///<  PHY ID

+

+  //

+  //  Link state

+  //

+  BOOLEAN b100Mbps;         ///<  Current link speed, FALSE = 10 Mbps

+  BOOLEAN bComplete;        ///<  Current state of auto-negotiation

+  BOOLEAN bFullDuplex;      ///<  Current duplex

+  BOOLEAN bLinkUp;          ///<  Current link state

+  UINTN  LinkIdleCnt;

+  UINTN PollCount;          ///<  Number of times the autonegotiation status was polled

+  UINT16 CurRxControl;

+  //

+  //  Receive buffer list

+  //

+  RX_TX_PACKET * pRxTest;

+  RX_TX_PACKET * pTxTest;

+

+  INT8 MulticastHash[8];

+  EFI_MAC_ADDRESS MAC;

+  BOOLEAN bHavePkt;

+ 

+  EFI_DEVICE_PATH_PROTOCOL                  *MyDevPath;

+  

+  EFI_DRIVER_BINDING_PROTOCOL * DrvBind;

+  

+  RX_PKT * QueueHead;

+  RX_PKT * pNextFill;

+  RX_PKT * pFirstFill;

+  UINTN   PktCntInQueue;

+  UINT8 * pBulkInBuff;

+ 

+} NIC_DEVICE;

+

+#define DEV_FROM_SIMPLE_NETWORK(a)  CR (a, NIC_DEVICE, SimpleNetwork, DEV_SIGNATURE)  ///< Locate NIC_DEVICE from Simple Network Protocol

+

+//------------------------------------------------------------------------------

+// Simple Network Protocol

+//------------------------------------------------------------------------------

+

+/**

+  Reset the network adapter.

+

+  Resets a network adapter and reinitializes it with the parameters that

+  were provided in the previous call to Initialize ().  The transmit and

+  receive queues are cleared.  Receive filters, the station address, the

+  statistics, and the multicast-IP-to-HW MAC addresses are not reset by

+  this call.

+

+  This routine calls ::Ax88772Reset to perform the adapter specific

+  reset operation.  This routine also starts the link negotiation

+  by calling ::Ax88772NegotiateLinkStart.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bExtendedVerification  Indicates that the driver may perform a more

+                                exhaustive verification operation of the device

+                                during reset.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Reset (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bExtendedVerification

+  );

+

+/**

+  Initialize the simple network protocol.

+

+  This routine calls ::Ax88772MacAddressGet to obtain the

+  MAC address.

+

+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer

+

+  @retval EFI_SUCCESS     Setup was successful

+

+**/

+EFI_STATUS

+SN_Setup (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  This routine starts the network interface.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_ALREADY_STARTED   The network interface was already started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Start (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  );

+

+/**

+  Set the MAC address.

+  

+  This function modifies or resets the current station address of a

+  network interface.  If Reset is TRUE, then the current station address

+  is set ot the network interface's permanent address.  If Reset if FALSE

+  then the current station address is changed to the address specified by

+  pNew.

+

+  This routine calls ::Ax88772MacAddressSet to update the MAC address

+  in the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Flag used to reset the station address to the

+                                network interface's permanent address.

+  @param [in] pNew              New station address to be used for the network

+                                interface.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_StationAddress (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN EFI_MAC_ADDRESS * pNew

+  );

+

+/**

+  This function resets or collects the statistics on a network interface.

+  If the size of the statistics table specified by StatisticsSize is not

+  big enough for all of the statistics that are collected by the network

+  interface, then a partial buffer of statistics is returned in

+  StatisticsTable.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.

+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output

+                                the size, in bytes, of the resulting table of statistics.

+  @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that

+                                conains the statistics.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_BUFFER_TOO_SMALL  The pStatisticsTable is NULL or the buffer is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Statistics (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN OUT UINTN * pStatisticsSize,

+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable

+  );

+

+/**

+  This function stops a network interface.  This call is only valid

+  if the network interface is in the started state.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Stop (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  );

+

+/**

+  This function releases the memory buffers assigned in the Initialize() call.

+  Pending transmits and receives are lost, and interrupts are cleared and disabled.

+  After this call, only Initialize() and Stop() calls may be used.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Shutdown (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  );

+

+/**

+  Send a packet over the network.

+

+  This function places the packet specified by Header and Buffer on

+  the transmit queue.  This function performs a non-blocking transmit

+  operation.  When the transmit is complete, the buffer is returned

+  via the GetStatus() call.

+

+  This routine calls ::Ax88772Rx to empty the network adapter of

+  receive packets.  The routine then passes the transmit packet

+  to the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by

+                                the Transmit() function.  If HeaderSize is non-zero, then

+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize

+                                and DestAddr and Protocol parameters must not be NULL.

+  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and

+                                data) to be transmitted through the network interface.

+  @param [in] pBuffer           A pointer to the packet (media header followed by data) to

+                                to be transmitted.  This parameter can not be NULL.  If

+                                HeaderSize is zero, then the media header is Buffer must

+                                already be filled in by the caller.  If HeaderSize is nonzero,

+                                then the media header will be filled in by the Transmit()

+                                function.

+  @param [in] pSrcAddr          The source HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.  If HeaderSize is nonzero and

+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress

+                                is used for the source HW MAC address.

+  @param [in] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.

+  @param [in] pProtocol         The type of header to build.  If HeaderSize is zero, then

+                                this parameter is ignored.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.

+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Transmit (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN HeaderSize,

+  IN UINTN BufferSize,

+  IN VOID * pBuffer,

+  IN EFI_MAC_ADDRESS * pSrcAddr,

+  IN EFI_MAC_ADDRESS * pDestAddr,

+  IN UINT16 * pProtocol

+  );

+

+//------------------------------------------------------------------------------

+// Support Routines

+//------------------------------------------------------------------------------

+

+/**

+  Get the MAC address

+

+  This routine calls ::Ax88772UsbCommand to request the MAC

+  address from the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [out] pMacAddress      Address of a six byte buffer to receive the MAC address.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772MacAddressGet (

+  IN NIC_DEVICE * pNicDevice,

+  OUT UINT8 * pMacAddress

+  );

+

+/**

+  Set the MAC address

+

+  This routine calls ::Ax88772UsbCommand to set the MAC address

+  in the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the new MAC address.

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772MacAddressSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  );

+

+/**

+  Clear the multicast hash table

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+**/

+VOID

+Ax88772MulticastClear (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  Enable a multicast address in the multicast hash table

+

+  This routine calls ::Ax88772Crc to compute the hash bit for

+  this MAC address.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pMacAddress      Address of a six byte buffer to containing the MAC address.

+

+**/

+VOID

+Ax88772MulticastSet (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 * pMacAddress

+  );

+

+/**

+  Start the link negotiation

+

+  This routine calls ::Ax88772PhyWrite to start the PHY's link

+  negotiation.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The link negotiation was started.

+  @retval other                Failed to start the link negotiation.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkStart (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+/**

+  Complete the negotiation of the PHY link

+

+  This routine calls ::Ax88772PhyRead to determine if the

+  link negotiation is complete.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in, out] pPollCount  Address of number of times this routine was polled

+  @param [out] pbComplete      Address of boolean to receive complate status.

+  @param [out] pbLinkUp        Address of boolean to receive link status, TRUE=up.

+  @param [out] pbHiSpeed       Address of boolean to receive link speed, TRUE=100Mbps.

+  @param [out] pbFullDuplex    Address of boolean to receive link duplex, TRUE=full.

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772NegotiateLinkComplete (

+  IN NIC_DEVICE * pNicDevice,

+  IN OUT UINTN * pPollCount,

+  OUT BOOLEAN * pbComplete,

+  OUT BOOLEAN * pbLinkUp,

+  OUT BOOLEAN * pbHiSpeed,

+  OUT BOOLEAN * pbFullDuplex

+  );

+

+/**

+  Read a register from the PHY

+

+  This routine calls ::Ax88772UsbCommand to read a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in, out] pPhyData    Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data is available.

+  @retval other                The PHY data is not valid.

+

+**/

+EFI_STATUS

+Ax88772PhyRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN OUT UINT16 * pPhyData

+  );

+

+/**

+  Write to a PHY register

+

+  This routine calls ::Ax88772UsbCommand to write a PHY register.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RegisterAddress  Number of the register to read.

+  @param [in] PhyData          Address of a buffer to receive the PHY register value

+

+  @retval EFI_SUCCESS          The PHY data was written.

+  @retval other                Failed to wwrite the PHY register.

+

+**/

+EFI_STATUS

+Ax88772PhyWrite (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT8 RegisterAddress,

+  IN UINT16 PhyData

+  );

+

+/**

+  Reset the AX88772

+

+  This routine uses ::Ax88772UsbCommand to reset the network

+  adapter.  This routine also uses ::Ax88772PhyWrite to reset

+  the PHY.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+

+  @retval EFI_SUCCESS          The MAC address is available.

+  @retval other                The MAC address is not valid.

+

+**/

+EFI_STATUS

+Ax88772Reset (

+  IN NIC_DEVICE * pNicDevice

+  );

+

+VOID

+Ax88772ChkLink (

+  IN NIC_DEVICE * pNicDevice,

+  IN BOOLEAN bUpdateLink

+  );

+

+/**

+  Receive a frame from the network.

+

+  This routine polls the USB receive interface for a packet.  If a packet

+  is available, this routine adds the receive packet to the list of

+  pending receive packets.

+

+  This routine calls ::Ax88772NegotiateLinkComplete to verify

+  that the link is up.  This routine also calls ::SN_Reset to

+  reset the network adapter when necessary.  Finally this

+  routine attempts to receive one or more packets from the

+  network adapter.

+

+  @param [in] pNicDevice  Pointer to the NIC_DEVICE structure

+  @param [in] bUpdateLink TRUE = Update link status

+

+**/

+VOID

+Ax88772Rx (

+  IN NIC_DEVICE * pNicDevice,

+  IN BOOLEAN bUpdateLink

+  );

+

+/**

+  Enable or disable the receiver

+

+  This routine calls ::Ax88772UsbCommand to update the

+  receiver state.  This routine also calls ::Ax88772MacAddressSet

+  to establish the MAC address for the network adapter.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] RxFilter         Simple network RX filter mask value

+

+  @retval EFI_SUCCESS          The MAC address was set.

+  @retval other                The MAC address was not set.

+

+**/

+EFI_STATUS

+Ax88772RxControl (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 RxFilter

+  );

+

+/**

+  Read an SROM location

+

+  This routine calls ::Ax88772UsbCommand to read data from the

+  SROM.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] Address          SROM address

+  @param [out] pData           Buffer to receive the data

+

+  @retval EFI_SUCCESS          The read was successful

+  @retval other                The read failed

+

+**/

+EFI_STATUS

+Ax88772SromRead (

+  IN NIC_DEVICE * pNicDevice,

+  IN UINT32 Address,

+  OUT UINT16 * pData

+  );

+

+/**

+  Send a command to the USB device.

+

+  @param [in] pNicDevice       Pointer to the NIC_DEVICE structure

+  @param [in] pRequest         Pointer to the request structure

+  @param [in, out] pBuffer     Data buffer address

+

+  @retval EFI_SUCCESS          The USB transfer was successful

+  @retval other                The USB transfer failed

+

+**/

+EFI_STATUS

+Ax88772UsbCommand (

+  IN NIC_DEVICE * pNicDevice,

+  IN USB_DEVICE_REQUEST * pRequest,

+  IN OUT VOID * pBuffer

+  );

+

+//------------------------------------------------------------------------------

+// EFI Component Name Protocol Support

+//------------------------------------------------------------------------------

+

+extern EFI_COMPONENT_NAME_PROTOCOL   gComponentName;  ///<  Component name protocol declaration

+extern EFI_COMPONENT_NAME2_PROTOCOL  gComponentName2; ///<  Component name 2 protocol declaration

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppDriverName     A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppDriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] ControllerHandle  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+  @param [in] ChildHandle       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppControllerName A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  EFI_HANDLE ControllerHandle,

+  IN OPTIONAL EFI_HANDLE ChildHandle,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppControllerName

+  );

+  

+VOID 

+FillPkt2Queue (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN BufLength);

+

+//------------------------------------------------------------------------------

+

+#endif  //  _AX88772_H_

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
new file mode 100644
index 0000000..32a62f6
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
@@ -0,0 +1,67 @@
+## @file

+# Component description file for ASIX AX88772 USB/Ethernet driver.

+#

+# This module provides support for the ASIX AX88772 USB/Ethernet adapter.

+# Copyright (c) 2011-2013, 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.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010018

+  BASE_NAME                      = Ax88772b

+  FILE_GUID                      = 95C8D770-E1A4-4422-B263-E32F14FD8186

+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER

+  VERSION_STRING                 = 1.0

+

+  ENTRY_POINT                    = EntryPoint

+

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+

+[Sources.common]

+  Ax88772.h

+  Ax88772.c

+  ComponentName.c

+  DriverBinding.c

+  SimpleNetwork.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+[LibraryClasses]

+  UefiLib

+  UefiBootServicesTableLib

+  BaseMemoryLib

+  DebugLib

+  UefiRuntimeLib

+  UefiDriverEntryPoint

+

+[Protocols]  

+  gEfiDevicePathProtocolGuid           ## BY_START

+  gEfiSimpleNetworkProtocolGuid        ## BY_START

+  gEfiUsbIoProtocolGuid                ## TO_START

+

+[Depex]

+  gEfiBdsArchProtocolGuid AND

+  gEfiCpuArchProtocolGuid AND

+  gEfiMetronomeArchProtocolGuid AND

+  gEfiMonotonicCounterArchProtocolGuid AND

+  gEfiRealTimeClockArchProtocolGuid AND

+  gEfiResetArchProtocolGuid AND

+  gEfiRuntimeArchProtocolGuid AND

+  gEfiSecurityArchProtocolGuid AND

+  gEfiTimerArchProtocolGuid AND

+  gEfiVariableWriteArchProtocolGuid AND

+  gEfiVariableArchProtocolGuid AND

+  gEfiWatchdogTimerArchProtocolGuid

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentName.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentName.c
new file mode 100644
index 0000000..e78d76b
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentName.c
@@ -0,0 +1,181 @@
+/** @file

+  UEFI Component Name(2) protocol implementation.

+

+  Copyright (c) 2011, Intel Corporation

+  All rights reserved. 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.

+

+**/

+

+#include "Ax88772.h"

+

+/**

+  EFI Component Name Protocol declaration

+**/

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gComponentName = {

+  GetDriverName,

+  GetControllerName,

+  "eng"

+};

+

+/**

+  EFI Component Name 2 Protocol declaration

+**/

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GetControllerName,

+  "en"

+};

+

+

+/**

+  Driver name table declaration

+**/

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE

+mDriverNameTable[] = {

+  {"eng;en", L"ASIX AX88772B Ethernet Driver 1.0"},

+  {NULL,  NULL}

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppDriverName     A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppDriverName

+  )

+{

+  EFI_STATUS Status;

+

+  Status = LookupUnicodeString2 (

+             pLanguage,

+             pThis->SupportedLanguages,

+             mDriverNameTable,

+             ppDriverName,

+             (BOOLEAN)(pThis == &gComponentName)

+             );

+

+  return Status;

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param [in] pThis             A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+  @param [in] ControllerHandle  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+  @param [in] ChildHandle       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+  @param [in] pLanguage         A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 3066 or ISO 639-2 language code format.

+  @param [out] ppControllerName A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL * pThis,

+  IN  EFI_HANDLE ControllerHandle,

+  IN OPTIONAL EFI_HANDLE ChildHandle,

+  IN  CHAR8 * pLanguage,

+  OUT CHAR16 ** ppControllerName

+  )

+{

+  EFI_STATUS Status;

+

+  //

+  // Set the controller name

+  //

+  *ppControllerName = L"ASIX AX88772B USB Fast Ethernet Controller";

+  Status = EFI_SUCCESS;

+

+  //

+  // Return the operation status

+  //

+

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding.c
new file mode 100644
index 0000000..3b73040
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding.c
@@ -0,0 +1,658 @@
+/** @file

+  Implement the driver binding protocol for Asix AX88772 Ethernet driver.

+                     

+  Copyright (c) 2011-2013, Intel Corporation

+  All rights reserved. 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.

+

+**/

+

+#include "Ax88772.h"

+

+/**

+  Verify the controller type

+

+  @param [in] pThis                Protocol instance pointer.

+  @param [in] Controller           Handle of device to test.

+  @param [in] pRemainingDevicePath Not used.

+

+  @retval EFI_SUCCESS          This driver supports this device.

+  @retval other                This driver does not support this device.

+

+**/

+EFI_STATUS

+EFIAPI

+DriverSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL * pThis,

+  IN EFI_HANDLE Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath

+  )

+{

+  EFI_USB_DEVICE_DESCRIPTOR Device;

+  EFI_USB_IO_PROTOCOL * pUsbIo;

+  EFI_STATUS Status;

+  //

+  //  Connect to the USB stack

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &pUsbIo,

+                  pThis->DriverBindingHandle,         

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (!EFI_ERROR ( Status )) {

+

+    //

+    //  Get the interface descriptor to check the USB class and find a transport

+    //  protocol handler.

+    //

+    Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device );

+    if (EFI_ERROR ( Status )) {

+    	Status = EFI_UNSUPPORTED;

+    }

+    else {

+      //

+      //  Validate the adapter

+      //   

+      if ( VENDOR_ID == Device.IdVendor ) {

+

+        if (PRODUCT_ID == Device.IdProduct) {

+            DEBUG ((EFI_D_INFO, "Found the AX88772B\r\n"));

+        }

+		    else  {

+			     Status = EFI_UNSUPPORTED;

+		    }

+      }

+	    else {

+		      Status = EFI_UNSUPPORTED;

+       }   

+    }

+   

+    //

+    //  Done with the USB stack

+    //

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiUsbIoProtocolGuid,

+           pThis->DriverBindingHandle,

+           Controller

+           );

+  }

+  return Status;

+}

+

+

+/**

+  Start this driver on Controller by opening UsbIo and DevicePath protocols.

+  Initialize PXE structures, create a copy of the Controller Device Path with the

+  NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol

+  on the newly created Device Path.

+

+  @param [in] pThis                Protocol instance pointer.

+  @param [in] Controller           Handle of device to work with.

+  @param [in] pRemainingDevicePath Not used, always produce all possible children.

+

+  @retval EFI_SUCCESS          This driver is added to Controller.

+  @retval other                This driver does not support this device.

+

+**/

+EFI_STATUS

+EFIAPI

+DriverStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL * pThis,

+  IN EFI_HANDLE Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath

+  )

+{

+

+	EFI_STATUS						Status;

+	NIC_DEVICE						*pNicDevice;

+	UINTN							LengthInBytes;

+	EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath = NULL;

+	MAC_ADDR_DEVICE_PATH            MacDeviceNode;

+

+  //

+	//  Allocate the device structure

+	//

+	LengthInBytes = sizeof ( *pNicDevice );

+	Status = gBS->AllocatePool (

+                  EfiRuntimeServicesData,

+                  LengthInBytes,

+                  (VOID **) &pNicDevice

+                  );

+

+	if (EFI_ERROR (Status)) {

+		DEBUG ((EFI_D_ERROR, "gBS->AllocatePool:pNicDevice ERROR Status = %r\n", Status));

+		goto EXIT;

+	}

+	

+	//

+  //  Set the structure signature

+  //

+  ZeroMem ( pNicDevice, LengthInBytes );

+  pNicDevice->Signature = DEV_SIGNATURE;

+

+	Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiUsbIoProtocolGuid,

+                    (VOID **) &pNicDevice->pUsbIo,

+                    pThis->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_BY_DRIVER

+                    );

+

+	if (EFI_ERROR (Status)) {

+		DEBUG ((EFI_D_ERROR, "gBS->OpenProtocol:EFI_USB_IO_PROTOCOL ERROR Status = %r\n", Status));

+		gBS->FreePool ( pNicDevice );

+		goto EXIT;

+	}

+

+	//

+  //  Initialize the simple network protocol

+  //

+	Status = SN_Setup ( pNicDevice );

+

+	if (EFI_ERROR(Status)){

+	   DEBUG ((EFI_D_ERROR, "SN_Setup ERROR Status = %r\n", Status));

+	   gBS->CloseProtocol (

+					Controller,

+					&gEfiUsbIoProtocolGuid,

+					pThis->DriverBindingHandle,

+					Controller

+					);

+		  gBS->FreePool ( pNicDevice );

+		  goto EXIT;

+  }

+

+	//

+  // Set Device Path

+  //  			

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiDevicePathProtocolGuid,

+                  (VOID **) &ParentDevicePath,

+				          pThis->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+	if (EFI_ERROR(Status)) {

+        DEBUG ((EFI_D_ERROR, "gBS->OpenProtocol:EFI_DEVICE_PATH_PROTOCOL error. Status = %r\n",

+            Status));        

+		    gBS->CloseProtocol (

+					Controller,

+					&gEfiUsbIoProtocolGuid,

+					pThis->DriverBindingHandle,

+					Controller

+					);

+		  gBS->FreePool ( pNicDevice );

+		  goto EXIT;

+	}

+

+  ZeroMem (&MacDeviceNode, sizeof (MAC_ADDR_DEVICE_PATH));

+  MacDeviceNode.Header.Type = MESSAGING_DEVICE_PATH;

+  MacDeviceNode.Header.SubType = MSG_MAC_ADDR_DP;

+

+  SetDevicePathNodeLength (&MacDeviceNode.Header, sizeof (MAC_ADDR_DEVICE_PATH));

+      			

+  CopyMem (&MacDeviceNode.MacAddress,

+      								&pNicDevice->SimpleNetworkData.CurrentAddress,

+      								PXE_HWADDR_LEN_ETHER);

+      								

+  MacDeviceNode.IfType = pNicDevice->SimpleNetworkData.IfType;

+

+  pNicDevice->MyDevPath = AppendDevicePathNode (

+                                          ParentDevicePath,

+                                          (EFI_DEVICE_PATH_PROTOCOL *) &MacDeviceNode

+                                          );

+

+	pNicDevice->Controller = NULL;

+

+	//

+  //  Install both the simple network and device path protocols.

+  //

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                          &pNicDevice->Controller,

+                          &gEfiCallerIdGuid,

+                          pNicDevice,

+                          &gEfiSimpleNetworkProtocolGuid,            

+                          &pNicDevice->SimpleNetwork,

+						              &gEfiDevicePathProtocolGuid,

+						              pNicDevice->MyDevPath,

+                          NULL

+                          );

+

+	if (EFI_ERROR(Status)){

+		DEBUG ((EFI_D_ERROR, "gBS->InstallMultipleProtocolInterfaces error. Status = %r\n",

+            Status)); 

+		gBS->CloseProtocol (

+					               Controller,

+					               &gEfiDevicePathProtocolGuid,

+					               pThis->DriverBindingHandle,

+					               Controller);

+	   gBS->CloseProtocol (

+					Controller,

+					&gEfiUsbIoProtocolGuid,

+					pThis->DriverBindingHandle,

+					Controller

+					);

+		  gBS->FreePool ( pNicDevice );

+		  goto EXIT;

+	}

+

+	//

+	// Open For Child Device

+	//

+	Status = gBS->OpenProtocol (                                                                         

+                  Controller,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &pNicDevice->pUsbIo,

+                  pThis->DriverBindingHandle,

+                  pNicDevice->Controller,

+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER

+                  );

+

+	if (EFI_ERROR(Status)){

+	   gBS->UninstallMultipleProtocolInterfaces (

+              &pNicDevice->Controller,

+                          &gEfiCallerIdGuid,

+                          pNicDevice,

+                          &gEfiSimpleNetworkProtocolGuid,            

+                          &pNicDevice->SimpleNetwork,

+						              &gEfiDevicePathProtocolGuid,

+						              pNicDevice->MyDevPath,

+                          NULL

+                          );

+		gBS->CloseProtocol (

+					               Controller,

+					               &gEfiDevicePathProtocolGuid,

+					               pThis->DriverBindingHandle,

+					               Controller);

+	   gBS->CloseProtocol (

+					Controller,

+					&gEfiUsbIoProtocolGuid,

+					pThis->DriverBindingHandle,

+					Controller

+					);

+		  gBS->FreePool ( pNicDevice );

+	}

+

+EXIT:

+	return Status;

+

+}

+

+/**

+  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and

+  closing the DevicePath and PciIo protocols on Controller.

+

+  @param [in] pThis                Protocol instance pointer.

+  @param [in] Controller           Handle of device to stop driver on.

+  @param [in] NumberOfChildren     How many children need to be stopped.

+  @param [in] pChildHandleBuffer   Not used.

+

+  @retval EFI_SUCCESS          This driver is removed Controller.

+  @retval EFI_DEVICE_ERROR     The device could not be stopped due to a device error.

+  @retval other                This driver was not removed from this device.

+

+**/

+EFI_STATUS

+EFIAPI

+DriverStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL * pThis,

+  IN  EFI_HANDLE Controller,

+  IN  UINTN NumberOfChildren,

+  IN  EFI_HANDLE * ChildHandleBuffer

+  )

+{

+		BOOLEAN                                   AllChildrenStopped;

+		UINTN                                     Index;

+		EFI_SIMPLE_NETWORK_PROTOCOL				  *SimpleNetwork;

+		EFI_STATUS                                Status = EFI_SUCCESS;

+		NIC_DEVICE								  *pNicDevice;

+		

+		//

+		// Complete all outstanding transactions to Controller.

+		// Don't allow any new transaction to Controller to be started.

+		//

+		if (NumberOfChildren == 0) {

+		

+		  Status = gBS->OpenProtocol (

+				                Controller,

+				                &gEfiSimpleNetworkProtocolGuid,

+				                (VOID **) &SimpleNetwork,

+				                pThis->DriverBindingHandle,

+				                Controller,

+				                EFI_OPEN_PROTOCOL_GET_PROTOCOL

+				                );

+				                

+			if (EFI_ERROR(Status)) {

+        //

+        // This is a 2nd type handle(multi-lun root), it needs to close devicepath

+        // and usbio protocol.

+        //

+        gBS->CloseProtocol (

+            Controller,

+            &gEfiDevicePathProtocolGuid,

+            pThis->DriverBindingHandle,

+            Controller

+            );

+        gBS->CloseProtocol (

+            Controller,

+            &gEfiUsbIoProtocolGuid,

+            pThis->DriverBindingHandle,

+            Controller

+            );

+        return EFI_SUCCESS;

+      }

+      

+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork );

+      

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+				                  Controller,				                  

+				                  &gEfiCallerIdGuid,

+                          pNicDevice,

+                          &gEfiSimpleNetworkProtocolGuid,            

+                          &pNicDevice->SimpleNetwork,

+						              &gEfiDevicePathProtocolGuid,

+						              pNicDevice->MyDevPath,

+                          NULL

+                          );

+                          

+      if (EFI_ERROR (Status)) {

+        return Status;

+      }

+		  //

+		  // Close the bus driver

+		  //

+		  Status = gBS->CloseProtocol (

+		                  Controller,

+		                  &gEfiDevicePathProtocolGuid,

+		                  pThis->DriverBindingHandle,

+		                  Controller

+		                  );

+

+		  if (EFI_ERROR(Status)){

+          DEBUG ((EFI_D_ERROR, "driver stop: gBS->CloseProtocol:EfiDevicePathProtocol error. Status %r\n", Status));

+		  }

+

+		  Status = gBS->CloseProtocol (

+		                  Controller,

+		                  &gEfiUsbIoProtocolGuid,

+		                  pThis->DriverBindingHandle,

+		                  Controller

+		                  );

+

+		  if (EFI_ERROR(Status)){

+          DEBUG ((EFI_D_ERROR, "driver stop: gBS->CloseProtocol:EfiUsbIoProtocol error. Status %r\n", Status));

+		  }

+      return EFI_SUCCESS;

+		} 

+		AllChildrenStopped = TRUE;

+

+		for (Index = 0; Index < NumberOfChildren; Index++) {

+

+				Status = gBS->OpenProtocol (

+				                ChildHandleBuffer[Index],

+				                &gEfiSimpleNetworkProtocolGuid,

+				                (VOID **) &SimpleNetwork,

+				                pThis->DriverBindingHandle,

+				                Controller,

+				                EFI_OPEN_PROTOCOL_GET_PROTOCOL

+				                );

+				                

+				if (EFI_ERROR (Status)) {

+          AllChildrenStopped = FALSE;

+          DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening SimpleNetwork\n", (UINT32)Index));

+          continue;

+        } 

+        

+        pNicDevice = DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork );

+        

+        gBS->CloseProtocol (

+				                    Controller,

+				                    &gEfiUsbIoProtocolGuid,

+				                    pThis->DriverBindingHandle,

+				                    ChildHandleBuffer[Index]

+				                    ); 

+				                    

+				Status = gBS->UninstallMultipleProtocolInterfaces (

+				                  ChildHandleBuffer[Index],				                  

+				                  &gEfiCallerIdGuid,

+                          pNicDevice,

+                          &gEfiSimpleNetworkProtocolGuid,            

+                          &pNicDevice->SimpleNetwork,

+						              &gEfiDevicePathProtocolGuid,

+						              pNicDevice->MyDevPath,

+                          NULL

+                          );

+                          

+        if (EFI_ERROR (Status)) {

+            Status = gBS->OpenProtocol (                                                                         

+                  Controller,

+                  &gEfiUsbIoProtocolGuid,

+                  (VOID **) &pNicDevice->pUsbIo,

+                  pThis->DriverBindingHandle,

+                  ChildHandleBuffer[Index],

+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER

+                  );

+        }

+        else {

+            int i;

+            RX_PKT * pCurr = pNicDevice->QueueHead;

+            RX_PKT * pFree;

+            

+            for ( i = 0 ; i < MAX_QUEUE_SIZE ; i++) {

+                 if ( NULL != pCurr ) {

+                    pFree = pCurr;

+                    pCurr = pCurr->pNext;

+                    gBS->FreePool (pFree);

+                 }

+            }

+            

+            if ( NULL != pNicDevice->pRxTest)

+						    gBS->FreePool (pNicDevice->pRxTest);

+

+					 if ( NULL != pNicDevice->pTxTest)

+						    gBS->FreePool (pNicDevice->pTxTest);

+

+           if ( NULL != pNicDevice->MyDevPath)

+					       gBS->FreePool (pNicDevice->MyDevPath);

+		  

+				    if ( NULL != pNicDevice)

+                  gBS->FreePool (pNicDevice);

+        }

+    }

+        

+        if (!AllChildrenStopped) {

+                return EFI_DEVICE_ERROR;

+        }

+        return EFI_SUCCESS;

+}

+

+

+/**

+  Driver binding protocol declaration

+**/

+EFI_DRIVER_BINDING_PROTOCOL  gDriverBinding = {

+  DriverSupported,

+  DriverStart,

+  DriverStop,

+  0xa,

+  NULL,

+  NULL

+};

+

+

+/**

+  Ax88772 driver unload routine.

+

+  @param [in] ImageHandle       Handle for the image.

+

+  @retval EFI_SUCCESS           Image may be unloaded

+

+**/

+EFI_STATUS

+EFIAPI

+DriverUnload (

+  IN EFI_HANDLE ImageHandle

+  )

+{

+  UINTN BufferSize;

+  UINTN Index;

+  UINTN Max;

+  EFI_HANDLE * pHandle;

+  EFI_STATUS Status;

+

+  //

+  //  Determine which devices are using this driver

+  //

+  BufferSize = 0;

+  pHandle = NULL;

+  Status = gBS->LocateHandle (

+                  ByProtocol,

+                  &gEfiCallerIdGuid,

+                  NULL,

+                  &BufferSize,

+                  NULL );

+  if ( EFI_BUFFER_TOO_SMALL == Status ) {

+    for ( ; ; ) {

+      //

+      //  One or more block IO devices are present

+      //

+      Status = gBS->AllocatePool (

+                      EfiRuntimeServicesData,

+                      BufferSize,

+                      (VOID **) &pHandle

+                      );

+      if ( EFI_ERROR ( Status )) {

+        DEBUG ((EFI_D_ERROR, "Insufficient memory, failed handle buffer allocation\r\n"));

+        break;

+      }

+

+      //

+      //  Locate the block IO devices

+      //

+      Status = gBS->LocateHandle (

+                      ByProtocol,

+                      &gEfiCallerIdGuid,

+                      NULL,

+                      &BufferSize,

+                      pHandle );

+      if ( EFI_ERROR ( Status )) {

+        //

+        //  Error getting handles

+        //

+        break;

+      }

+      

+      //

+      //  Remove any use of the driver

+      //

+      Max = BufferSize / sizeof ( pHandle[ 0 ]);

+      for ( Index = 0; Max > Index; Index++ ) {

+        Status = DriverStop ( &gDriverBinding,

+                              pHandle[ Index ],

+                              0,

+                              NULL );

+        if ( EFI_ERROR ( Status )) {

+          DEBUG ((EFI_D_ERROR, "WARNING - Failed to shutdown the driver on handle %08x\r\n", pHandle[ Index ]));

+          break;

+        }

+      }

+      break;

+    }

+  }

+  else {

+    if ( EFI_NOT_FOUND == Status ) {

+      //

+      //  No devices were found

+      //

+      Status = EFI_SUCCESS;

+    }

+  }

+

+  //

+  //  Free the handle array          

+  //

+  if ( NULL != pHandle ) {

+    gBS->FreePool ( pHandle );

+  }

+

+  //

+  //  Remove the protocols installed by the EntryPoint routine.

+  //

+  if ( !EFI_ERROR ( Status )) {

+    gBS->UninstallMultipleProtocolInterfaces (

+            ImageHandle,

+            &gEfiDriverBindingProtocolGuid,

+            &gDriverBinding,                              

+            &gEfiComponentNameProtocolGuid,

+            &gComponentName,

+            &gEfiComponentName2ProtocolGuid,

+            &gComponentName2,

+            NULL

+            );

+

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+            "Removed:   gEfiComponentName2ProtocolGuid from 0x%08x\r\n",

+            ImageHandle ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Removed:   gEfiComponentNameProtocolGuid from 0x%08x\r\n",

+              ImageHandle ));

+    DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,

+              "Removed:   gEfiDriverBindingProtocolGuid from 0x%08x\r\n",

+              ImageHandle ));

+

+  }

+

+  return Status;

+}

+

+

+/**

+Ax88772 driver entry point.

+

+@param [in] ImageHandle       Handle for the image.

+@param [in] pSystemTable      Address of the system table.

+

+@retval EFI_SUCCESS           Image successfully loaded.

+

+**/

+EFI_STATUS

+EFIAPI

+EntryPoint (

+  IN EFI_HANDLE ImageHandle,

+  IN EFI_SYSTEM_TABLE * pSystemTable

+  )

+{

+  EFI_STATUS    Status;

+

+  //

+  //  Add the driver to the list of drivers

+  //

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             pSystemTable,

+             &gDriverBinding,

+             ImageHandle,

+             &gComponentName,

+             &gComponentName2

+             );

+  if ( !EFI_ERROR ( Status )) {

+    DEBUG ((EFI_D_INFO, "Installed: gEfiDriverBindingProtocolGuid on   0x%08x\r\n",

+              ImageHandle));

+    DEBUG ((EFI_D_INFO, "Installed: gEfiComponentNameProtocolGuid on   0x%08x\r\n",

+              ImageHandle));

+    DEBUG ((EFI_D_INFO,"Installed: gEfiComponentName2ProtocolGuid on   0x%08x\r\n",

+              ImageHandle ));

+

+  }

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork.c b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork.c
new file mode 100644
index 0000000..9eeb61f
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork.c
@@ -0,0 +1,1665 @@
+/** @file

+  Provides the Simple Network functions.

+

+  Copyright (c) 2011 - 2013, Intel Corporation

+  All rights reserved. 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.

+

+**/

+

+#include "Ax88772.h"

+

+/**

+  This function updates the filtering on the receiver.

+

+  This support routine calls ::Ax88772MacAddressSet to update

+  the MAC address.  This routine then rebuilds the multicast

+  hash by calling ::Ax88772MulticastClear and ::Ax88772MulticastSet.

+  Finally this routine enables the receiver by calling

+  ::Ax88772RxControl.

+                                                                                  

+  @param [in] pSimpleNetwork    Simple network mode pointer  

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+ReceiveFilterUpdate (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+  UINT32 Index;

+

+  //

+  // Set the MAC address

+  //

+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+  pMode = pSimpleNetwork->Mode;

+

+  //

+  // Clear the multicast hash table

+  //

+  Ax88772MulticastClear ( pNicDevice );

+

+  //

+  // Load the multicast hash table

+  //

+  if ( 0 != ( pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) {

+      for ( Index = 0; Index < pMode->MCastFilterCount; Index++ ) {

+        //

+        // Enable the next multicast address

+        //

+        Ax88772MulticastSet ( pNicDevice,

+                              &pMode->MCastFilter[ Index ].Addr[0]);

+      }

+  }

+

+  Status = Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSetting );

+

+  return Status;

+}

+

+

+/**

+  This function updates the SNP driver status.

+  

+  This function gets the current interrupt and recycled transmit

+  buffer status from the network interface.  The interrupt status

+  and the media status are returned as a bit mask in InterruptStatus.

+  If InterruptStatus is NULL, the interrupt status will not be read.

+  Upon successful return of the media status, the MediaPresent field

+  of EFI_SIMPLE_NETWORK_MODE will be updated to reflect any change

+  of media status.  If TxBuf is not NULL, a recycled transmit buffer

+  address will be retrived.  If a recycled transmit buffer address

+  is returned in TxBuf, then the buffer has been successfully

+  transmitted, and the status for that buffer is cleared.

+

+  This function calls ::Ax88772Rx to update the media status and

+  queue any receive packets.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] pInterruptStatus  A pointer to the bit mask of the current active interrupts.

+                                If this is NULL, the interrupt status will not be read from

+                                the device.  If this is not NULL, the interrupt status will

+                                be read from teh device.  When the interrupt status is read,

+                                it will also be cleared.  Clearing the transmit interrupt

+                                does not empty the recycled transmit buffer array.

+  @param [out] ppTxBuf          Recycled transmit buffer address.  The network interface will

+                                not transmit if its internal recycled transmit buffer array is

+                                full.  Reading the transmit buffer does not clear the transmit

+                                interrupt.  If this is NULL, then the transmit buffer status

+                                will not be read.  If there are not transmit buffers to recycle

+                                and TxBuf is not NULL, *TxBuf will be set to NULL.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_GetStatus (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  OUT UINT32 * pInterruptStatus,

+  OUT VOID ** ppTxBuf

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+  BOOLEAN bFullDuplex;

+  BOOLEAN bLinkUp;

+  BOOLEAN bSpeed100;

+  EFI_TPL TplPrevious;

+ 

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Return the transmit buffer

+    //

+    

+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+    if (( NULL != ppTxBuf ) && ( NULL != pNicDevice->pTxBuffer )) {

+     		 *ppTxBuf = pNicDevice->pTxBuffer;

+     		 pNicDevice->pTxBuffer = NULL;

+   	}

+    

+    //

+    // Determine if interface is running

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+

+      if ( pNicDevice->LinkIdleCnt > MAX_LINKIDLE_THRESHOLD) {

+

+          bLinkUp = pNicDevice->bLinkUp;

+          bSpeed100 = pNicDevice->b100Mbps;

+          bFullDuplex = pNicDevice->bFullDuplex;

+          Status = Ax88772NegotiateLinkComplete ( pNicDevice,

+                                            &pNicDevice->PollCount,

+                                            &pNicDevice->bComplete,

+                                            &pNicDevice->bLinkUp,

+                                            &pNicDevice->b100Mbps,

+                                            &pNicDevice->bFullDuplex );

+

+          //

+          // Determine if the autonegotiation is complete

+          //

+          if ( pNicDevice->bComplete ) {

+              if ( pNicDevice->bLinkUp ) {

+                  if (( bSpeed100 && ( !pNicDevice->b100Mbps ))

+                      || (( !bSpeed100 ) && pNicDevice->b100Mbps )

+                      || ( bFullDuplex && ( !pNicDevice->bFullDuplex ))

+                      || (( !bFullDuplex ) && pNicDevice->bFullDuplex )) {

+                          pNicDevice->PollCount = 0;

+                          DEBUG (( EFI_D_INFO , "Reset to establish proper link setup: %d Mbps, %a duplex\r\n",

+                                    pNicDevice->b100Mbps ? 100 : 10, pNicDevice->bFullDuplex ? "Full" : "Half"));

+                          Status = SN_Reset ( &pNicDevice->SimpleNetwork, FALSE );

+                  }

+                  if (( !bLinkUp ) && pNicDevice->bLinkUp ) {

+                      //

+                      // Display the autonegotiation status

+                      //

+                      DEBUG (( EFI_D_INFO , "Link: Up, %d Mbps, %a duplex\r\n",

+                                pNicDevice->b100Mbps ? 100 : 10, pNicDevice->bFullDuplex ? "Full" : "Half"));

+

+                  }

+                  pNicDevice->LinkIdleCnt = 0;

+            }

+        }

+        //

+        //  Update the link status

+        //

+        if ( bLinkUp && ( !pNicDevice->bLinkUp )) {

+            DEBUG (( EFI_D_INFO , "Link: Down\r\n"));

+        }

+      }

+

+      pMode->MediaPresent = pNicDevice->bLinkUp;

+      //

+      // Return the interrupt status

+      //

+      if ( NULL != pInterruptStatus ) {

+        *pInterruptStatus = 0;

+      }   

+      Status = EFI_SUCCESS;

+    }

+    else {

+      if ( EfiSimpleNetworkStarted == pMode->State ) {

+        Status = EFI_DEVICE_ERROR;

+      }

+      else {

+        Status = EFI_NOT_STARTED;

+      }

+    }

+      

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  gBS->RestoreTPL(TplPrevious) ;

+

+  return Status;

+}

+

+

+/**

+  Resets the network adapter and allocates the transmit and receive buffers

+  required by the network interface; optionally, also requests allocation of

+  additional transmit and receive buffers.  This routine must be called before

+  any other routine in the Simple Network protocol is called.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] ExtraRxBufferSize Size in bytes to add to the receive buffer allocation

+  @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buffer allocation

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_OUT_OF_RESORUCES  There was not enough memory for the transmit and receive buffers

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Initialize (                                              

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN ExtraRxBufferSize,

+  IN UINTN ExtraTxBufferSize

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+  UINT32  TmpState;

+   EFI_TPL TplPrevious;

+   

+   TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Determine if the interface is already started

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStarted == pMode->State ) {

+      if (( 0 == ExtraRxBufferSize ) && ( 0 == ExtraTxBufferSize )) {

+        //

+        // Start the adapter

+        //

+        TmpState = pMode->State;

+        pMode->State = EfiSimpleNetworkInitialized;

+        Status = SN_Reset ( pSimpleNetwork, FALSE );

+        if ( EFI_ERROR ( Status )) {

+          //

+          // Update the network state

+          //

+          pMode->State = TmpState;

+          DEBUG (( EFI_D_ERROR , "SN_reset failed\n"));

+        }

+      }

+      else {

+        DEBUG (( EFI_D_ERROR , "Increase ExtraRxBufferSize = %d ExtraTxBufferSize=%d\n", 

+              ExtraRxBufferSize, ExtraTxBufferSize));

+        Status = EFI_UNSUPPORTED;

+      }

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  gBS->RestoreTPL (TplPrevious);

+

+  return Status;

+}

+

+

+/**

+  This function converts a multicast IP address to a multicast HW MAC address

+  for all packet transactions.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bIPv6             Set to TRUE if the multicast IP address is IPv6 [RFC2460].

+                                Set to FALSE if the multicast IP address is IPv4 [RFC 791].

+  @param [in] pIP               The multicast IP address that is to be converted to a

+                                multicast HW MAC address.

+  @param [in] pMAC              The multicast HW MAC address that is to be generated from IP.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_MCastIPtoMAC (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bIPv6,

+  IN EFI_IP_ADDRESS * pIP,

+  OUT EFI_MAC_ADDRESS * pMAC

+  )

+{

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  // Get pointer to SNP driver instance for *this.

+  //

+  if (pSimpleNetwork == NULL) {

+    gBS->RestoreTPL(TplPrevious);

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (pIP == NULL || pMAC == NULL) {

+    gBS->RestoreTPL(TplPrevious);

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (bIPv6){

+    Status = EFI_UNSUPPORTED;

+  }  

+  else {

+      //

+      // check if the ip given is a mcast IP

+      //

+      if ((pIP->v4.Addr[0] & 0xF0) != 0xE0) {

+        gBS->RestoreTPL(TplPrevious);

+        return EFI_INVALID_PARAMETER;

+      }

+      else {

+        if (pSimpleNetwork->Mode->State == EfiSimpleNetworkInitialized)

+        {

+          pMAC->Addr[0] = 0x01;

+          pMAC->Addr[1] = 0x00;

+          pMAC->Addr[2] = 0x5e;

+          pMAC->Addr[3] = (UINT8) (pIP->v4.Addr[1] & 0x7f);

+          pMAC->Addr[4] = (UINT8) pIP->v4.Addr[2];

+          pMAC->Addr[5] = (UINT8) pIP->v4.Addr[3];

+          Status = EFI_SUCCESS;

+        }

+        else if (pSimpleNetwork->Mode->State == EfiSimpleNetworkStarted) {

+          Status = EFI_DEVICE_ERROR;

+        }

+        else {

+          Status = EFI_NOT_STARTED;

+        }

+        gBS->RestoreTPL(TplPrevious);

+      }

+  }

+  return Status;

+}

+

+

+/**

+  This function performs read and write operations on the NVRAM device

+  attached to a network interface.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] ReadWrite         TRUE for read operations, FALSE for write operations.

+  @param [in] Offset            Byte offset in the NVRAM device at which to start the

+                                read or write operation.  This must be a multiple of

+                                NvRamAccessSize and less than NvRamSize.

+  @param [in] BufferSize        The number of bytes to read or write from the NVRAM device.

+                                This must also be a multiple of NvramAccessSize.

+  @param [in, out] pBuffer      A pointer to the data buffer.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_NvData (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN ReadWrite,

+  IN UINTN Offset,

+  IN UINTN BufferSize,

+  IN OUT VOID * pBuffer

+  )

+{

+  EFI_STATUS Status;

+  //

+  // This is not currently supported

+  //

+  Status = EFI_UNSUPPORTED;

+  return Status;

+}

+

+VOID 

+FillPkt2Queue (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN BufLength)

+{

+

+  UINT16 * pLength;

+  UINT16 * pLengthBar;

+  UINT8* pData;

+  UINT32 offset;

+  NIC_DEVICE * pNicDevice;

+  

+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork);

+  for ( offset = 0; offset < BufLength; ){

+      pLength = (UINT16*) (pNicDevice->pBulkInBuff + offset);

+      pLengthBar = (UINT16*) (pNicDevice->pBulkInBuff + offset +2);

+      

+      *pLength &= 0x7ff;

+      *pLengthBar &= 0x7ff;

+      *pLengthBar |= 0xf800;

+      

+      if ((*pLength ^ *pLengthBar ) != 0xFFFF) {

+          DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength = %d\n", BufLength));

+          return;

+      }          

+      

+      if (TRUE == pNicDevice->pNextFill->f_Used) {

+        return;

+      }

+      else {

+          pData = pNicDevice->pBulkInBuff + offset + 4;

+          pNicDevice->pNextFill->f_Used = TRUE;

+          pNicDevice->pNextFill->Length = *pLength;

+          CopyMem (&pNicDevice->pNextFill->Data[0], pData, *pLength);

+          

+          pNicDevice->pNextFill = pNicDevice->pNextFill->pNext;

+          offset += ((*pLength + HW_HDR_LENGTH - 1) &~3) + 1;

+          pNicDevice->PktCntInQueue++;

+      }

+              

+  }

+}

+

+EFI_STATUS

+EFIAPI

+SN_Receive (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  OUT UINTN                      * pHeaderSize,

+  OUT UINTN                      * pBufferSize,

+  OUT VOID                       * pBuffer,

+  OUT EFI_MAC_ADDRESS            * pSrcAddr,

+  OUT EFI_MAC_ADDRESS            * pDestAddr,

+  OUT UINT16                     * pProtocol

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  UINT16 Type;

+  EFI_USB_IO_PROTOCOL *pUsbIo;

+  UINTN LengthInBytes;

+  UINT32 TransferStatus;

+  RX_PKT * pFirstFill;

+  TplPrevious = gBS->RaiseTPL (TPL_CALLBACK);

+  

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && 

+    ( NULL != pSimpleNetwork->Mode ) && 

+    (NULL != pBufferSize) && 

+    (NULL != pBuffer)) {

+    //

+    // The interface must be running

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+      //

+      // Update the link status

+      //

+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+      pNicDevice->LinkIdleCnt++;

+      pMode->MediaPresent = pNicDevice->bLinkUp;

+      

+      if ( pMode->MediaPresent && pNicDevice->bComplete) {

+      

+      

+        if (pNicDevice->PktCntInQueue != 0 ) {

+            DEBUG (( EFI_D_INFO, "pNicDevice->PktCntInQueue = %d\n",

+                pNicDevice->PktCntInQueue));

+        }

+        

+        LengthInBytes = MAX_BULKIN_SIZE;

+        if (pNicDevice->PktCntInQueue == 0 ){

+            //

+            // Attempt to do bulk in

+            //

+            SetMem (&pNicDevice->pBulkInBuff[0], 4, 0);

+            pUsbIo = pNicDevice->pUsbIo;

+            Status = pUsbIo->UsbBulkTransfer ( pUsbIo,

+                                       USB_ENDPOINT_DIR_IN | BULK_IN_ENDPOINT,

+                                       &pNicDevice->pBulkInBuff[0],

+                                       &LengthInBytes,

+                                       BULKIN_TIMEOUT,

+                                       &TransferStatus );

+                                       

+            if (LengthInBytes != 0 && !EFI_ERROR(Status) && !EFI_ERROR(TransferStatus) ){

+                FillPkt2Queue(pSimpleNetwork, LengthInBytes);

+            }

+        }

+        

+        pFirstFill = pNicDevice->pFirstFill;

+         

+        if (TRUE == pFirstFill->f_Used) {

+            ETHERNET_HEADER * pHeader;

+            pNicDevice->LinkIdleCnt = 0;

+            CopyMem (pBuffer,  &pFirstFill->Data[0], pFirstFill->Length);

+            pHeader = (ETHERNET_HEADER *) &pFirstFill->Data[0];

+                     

+            DEBUG (( EFI_D_INFO, "RX: %02x-%02x-%02x-%02x-%02x-%02x " 

+                      "%02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x  %d bytes\r\n",

+                      pFirstFill->Data[0],

+                      pFirstFill->Data[1],

+                      pFirstFill->Data[2],

+                      pFirstFill->Data[3],

+                      pFirstFill->Data[4],

+                      pFirstFill->Data[5],

+                      pFirstFill->Data[6],

+                      pFirstFill->Data[7],

+                      pFirstFill->Data[8],

+                      pFirstFill->Data[9],

+                      pFirstFill->Data[10],

+                      pFirstFill->Data[11],

+                      pFirstFill->Data[12],

+                      pFirstFill->Data[13],

+                      pFirstFill->Length));   

+            

+            if ( NULL != pHeaderSize ) {

+              *pHeaderSize = sizeof ( *pHeader );

+            }

+            if ( NULL != pDestAddr ) {

+               CopyMem ( pDestAddr, &pHeader->dest_addr, PXE_HWADDR_LEN_ETHER );

+            }

+            if ( NULL != pSrcAddr ) {

+             CopyMem ( pSrcAddr, &pHeader->src_addr, PXE_HWADDR_LEN_ETHER );

+            }

+            if ( NULL != pProtocol ) {

+              Type = pHeader->type;

+              Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));

+              *pProtocol = Type;

+            }

+            Status = EFI_SUCCESS;

+            if (*pBufferSize < pFirstFill->Length) {

+                  DEBUG (( EFI_D_ERROR, "RX: Buffer was too small"));

+                  Status = EFI_BUFFER_TOO_SMALL;

+            }

+            *pBufferSize =  pFirstFill->Length;

+            pFirstFill->f_Used = FALSE;

+            pNicDevice->pFirstFill = pFirstFill->pNext;

+            pNicDevice->PktCntInQueue--;

+        }

+        else {

+            pNicDevice->LinkIdleCnt++;

+            Status = EFI_NOT_READY;

+        }

+      }

+      else {

+        //

+        //  Link no up

+        //

+        pNicDevice->LinkIdleCnt++;

+        Status = EFI_NOT_READY; 

+      }

+      

+    }

+    else {

+      if (EfiSimpleNetworkStarted == pMode->State) {

+        Status = EFI_DEVICE_ERROR;

+      }

+      else {

+        Status = EFI_NOT_STARTED;

+      }

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }                              

+  gBS->RestoreTPL (TplPrevious);

+  return Status;

+}

+

+/**

+  This function is used to enable and disable the hardware and software receive

+  filters for the underlying network device.

+

+  The receive filter change is broken down into three steps:

+

+    1.  The filter mask bits that are set (ON) in the Enable parameter

+        are added to the current receive filter settings.

+

+    2.  The filter mask bits that are set (ON) in the Disable parameter

+        are subtracted from the updated receive filter settins.

+

+    3.  If the resulting filter settigns is not supported by the hardware

+        a more liberal setting is selected.

+

+  If the same bits are set in the Enable and Disable parameters, then the bits

+  in the Disable parameter takes precedence.

+

+  If the ResetMCastFilter parameter is TRUE, then the multicast address list

+  filter is disabled (irregardless of what other multicast bits are set in

+  the enable and Disable parameters).  The SNP->Mode->MCastFilterCount field

+  is set to zero.  The SNP->Mode->MCastFilter contents are undefined.

+

+  After enableing or disabling receive filter settings, software should

+  verify the new settings by checking the SNP->Mode->ReceeiveFilterSettings,

+  SNP->Mode->MCastFilterCount and SNP->Mode->MCastFilter fields.

+

+  Note: Some network drivers and/or devices will automatically promote

+  receive filter settings if the requested setting can not be honored.

+  For example, if a request for four multicast addresses is made and

+  the underlying hardware only supports two multicast addresses the

+  driver might set the promiscuous or promiscuous multicast receive filters

+  instead.  The receiving software is responsible for discarding any extra

+  packets that get through the hardware receive filters.

+

+  If ResetMCastFilter is TRUE, then the multicast receive filter list

+  on the network interface will be reset to the default multicast receive

+  filter list.  If ResetMCastFilter is FALSE, and this network interface

+  allows the multicast receive filter list to be modified, then the

+  MCastFilterCnt and MCastFilter are used to update the current multicast

+  receive filter list.  The modified receive filter list settings can be

+  found in the MCastFilter field of EFI_SIMPLE_NETWORK_MODE.

+

+  This routine calls ::ReceiveFilterUpdate to update the receive

+  state in the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] Enable            A bit mask of receive filters to enable on the network interface.

+  @param [in] Disable           A bit mask of receive filters to disable on the network interface.

+                                For backward compatibility with EFI 1.1 platforms, the

+                                EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit must be set

+                                when the ResetMCastFilter parameter is TRUE.

+  @param [in] bResetMCastFilter Set to TRUE to reset the contents of the multicast receive

+                                filters on the network interface to their default values.

+  @param [in] MCastFilterCnt    Number of multicast HW MAC address in the new MCastFilter list.

+                                This value must be less than or equal to the MaxMCastFilterCnt

+                                field of EFI_SIMPLE_NETWORK_MODE.  This field is optional if

+                                ResetMCastFilter is TRUE.

+  @param [in] pMCastFilter      A pointer to a list of new multicast receive filter HW MAC

+                                addresses.  This list will replace any existing multicast

+                                HW MAC address list.  This field is optional if ResetMCastFilter

+                                is TRUE.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_ReceiveFilters (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINT32 Enable,

+  IN UINT32 Disable,

+/*

+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST               0x01

+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST             0x02

+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST             0x04

+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS           0x08

+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10

+*/

+  IN BOOLEAN bResetMCastFilter,

+  IN UINTN MCastFilterCnt,

+  IN EFI_MAC_ADDRESS * pMCastFilter

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status = EFI_SUCCESS;   

+  EFI_TPL TplPrevious; 

+  NIC_DEVICE * pNicDevice;

+

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+  pMode = pSimpleNetwork->Mode;

+

+  if (pSimpleNetwork == NULL) {

+    gBS->RestoreTPL(TplPrevious);

+    return EFI_INVALID_PARAMETER;

+  }

+

+  switch (pMode->State) {

+    case EfiSimpleNetworkInitialized:

+      break;

+    case EfiSimpleNetworkStopped:

+      Status = EFI_NOT_STARTED;

+      gBS->RestoreTPL(TplPrevious);

+      return Status;

+    default:

+      Status = EFI_DEVICE_ERROR;

+      gBS->RestoreTPL(TplPrevious);

+      return Status;

+  }

+

+  //

+  // check if we are asked to enable or disable something that the UNDI

+  // does not even support!

+  //

+  if (((Enable &~pMode->ReceiveFilterMask) != 0) ||

+    ((Disable &~pMode->ReceiveFilterMask) != 0)) {

+    Status = EFI_INVALID_PARAMETER;

+    gBS->RestoreTPL(TplPrevious);

+    return Status;

+  }

+  

+  if (bResetMCastFilter) {

+    Disable |= (EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & pMode->ReceiveFilterMask);

+      pMode->MCastFilterCount = 0;

+      if ( (0 == (pMode->ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) 

+            && Enable == 0 && Disable == 2) {

+            gBS->RestoreTPL(TplPrevious);

+            return EFI_SUCCESS;

+      }

+  } 

+  else {

+    if (MCastFilterCnt != 0) {

+      UINTN i; 

+      EFI_MAC_ADDRESS * pMulticastAddress;

+      pMulticastAddress =  pMCastFilter;

+      

+      if ((MCastFilterCnt > pMode->MaxMCastFilterCount) ||

+          (pMCastFilter == NULL)) {

+        Status = EFI_INVALID_PARAMETER;

+        gBS->RestoreTPL(TplPrevious);

+        return Status;

+      }

+      

+      for ( i = 0 ; i < MCastFilterCnt ; i++ ) {

+          UINT8  tmp;

+          tmp = pMulticastAddress->Addr[0];

+          if ( (tmp & 0x01) != 0x01 ) {

+            gBS->RestoreTPL(TplPrevious);

+            return EFI_INVALID_PARAMETER;

+          }

+          pMulticastAddress++;

+      }

+      

+      pMode->MCastFilterCount = (UINT32)MCastFilterCnt;

+      CopyMem (&pMode->MCastFilter[0],

+                     pMCastFilter,

+                     MCastFilterCnt * sizeof ( EFI_MAC_ADDRESS));

+    }

+  }

+  

+  if (Enable == 0 && Disable == 0 && !bResetMCastFilter && MCastFilterCnt == 0) {

+    Status = EFI_SUCCESS;

+    gBS->RestoreTPL(TplPrevious);

+    return Status;

+  }

+

+  if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {

+    Status = EFI_INVALID_PARAMETER;

+    gBS->RestoreTPL(TplPrevious);

+    return Status;

+  }

+  

+  pMode->ReceiveFilterSetting |= Enable;

+  pMode->ReceiveFilterSetting &= ~Disable;

+  Status = ReceiveFilterUpdate (pSimpleNetwork);

+  

+  if (EFI_DEVICE_ERROR == Status || EFI_INVALID_PARAMETER == Status)

+      Status = EFI_SUCCESS;

+

+  gBS->RestoreTPL(TplPrevious);

+  return Status;

+}

+

+/**

+  Reset the network adapter.

+

+  Resets a network adapter and reinitializes it with the parameters that

+  were provided in the previous call to Initialize ().  The transmit and

+  receive queues are cleared.  Receive filters, the station address, the

+  statistics, and the multicast-IP-to-HW MAC addresses are not reset by

+  this call.

+

+  This routine calls ::Ax88772Reset to perform the adapter specific

+  reset operation.  This routine also starts the link negotiation

+  by calling ::Ax88772NegotiateLinkStart.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bExtendedVerification  Indicates that the driver may perform a more

+                                exhaustive verification operation of the device

+                                during reset.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Reset (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bExtendedVerification

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  //  Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+		pMode = pSimpleNetwork->Mode;

+		if ( EfiSimpleNetworkInitialized == pMode->State ) {

+    	//

+    	//  Update the device state

+    	//

+    	pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+    	pNicDevice->bComplete = FALSE;

+    	pNicDevice->bLinkUp = FALSE; 

+    	pNicDevice->bHavePkt = FALSE;

+    	pMode = pSimpleNetwork->Mode;

+    	pMode->MediaPresent = FALSE;

+

+    	//

+   		//  Reset the device

+    	//

+    	Status = Ax88772Reset ( pNicDevice );

+    	if ( !EFI_ERROR ( Status )) {

+     	 	//

+     	 	//  Update the receive filters in the adapter

+     	 	//

+     	 	Status = ReceiveFilterUpdate ( pSimpleNetwork );

+

+     	 	//

+     		 //  Try to get a connection to the network

+     	 	//

+     	 	if ( !EFI_ERROR ( Status )) {

+        	//

+        	//  Start the autonegotiation

+       		//

+        	Status = Ax88772NegotiateLinkStart ( pNicDevice );

+     		}

+   	 	}

+   	}

+   	else {

+      if (EfiSimpleNetworkStarted == pMode->State) {

+        Status = EFI_DEVICE_ERROR;

+      }

+      else {

+        Status = EFI_NOT_STARTED;

+      }

+   	}  

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  gBS->RestoreTPL ( TplPrevious );

+  return Status;

+}

+

+/**

+  Initialize the simple network protocol.

+

+  This routine calls ::Ax88772MacAddressGet to obtain the

+  MAC address.

+

+  @param [in] pNicDevice       NIC_DEVICE_INSTANCE pointer

+

+  @retval EFI_SUCCESS     Setup was successful

+

+**/

+EFI_STATUS

+SN_Setup (

+  IN NIC_DEVICE * pNicDevice

+  )

+{

+  

+

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork;

+  EFI_STATUS Status;

+  RX_PKT * pCurr = NULL;

+  RX_PKT * pPrev = NULL;

+

+	pSimpleNetwork = &pNicDevice->SimpleNetwork;  

+  pSimpleNetwork->Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;

+  pSimpleNetwork->Start = (EFI_SIMPLE_NETWORK_START)SN_Start;

+  pSimpleNetwork->Stop = (EFI_SIMPLE_NETWORK_STOP)SN_Stop;

+  pSimpleNetwork->Initialize = (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize;

+  pSimpleNetwork->Reset = (EFI_SIMPLE_NETWORK_RESET)SN_Reset;

+  pSimpleNetwork->Shutdown = (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown;

+  pSimpleNetwork->ReceiveFilters = (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters;

+  pSimpleNetwork->StationAddress = (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress;

+  pSimpleNetwork->Statistics = (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics;

+  pSimpleNetwork->MCastIpToMac = (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC;

+  pSimpleNetwork->NvData = (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData;

+  pSimpleNetwork->GetStatus = (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus;

+  pSimpleNetwork->Transmit = (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit;

+  pSimpleNetwork->Receive = (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive;

+  pSimpleNetwork->WaitForPacket = NULL;

+  pMode = &pNicDevice->SimpleNetworkData;

+  pSimpleNetwork->Mode = pMode;

+  pMode->State = EfiSimpleNetworkStopped;

+  pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;

+  pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );

+  pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;

+  pMode->NvRamSize = 0;

+  pMode->NvRamAccessSize = 0;

+  pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST

+                           | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST

+                           | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST

+                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS

+                           | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;

+  pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST

+                              | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;

+  pMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;

+  pMode->MCastFilterCount = 0;

+  SetMem ( &pMode->BroadcastAddress,

+           PXE_HWADDR_LEN_ETHER,

+           0xff );

+  pMode->IfType = EfiNetworkInterfaceUndi;

+  pMode->MacAddressChangeable = TRUE;

+  pMode->MultipleTxSupported = FALSE;

+  pMode->MediaPresentSupported = TRUE;

+  pMode->MediaPresent = FALSE;

+  pNicDevice->LinkIdleCnt = 0;

+  //

+  //  Read the MAC address

+  //

+  pNicDevice->PhyId = PHY_ID_INTERNAL;

+  pNicDevice->b100Mbps = TRUE;

+  pNicDevice->bFullDuplex = TRUE;

+  

+  Status = Ax88772MacAddressGet (

+                pNicDevice,

+                &pMode->PermanentAddress.Addr[0]);

+

+  if ( !EFI_ERROR ( Status )) {

+    int i; 

+    //

+    //  Use the hardware address as the current address

+    //

+

+    CopyMem ( &pMode->CurrentAddress,

+              &pMode->PermanentAddress,

+              PXE_HWADDR_LEN_ETHER );

+              

+    CopyMem ( &pNicDevice->MAC,

+              &pMode->PermanentAddress,

+              PXE_HWADDR_LEN_ETHER );

+              

+    pNicDevice->PktCntInQueue = 0;

+    

+    for ( i = 0 ; i < MAX_QUEUE_SIZE ; i++) {

+        Status = gBS->AllocatePool ( EfiRuntimeServicesData, 

+                                      sizeof (RX_PKT),

+                                      (VOID **) &pCurr);

+        if ( EFI_ERROR(Status)) {

+            DEBUG (( EFI_D_ERROR, "Memory are not enough\n"));

+            return Status;

+        }                              

+        pCurr->f_Used = FALSE;

+        

+        if ( i ) {

+            pPrev->pNext = pCurr;

+        }

+        else {

+            pNicDevice->QueueHead = pCurr;

+        }

+        

+        if (MAX_QUEUE_SIZE - 1 == i) {

+            pCurr->pNext = pNicDevice->QueueHead;

+        }

+        

+        pPrev = pCurr;

+    }

+    

+    pNicDevice->pNextFill = pNicDevice->QueueHead;

+    pNicDevice->pFirstFill = pNicDevice->QueueHead;

+    

+    Status = gBS->AllocatePool (EfiRuntimeServicesData,

+                                MAX_BULKIN_SIZE,

+                                (VOID **) &pNicDevice->pBulkInBuff);

+                                

+    if (EFI_ERROR(Status)) {

+        DEBUG (( EFI_D_ERROR, "gBS->AllocatePool for pBulkInBuff error. Status = %r\n",

+              Status));

+        return Status;

+    }

+  }

+  else {

+    DEBUG (( EFI_D_ERROR, "Ax88772MacAddressGet error. Status = %r\n", Status));

+		return Status;

+  }

+  

+  Status = gBS->AllocatePool ( EfiRuntimeServicesData,

+                                   sizeof ( RX_TX_PACKET ),

+                                   (VOID **) &pNicDevice->pRxTest );

+

+  if (EFI_ERROR (Status)) {

+    DEBUG (( EFI_D_ERROR, "gBS->AllocatePool:pNicDevice->pRxTest error. Status = %r\n",

+              Status));

+	  return Status;

+  }

+                                   

+  Status = gBS->AllocatePool ( EfiRuntimeServicesData,

+                                   sizeof ( RX_TX_PACKET ),

+                                   (VOID **) &pNicDevice->pTxTest );

+

+  if (EFI_ERROR (Status)) {

+    DEBUG (( EFI_D_ERROR, "gBS->AllocatePool:pNicDevice->pTxTest error. Status = %r\n",

+              Status));

+	  gBS->FreePool (pNicDevice->pRxTest);

+  }

+

+  return Status;

+}

+

+

+/**

+  This routine starts the network interface.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_ALREADY_STARTED   The network interface was already started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Start (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  NIC_DEVICE * pNicDevice;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  int i = 0;

+  RX_PKT * pCurr = NULL;

+

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  // Verify the parameters

+  //

+  Status = EFI_INVALID_PARAMETER;

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkStopped == pMode->State ) {

+      //

+      // Initialize the mode structuref

+      // NVRAM access is not supported

+      //

+      ZeroMem ( pMode, sizeof ( *pMode ));

+  

+      pMode->State = EfiSimpleNetworkStarted;

+      pMode->HwAddressSize = PXE_HWADDR_LEN_ETHER;

+      pMode->MediaHeaderSize = sizeof ( ETHERNET_HEADER );

+      pMode->MaxPacketSize = MAX_ETHERNET_PKT_SIZE;

+      pMode->ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST

+                               | EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST

+                               | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST

+                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS

+                               | EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;

+      pMode->ReceiveFilterSetting = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;

+      pMode->MaxMCastFilterCount = MAX_MCAST_FILTER_CNT;

+      pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+      Status = Ax88772MacAddressGet ( pNicDevice, &pMode->PermanentAddress.Addr[0]);

+      CopyMem ( &pMode->CurrentAddress,

+                &pMode->PermanentAddress,

+                sizeof ( pMode->CurrentAddress ));

+      SetMem(&pMode->BroadcastAddress, PXE_HWADDR_LEN_ETHER, 0xff);

+      pMode->IfType = EfiNetworkInterfaceUndi;

+      pMode->MacAddressChangeable = TRUE;

+      pMode->MultipleTxSupported = FALSE;

+      pMode->MediaPresentSupported = TRUE;

+      pMode->MediaPresent = FALSE; 

+      pNicDevice->PktCntInQueue = 0;

+      pNicDevice->pNextFill = pNicDevice->QueueHead;

+      pNicDevice->pFirstFill = pNicDevice->QueueHead;

+      pCurr = pNicDevice->QueueHead;

+      

+      for ( i = 0 ; i < MAX_QUEUE_SIZE ; i++) { 

+        pCurr->f_Used = FALSE;

+        pCurr = pCurr->pNext;

+      }

+      

+    }

+    else {

+      Status = EFI_ALREADY_STARTED;

+    }

+  }

+  gBS->RestoreTPL ( TplPrevious );

+  return Status;

+}

+

+

+/**

+  Set the MAC address.

+  

+  This function modifies or resets the current station address of a

+  network interface.  If Reset is TRUE, then the current station address

+  is set ot the network interface's permanent address.  If Reset if FALSE

+  then the current station address is changed to the address specified by

+  pNew.

+

+  This routine calls ::Ax88772MacAddressSet to update the MAC address

+  in the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Flag used to reset the station address to the

+                                network interface's permanent address.

+  @param [in] pNew              New station address to be used for the network

+                                interface.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_StationAddress (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN EFI_MAC_ADDRESS * pNew

+  )

+{

+  NIC_DEVICE * pNicDevice;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork )

+    && ( NULL != pSimpleNetwork->Mode )

+    && (( bReset ) || ( ( !bReset) && ( NULL != pNew )))) {

+    //

+    // Verify that the adapter is already started

+    //

+    pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+      //

+      // Determine the adapter MAC address

+      //

+      if ( bReset ) {

+        //

+        // Use the permanent address

+        //

+        CopyMem ( &pMode->CurrentAddress,

+                  &pMode->PermanentAddress,

+                  sizeof ( pMode->CurrentAddress ));

+      }

+      else {

+        //

+        // Use the specified address

+        //

+        CopyMem ( &pMode->CurrentAddress,

+                  pNew,

+                  sizeof ( pMode->CurrentAddress ));

+      }

+

+      //

+      // Update the address on the adapter

+      //

+      Status = Ax88772MacAddressSet ( pNicDevice, &pMode->CurrentAddress.Addr[0]);

+    }

+    else {

+      if (EfiSimpleNetworkStarted == pMode->State) {

+        Status = EFI_DEVICE_ERROR;

+      }

+      else {

+        Status = EFI_NOT_STARTED;

+      }

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  gBS->RestoreTPL ( TplPrevious );

+  return Status;

+}

+

+

+/**

+  This function resets or collects the statistics on a network interface.

+  If the size of the statistics table specified by StatisticsSize is not

+  big enough for all of the statistics that are collected by the network

+  interface, then a partial buffer of statistics is returned in

+  StatisticsTable.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] bReset            Set to TRUE to reset the statistics for the network interface.

+  @param [in, out] pStatisticsSize  On input the size, in bytes, of StatisticsTable.  On output

+                                the size, in bytes, of the resulting table of statistics.

+  @param [out] pStatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that

+                                conains the statistics.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_BUFFER_TOO_SMALL  The pStatisticsTable is NULL or the buffer is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+  typedef struct {

+  UINT64 RxTotalFrames;

+  UINT64 RxGoodFrames;

+  UINT64 RxUndersizeFrames;

+  UINT64 RxOversizeFrames;

+  UINT64 RxDroppedFrames;

+  UINT64 RxUnicastFrames;

+  UINT64 RxBroadcastFrames;

+  UINT64 RxMulticastFrames;

+  UINT64 RxCrcErrorFrames;

+  UINT64 RxTotalBytes;

+  UINT64 TxTotalFrames;

+  UINT64 TxGoodFrames;

+  UINT64 TxUndersizeFrames;

+  UINT64 TxOversizeFrames;

+  UINT64 TxDroppedFrames;

+  UINT64 TxUnicastFrames;

+  UINT64 TxBroadcastFrames;

+  UINT64 TxMulticastFrames;

+  UINT64 TxCrcErrorFrames;

+  UINT64 TxTotalBytes;

+  UINT64 Collisions;

+  UINT64 UnsupportedProtocol;

+  } EFI_NETWORK_STATISTICS;

+**/

+EFI_STATUS

+EFIAPI

+SN_Statistics (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN BOOLEAN bReset,

+  IN OUT UINTN * pStatisticsSize,

+  OUT EFI_NETWORK_STATISTICS * pStatisticsTable

+  )

+{

+  EFI_STATUS Status;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  //

+  // Verify the prarameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    pMode = pSimpleNetwork->Mode;

+    //

+    // Determine if the interface is started 

+    //

+    if (EfiSimpleNetworkInitialized == pMode->State){

+      //

+      // Determine if the StatisticsSize is big enough

+      //

+      if (sizeof (EFI_NETWORK_STATISTICS) <= *pStatisticsSize){

+        if (bReset) {

+          Status = EFI_SUCCESS;

+        } 

+        else {

+          Status = EFI_UNSUPPORTED;

+        }

+      }

+      else {

+        Status = EFI_BUFFER_TOO_SMALL;

+      }

+    }

+    else{

+      if (EfiSimpleNetworkStarted == pMode->State) {

+        Status = EFI_DEVICE_ERROR;

+      }

+      else {

+        Status = EFI_NOT_STARTED;

+      }

+    }

+  }

+  else {

+  	Status = EFI_INVALID_PARAMETER;

+  }

+

+  return Status;

+}

+

+

+/**

+  This function stops a network interface.  This call is only valid

+  if the network interface is in the started state.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Stop (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Determine if the interface is started

+    //

+    pMode = pSimpleNetwork->Mode;   

+    if ( EfiSimpleNetworkStarted == pMode->State ) {

+        pMode->State = EfiSimpleNetworkStopped;

+        Status = EFI_SUCCESS; 

+    }

+    else {

+        Status = EFI_NOT_STARTED;

+    }

+  } 

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  

+  gBS->RestoreTPL ( TplPrevious );

+  return Status;

+}

+

+

+/**

+  This function releases the memory buffers assigned in the Initialize() call.

+  Pending transmits and receives are lost, and interrupts are cleared and disabled.

+  After this call, only Initialize() and Stop() calls may be used.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+  @retval EFI_UNSUPPORTED       The increased buffer size feature is not supported.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Shutdown (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork

+  )

+{

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  UINT32 RxFilter;

+  EFI_STATUS Status;

+  EFI_TPL TplPrevious;

+  

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+  //

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && ( NULL != pSimpleNetwork->Mode )) {

+    //

+    // Determine if the interface is already started

+    //

+    pMode = pSimpleNetwork->Mode;

+    if ( EfiSimpleNetworkInitialized == pMode->State ) {

+      //

+      // Stop the adapter

+      //

+      RxFilter = pMode->ReceiveFilterSetting;

+      pMode->ReceiveFilterSetting = 0;

+      Status = SN_Reset ( pSimpleNetwork, FALSE );

+      pMode->ReceiveFilterSetting = RxFilter;

+      if ( !EFI_ERROR ( Status )) {

+

+        //

+        // Update the network state

+        //

+        pMode->State = EfiSimpleNetworkStarted;

+      }

+      else if ( EFI_DEVICE_ERROR == Status ) {

+      	pMode->State = EfiSimpleNetworkStopped;

+      }

+    }

+    else {

+      Status = EFI_NOT_STARTED;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  gBS->RestoreTPL ( TplPrevious );

+  return Status;

+}

+

+

+/**

+  Send a packet over the network.

+

+  This function places the packet specified by Header and Buffer on

+  the transmit queue.  This function performs a non-blocking transmit

+  operation.  When the transmit is complete, the buffer is returned

+  via the GetStatus() call.

+

+  This routine calls ::Ax88772Rx to empty the network adapter of

+  receive packets.  The routine then passes the transmit packet

+  to the network adapter.

+

+  @param [in] pSimpleNetwork    Protocol instance pointer

+  @param [in] HeaderSize        The size, in bytes, of the media header to be filled in by

+                                the Transmit() function.  If HeaderSize is non-zero, then

+                                it must be equal to SimpleNetwork->Mode->MediaHeaderSize

+                                and DestAddr and Protocol parameters must not be NULL.

+  @param [in] BufferSize        The size, in bytes, of the entire packet (media header and

+                                data) to be transmitted through the network interface.

+  @param [in] pBuffer           A pointer to the packet (media header followed by data) to

+                                to be transmitted.  This parameter can not be NULL.  If

+                                HeaderSize is zero, then the media header is Buffer must

+                                already be filled in by the caller.  If HeaderSize is nonzero,

+                                then the media header will be filled in by the Transmit()

+                                function.

+  @param [in] pSrcAddr          The source HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.  If HeaderSize is nonzero and

+                                SrcAddr is NULL, then SimpleNetwork->Mode->CurrentAddress

+                                is used for the source HW MAC address.

+  @param [in] pDestAddr         The destination HW MAC address.  If HeaderSize is zero, then

+                                this parameter is ignored.

+  @param [in] pProtocol         The type of header to build.  If HeaderSize is zero, then

+                                this parameter is ignored.

+

+  @retval EFI_SUCCESS           This operation was successful.

+  @retval EFI_NOT_STARTED       The network interface was not started.

+  @retval EFI_NOT_READY         The network interface is too busy to accept this transmit request.

+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize parameter is too small.

+  @retval EFI_INVALID_PARAMETER pSimpleNetwork parameter was NULL or did not point to a valid

+                                EFI_SIMPLE_NETWORK_PROTOCOL structure.

+  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

+

+**/

+EFI_STATUS

+EFIAPI

+SN_Transmit (

+  IN EFI_SIMPLE_NETWORK_PROTOCOL * pSimpleNetwork,

+  IN UINTN HeaderSize,

+  IN UINTN BufferSize,

+  IN VOID * pBuffer,

+  IN EFI_MAC_ADDRESS * pSrcAddr,

+  IN EFI_MAC_ADDRESS * pDestAddr,

+  IN UINT16 * pProtocol

+  )

+{

+  ETHERNET_HEADER * pHeader;

+  EFI_SIMPLE_NETWORK_MODE * pMode;

+  NIC_DEVICE * pNicDevice;

+  EFI_USB_IO_PROTOCOL * pUsbIo;

+  EFI_STATUS Status;

+  UINTN TransferLength;

+  UINT32 TransferStatus;

+  UINT16 Type;

+  EFI_TPL TplPrevious;

+

+  TplPrevious = gBS->RaiseTPL(TPL_CALLBACK);

+

+  // Verify the parameters

+  //

+  if (( NULL != pSimpleNetwork ) && 

+      ( NULL != pSimpleNetwork->Mode ) && 

+      ( NULL != pBuffer) && 

+      ( (HeaderSize == 0) || ( (NULL != pDestAddr) && (NULL != pProtocol) ))) {

+    //

+    // The interface must be running

+    //

+    pMode = pSimpleNetwork->Mode;

+    //

+    // Verify parameter of HeaderSize

+    //

+    if ((HeaderSize == 0) || (HeaderSize == pMode->MediaHeaderSize)){

+      //

+      // Determine if BufferSize is big enough

+      //

+      if (BufferSize >= pMode->MediaHeaderSize){

+        if ( EfiSimpleNetworkInitialized == pMode->State ) {

+          //

+          // Update the link status

+          //

+          pNicDevice = DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork );

+          pMode->MediaPresent = pNicDevice->bLinkUp;

+

+          //

+          //  Release the synchronization with Ax88772Timer

+          //      

+          if ( pMode->MediaPresent && pNicDevice->bComplete) {

+            //

+            //  Copy the packet into the USB buffer

+            //

+

+            CopyMem ( &pNicDevice->pTxTest->Data[0], pBuffer, BufferSize ); 

+            pNicDevice->pTxTest->Length = (UINT16) BufferSize;

+

+            //

+            //  Transmit the packet

+            //

+            pHeader = (ETHERNET_HEADER *) &pNicDevice->pTxTest->Data[0];

+            if ( 0 != HeaderSize ) {

+              if ( NULL != pDestAddr ) {

+                CopyMem ( &pHeader->dest_addr, pDestAddr, PXE_HWADDR_LEN_ETHER );

+              }

+              if ( NULL != pSrcAddr ) {

+                CopyMem ( &pHeader->src_addr, pSrcAddr, PXE_HWADDR_LEN_ETHER );

+              }

+              else {

+                CopyMem ( &pHeader->src_addr, &pMode->CurrentAddress.Addr[0], PXE_HWADDR_LEN_ETHER );

+              }

+              if ( NULL != pProtocol ) {

+                Type = *pProtocol;

+              }

+              else {

+                Type = pNicDevice->pTxTest->Length;

+              }

+              Type = (UINT16)(( Type >> 8 ) | ( Type << 8 ));

+              pHeader->type = Type;

+            }

+            if ( pNicDevice->pTxTest->Length < MIN_ETHERNET_PKT_SIZE ) {

+              pNicDevice->pTxTest->Length = MIN_ETHERNET_PKT_SIZE;

+              ZeroMem ( &pNicDevice->pTxTest->Data[ BufferSize ],

+                        pNicDevice->pTxTest->Length - BufferSize );

+            }

+        

+            DEBUG ((EFI_D_INFO, "TX: %02x-%02x-%02x-%02x-%02x-%02x  %02x-%02x-%02x-%02x-%02x-%02x"

+                      "  %02x-%02x  %d bytes\r\n",

+                      pNicDevice->pTxTest->Data[0],

+                      pNicDevice->pTxTest->Data[1],

+                      pNicDevice->pTxTest->Data[2],

+                      pNicDevice->pTxTest->Data[3],

+                      pNicDevice->pTxTest->Data[4],

+                      pNicDevice->pTxTest->Data[5],

+                      pNicDevice->pTxTest->Data[6],

+                      pNicDevice->pTxTest->Data[7],

+                      pNicDevice->pTxTest->Data[8],

+                      pNicDevice->pTxTest->Data[9],

+                      pNicDevice->pTxTest->Data[10],

+                      pNicDevice->pTxTest->Data[11],

+                      pNicDevice->pTxTest->Data[12],

+                      pNicDevice->pTxTest->Data[13],

+                      pNicDevice->pTxTest->Length ));

+

+            pNicDevice->pTxTest->LengthBar = ~(pNicDevice->pTxTest->Length);

+            TransferLength = sizeof ( pNicDevice->pTxTest->Length )

+                           + sizeof ( pNicDevice->pTxTest->LengthBar )

+                           + pNicDevice->pTxTest->Length;

+                           

+            if (TransferLength % 512 == 0 || TransferLength % 1024 == 0)

+                TransferLength +=4;

+

+            //

+            //  Work around USB bus driver bug where a timeout set by receive

+            //  succeeds but the timeout expires immediately after, causing the

+            //  transmit operation to timeout.

+            //

+            pUsbIo = pNicDevice->pUsbIo;

+            Status = pUsbIo->UsbBulkTransfer ( pUsbIo,

+                                               BULK_OUT_ENDPOINT,

+                                               &pNicDevice->pTxTest->Length,

+                                               &TransferLength,

+                                               0xfffffffe, 

+                                               &TransferStatus );

+            if ( !EFI_ERROR ( Status )) {

+              Status = TransferStatus;

+            }

+

+            if ( !EFI_ERROR ( Status )) {

+              pNicDevice->pTxBuffer = pBuffer;

+            }

+            else {

+              if ((TransferLength != (UINTN)( pNicDevice->pTxTest->Length + 4 )) &&

+                   (TransferLength != (UINTN)(( pNicDevice->pTxTest->Length + 4 ) + 4))) {

+                DEBUG ((EFI_D_INFO, "TransferLength didn't match Packet Length\n"));

+              }

+              //

+              //  Reset the controller to fix the error

+              //

+              if ( EFI_DEVICE_ERROR == Status ) {

+                SN_Reset ( pSimpleNetwork, FALSE );

+              }

+              Status = EFI_NOT_READY;

+            }

+          }

+          else {

+            //

+            // No packets available.

+            //

+            Status = EFI_NOT_READY;

+          }

+          

+        }

+        else {

+          if (EfiSimpleNetworkStarted == pMode->State) {

+            Status = EFI_DEVICE_ERROR;

+          }

+          else {

+            Status = EFI_NOT_STARTED ;

+          }

+        }

+      }

+      else {

+        Status = EFI_BUFFER_TOO_SMALL;

+      }

+    }

+    else {

+      Status = EFI_INVALID_PARAMETER;

+    }

+  }

+  else {

+    Status = EFI_INVALID_PARAMETER;

+  }

+  

+  gBS->RestoreTPL (TplPrevious);

+

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c
new file mode 100644
index 0000000..8b6dfac
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c
@@ -0,0 +1,923 @@
+/** @file

+  Cirrus Logic 5430 Controller Driver.

+  This driver is a sample implementation of the UGA Draw and Graphics Output

+  Protocols for the Cirrus Logic 5430 family of PCI video controllers.

+  This driver is only usable in the EFI pre-boot environment.

+  This sample is intended to show how the UGA Draw and Graphics output Protocol

+  is able to function.

+  The UGA I/O Protocol is not implemented in this sample.

+  A fully compliant EFI UGA driver requires both

+  the UGA Draw and the UGA I/O Protocol.  Please refer to Microsoft's

+  documentation on UGA for details on how to write a UGA driver that is able

+  to function both in the EFI pre-boot environment and from the OS runtime.

+

+  Copyright (c) 2006 - 2010, 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.

+

+**/

+

+//

+// Cirrus Logic 5430 Controller Driver

+//

+#include "CirrusLogic5430.h"

+

+EFI_DRIVER_BINDING_PROTOCOL gCirrusLogic5430DriverBinding = {

+  CirrusLogic5430ControllerDriverSupported,

+  CirrusLogic5430ControllerDriverStart,

+  CirrusLogic5430ControllerDriverStop,

+  0x10,

+  NULL,

+  NULL

+};

+

+///

+/// Generic Attribute Controller Register Settings

+///

+UINT8  AttributeController[21] = {

+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,

+  0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,

+  0x41, 0x00, 0x0F, 0x00, 0x00

+};

+

+///

+/// Generic Graphics Controller Register Settings

+///

+UINT8 GraphicsController[9] = {

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF

+};

+

+//

+// 640 x 480 x 256 color @ 60 Hertz

+//

+UINT8 Crtc_640_480_256_60[28] = {

+  0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,

+  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3,

+  0xff, 0x00, 0x00, 0x22

+};

+

+UINT16 Seq_640_480_256_60[15] = {

+  0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,

+  0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e

+};

+

+//

+// 800 x 600 x 256 color @ 60 Hertz

+//

+UINT8 Crtc_800_600_256_60[28] = {

+  0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,

+  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3,

+  0xFF, 0x00, 0x00, 0x22

+};

+

+UINT16 Seq_800_600_256_60[15] = {

+  0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,

+  0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e

+};

+

+//

+// 1024 x 768 x 256 color @ 60 Hertz

+//

+UINT8 Crtc_1024_768_256_60[28] = {

+  0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,

+  0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

+  0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,

+  0xFF, 0x4A, 0x00, 0x22

+};

+

+UINT16 Seq_1024_768_256_60[15] = {

+  0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,

+  0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e

+};

+

+///

+/// Table of supported video modes

+///

+CIRRUS_LOGIC_5430_VIDEO_MODES  CirrusLogic5430VideoModes[] = {

+  {  640, 480, 8, 60, Crtc_640_480_256_60,  Seq_640_480_256_60,  0xe3 },

+  {  800, 600, 8, 60, Crtc_800_600_256_60,  Seq_800_600_256_60,  0xef },

+  { 1024, 768, 8, 60, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef }

+};

+

+

+/**

+  CirrusLogic5430ControllerDriverSupported

+

+  TODO:    This - add argument and description to function comment

+  TODO:    Controller - add argument and description to function comment

+  TODO:    RemainingDevicePath - add argument and description to function comment

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ControllerDriverSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

+  )

+{

+  EFI_STATUS          Status;

+  EFI_PCI_IO_PROTOCOL *PciIo;

+  PCI_TYPE00          Pci;

+  EFI_DEV_PATH        *Node;

+

+  //

+  // Open the PCI I/O Protocol

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Read the PCI Configuration Header from the PCI Device

+  //

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint32,

+                        0,

+                        sizeof (Pci) / sizeof (UINT32),

+                        &Pci

+                        );

+  if (EFI_ERROR (Status)) {

+    goto Done;

+  }

+

+  Status = EFI_UNSUPPORTED;

+  //

+  // See if the I/O enable is on.  Most systems only allow one VGA device to be turned on

+  // at a time, so see if this is one that is turned on.

+  //

+  //  if (((Pci.Hdr.Command & 0x01) == 0x01)) {

+  //

+  // See if this is a Cirrus Logic PCI controller

+  //

+  if (Pci.Hdr.VendorId == CIRRUS_LOGIC_VENDOR_ID) {

+    //

+    // See if this is a 5430 or a 5446 PCI controller

+    //

+    if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_DEVICE_ID || 

+        Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID ||

+        Pci.Hdr.DeviceId == CIRRUS_LOGIC_5446_DEVICE_ID) {

+        

+      Status = EFI_SUCCESS;

+      //

+      // If this is an Intel 945 graphics controller,

+      // go further check RemainingDevicePath validation

+      //

+      if (RemainingDevicePath != NULL) {

+        Node = (EFI_DEV_PATH *) RemainingDevicePath;

+        //

+        // Check if RemainingDevicePath is the End of Device Path Node, 

+        // if yes, return EFI_SUCCESS

+        //

+        if (!IsDevicePathEnd (Node)) {

+          //

+          // If RemainingDevicePath isn't the End of Device Path Node,

+          // check its validation

+          //

+          if (Node->DevPath.Type != ACPI_DEVICE_PATH ||

+              Node->DevPath.SubType != ACPI_ADR_DP ||

+              DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {

+            Status = EFI_UNSUPPORTED;

+          }

+        }

+      }

+    }

+  }

+

+Done:

+  //

+  // Close the PCI I/O Protocol

+  //

+  gBS->CloseProtocol (

+        Controller,

+        &gEfiPciIoProtocolGuid,

+        This->DriverBindingHandle,

+        Controller

+        );

+

+  return Status;

+}

+

+/**

+  CirrusLogic5430ControllerDriverStart

+

+  TODO:    This - add argument and description to function comment

+  TODO:    Controller - add argument and description to function comment

+  TODO:    RemainingDevicePath - add argument and description to function comment

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ControllerDriverStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

+  )

+{

+  EFI_STATUS                      Status;

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+  BOOLEAN                         PciAttributesSaved;

+  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;

+  ACPI_ADR_DEVICE_PATH            AcpiDeviceNode;

+  UINT64                          Supports;

+

+  PciAttributesSaved = FALSE;

+  //

+  // Allocate Private context data for UGA Draw inteface.

+  //

+  Private = AllocateZeroPool (sizeof (CIRRUS_LOGIC_5430_PRIVATE_DATA));

+  if (Private == NULL) {

+    Status = EFI_OUT_OF_RESOURCES;

+    goto Error;

+  }

+

+  //

+  // Set up context record

+  //

+  Private->Signature  = CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE;

+  Private->Handle     = NULL;

+

+  //

+  // Open PCI I/O Protocol

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &Private->PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    goto Error;

+  }

+

+  //

+  // Get supported PCI attributes

+  //

+  Status = Private->PciIo->Attributes (

+                             Private->PciIo,

+                             EfiPciIoAttributeOperationSupported,

+                             0,

+                             &Supports

+                             );

+  if (EFI_ERROR (Status)) {

+    goto Error;

+  }

+

+  Supports &= (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);

+  if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {

+    Status = EFI_UNSUPPORTED;

+    goto Error;

+  }  

+

+  //

+  // Save original PCI attributes

+  //

+  Status = Private->PciIo->Attributes (

+                    Private->PciIo,

+                    EfiPciIoAttributeOperationGet,

+                    0,

+                    &Private->OriginalPciAttributes

+                    );

+

+  if (EFI_ERROR (Status)) {

+    goto Error;

+  }

+  PciAttributesSaved = TRUE;

+

+  Status = Private->PciIo->Attributes (

+                             Private->PciIo,

+                             EfiPciIoAttributeOperationEnable,

+                             EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,

+                             NULL

+                             );

+  if (EFI_ERROR (Status)) {

+    goto Error;

+  }

+

+  //

+  // Get ParentDevicePath

+  //

+  Status = gBS->HandleProtocol (

+                  Controller,

+                  &gEfiDevicePathProtocolGuid,

+                  (VOID **) &ParentDevicePath

+                  );

+  if (EFI_ERROR (Status)) {

+    goto Error;

+  }

+

+  if (FeaturePcdGet (PcdSupportGop)) {

+    //

+    // Set Gop Device Path

+    //

+    if (RemainingDevicePath == NULL) {

+      ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));

+      AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;

+      AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;

+      AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);

+      SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));

+

+      Private->GopDevicePath = AppendDevicePathNode (

+                                          ParentDevicePath,

+                                          (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode

+                                          );

+    } else if (!IsDevicePathEnd (RemainingDevicePath)) {

+      //

+      // If RemainingDevicePath isn't the End of Device Path Node, 

+      // only scan the specified device by RemainingDevicePath

+      //

+      Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);

+    } else {

+      //

+      // If RemainingDevicePath is the End of Device Path Node, 

+      // don't create child device and return EFI_SUCCESS

+      //

+      Private->GopDevicePath = NULL;

+    }

+      

+    if (Private->GopDevicePath != NULL) {

+      //

+      // Creat child handle and device path protocol firstly

+      //

+      Private->Handle = NULL;

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      &Private->Handle,

+                      &gEfiDevicePathProtocolGuid,

+                      Private->GopDevicePath,

+                      NULL

+                      );

+    }

+  }

+

+  //

+  // Construct video mode buffer

+  //

+  Status = CirrusLogic5430VideoModeSetup (Private);

+  if (EFI_ERROR (Status)) {

+    goto Error;

+  }

+

+  if (FeaturePcdGet (PcdSupportUga)) {

+    //

+    // Start the UGA Draw software stack.

+    //

+    Status = CirrusLogic5430UgaDrawConstructor (Private);

+    ASSERT_EFI_ERROR (Status);

+

+    Private->UgaDevicePath = ParentDevicePath;

+    Status = gBS->InstallMultipleProtocolInterfaces (

+                    &Controller,

+                    &gEfiUgaDrawProtocolGuid,

+                    &Private->UgaDraw,

+                    &gEfiDevicePathProtocolGuid,

+                    Private->UgaDevicePath,

+                    NULL

+                    );

+

+  } else if (FeaturePcdGet (PcdSupportGop)) {

+    if (Private->GopDevicePath == NULL) {

+      //

+      // If RemainingDevicePath is the End of Device Path Node, 

+      // don't create child device and return EFI_SUCCESS

+      //

+      Status = EFI_SUCCESS;

+    } else {

+  

+      //

+      // Start the GOP software stack.

+      //

+      Status = CirrusLogic5430GraphicsOutputConstructor (Private);

+      ASSERT_EFI_ERROR (Status);

+  

+      Status = gBS->InstallMultipleProtocolInterfaces (

+                      &Private->Handle,

+                      &gEfiGraphicsOutputProtocolGuid,

+                      &Private->GraphicsOutput,

+                      &gEfiEdidDiscoveredProtocolGuid,

+                      &Private->EdidDiscovered,

+                      &gEfiEdidActiveProtocolGuid,

+                      &Private->EdidActive,

+                      NULL

+                      );

+    }

+  } else {

+    //

+    // This driver must support eithor GOP or UGA or both.

+    //

+    ASSERT (FALSE);

+    Status = EFI_UNSUPPORTED;

+  }

+

+

+Error:

+  if (EFI_ERROR (Status)) {

+    if (Private) {

+      if (Private->PciIo) {

+        if (PciAttributesSaved == TRUE) {

+          //

+          // Restore original PCI attributes

+          //

+          Private->PciIo->Attributes (

+                          Private->PciIo,

+                          EfiPciIoAttributeOperationSet,

+                          Private->OriginalPciAttributes,

+                          NULL

+                          );

+        }

+        //

+        // Close the PCI I/O Protocol

+        //

+        gBS->CloseProtocol (

+              Private->Handle,

+              &gEfiPciIoProtocolGuid,

+              This->DriverBindingHandle,

+              Private->Handle

+              );

+      }

+

+      gBS->FreePool (Private);

+    }

+  }

+

+  return Status;

+}

+

+/**

+  CirrusLogic5430ControllerDriverStop

+

+  TODO:    This - add argument and description to function comment

+  TODO:    Controller - add argument and description to function comment

+  TODO:    NumberOfChildren - add argument and description to function comment

+  TODO:    ChildHandleBuffer - add argument and description to function comment

+  TODO:    EFI_SUCCESS - add return value to function comment

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ControllerDriverStop (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN UINTN                          NumberOfChildren,

+  IN EFI_HANDLE                     *ChildHandleBuffer

+  )

+{

+  EFI_UGA_DRAW_PROTOCOL           *UgaDraw;

+  EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput;

+

+  EFI_STATUS                      Status;

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+

+  if (FeaturePcdGet (PcdSupportUga)) {

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiUgaDrawProtocolGuid,

+                    (VOID **) &UgaDraw,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+    //

+    // Get our private context information

+    //

+    Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (UgaDraw);

+    CirrusLogic5430UgaDrawDestructor (Private);

+

+    if (FeaturePcdGet (PcdSupportGop)) {

+      CirrusLogic5430GraphicsOutputDestructor (Private);

+      //

+      // Remove the UGA and GOP protocol interface from the system

+      //

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      Private->Handle,

+                      &gEfiUgaDrawProtocolGuid,

+                      &Private->UgaDraw,

+                      &gEfiGraphicsOutputProtocolGuid,

+                      &Private->GraphicsOutput,

+                      NULL

+                      );

+    } else {

+      //

+      // Remove the UGA Draw interface from the system

+      //

+      Status = gBS->UninstallMultipleProtocolInterfaces (

+                      Private->Handle,

+                      &gEfiUgaDrawProtocolGuid,

+                      &Private->UgaDraw,

+                      NULL

+                      );

+    }

+  } else {

+    Status = gBS->OpenProtocol (

+                    Controller,

+                    &gEfiGraphicsOutputProtocolGuid,

+                    (VOID **) &GraphicsOutput,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    //

+    // Get our private context information

+    //

+    Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);

+

+    CirrusLogic5430GraphicsOutputDestructor (Private);

+    //

+    // Remove the GOP protocol interface from the system

+    //

+    Status = gBS->UninstallMultipleProtocolInterfaces (

+                    Private->Handle,

+                    &gEfiUgaDrawProtocolGuid,

+                    &Private->UgaDraw,

+                    &gEfiGraphicsOutputProtocolGuid,

+                    &Private->GraphicsOutput,

+                    NULL

+                    );

+  }

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Restore original PCI attributes

+  //

+  Private->PciIo->Attributes (

+                  Private->PciIo,

+                  EfiPciIoAttributeOperationSet,

+                  Private->OriginalPciAttributes,

+                  NULL

+                  );

+

+  //

+  // Close the PCI I/O Protocol

+  //

+  gBS->CloseProtocol (

+        Controller,

+        &gEfiPciIoProtocolGuid,

+        This->DriverBindingHandle,

+        Controller

+        );

+

+  //

+  // Free our instance data

+  //

+  gBS->FreePool (Private);

+

+  return EFI_SUCCESS;

+}

+

+/**

+  CirrusLogic5430UgaDrawDestructor

+

+  TODO:    Private - add argument and description to function comment

+  TODO:    EFI_SUCCESS - add return value to function comment

+**/

+EFI_STATUS

+CirrusLogic5430UgaDrawDestructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+{

+  return EFI_SUCCESS;

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+  @param  Address TODO: add argument description

+  @param  Data TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+outb (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address,

+  UINT8                           Data

+  )

+{

+  Private->PciIo->Io.Write (

+                      Private->PciIo,

+                      EfiPciIoWidthUint8,

+                      EFI_PCI_IO_PASS_THROUGH_BAR,

+                      Address,

+                      1,

+                      &Data

+                      );

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+  @param  Address TODO: add argument description

+  @param  Data TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+outw (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address,

+  UINT16                          Data

+  )

+{

+  Private->PciIo->Io.Write (

+                      Private->PciIo,

+                      EfiPciIoWidthUint16,

+                      EFI_PCI_IO_PASS_THROUGH_BAR,

+                      Address,

+                      1,

+                      &Data

+                      );

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+  @param  Address TODO: add argument description

+

+  TODO: add return values

+

+**/

+UINT8

+inb (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address

+  )

+{

+  UINT8 Data;

+

+  Private->PciIo->Io.Read (

+                      Private->PciIo,

+                      EfiPciIoWidthUint8,

+                      EFI_PCI_IO_PASS_THROUGH_BAR,

+                      Address,

+                      1,

+                      &Data

+                      );

+  return Data;

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+  @param  Address TODO: add argument description

+

+  TODO: add return values

+

+**/

+UINT16

+inw (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address

+  )

+{

+  UINT16  Data;

+

+  Private->PciIo->Io.Read (

+                      Private->PciIo,

+                      EfiPciIoWidthUint16,

+                      EFI_PCI_IO_PASS_THROUGH_BAR,

+                      Address,

+                      1,

+                      &Data

+                      );

+  return Data;

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+  @param  Index TODO: add argument description

+  @param  Red TODO: add argument description

+  @param  Green TODO: add argument description

+  @param  Blue TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+SetPaletteColor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Index,

+  UINT8                           Red,

+  UINT8                           Green,

+  UINT8                           Blue

+  )

+{

+  outb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);

+  outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));

+  outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));

+  outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+SetDefaultPalette (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+{

+  UINTN Index;

+  UINTN RedIndex;

+  UINTN GreenIndex;

+  UINTN BlueIndex;

+

+  Index = 0;

+  for (RedIndex = 0; RedIndex < 8; RedIndex++) {

+    for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {

+      for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {

+        SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));

+        Index++;

+      }

+    }

+  }

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+ClearScreen (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+{

+  UINT32  Color;

+

+  Color = 0;

+  Private->PciIo->Mem.Write (

+                        Private->PciIo,

+                        EfiPciIoWidthFillUint32,

+                        0,

+                        0,

+                        0x100000 >> 2,

+                        &Color

+                        );

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+DrawLogo (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           ScreenWidth,

+  UINTN                           ScreenHeight

+  )

+{

+}

+

+/**

+  TODO: Add function description

+

+  @param  Private TODO: add argument description

+  @param  ModeData TODO: add argument description

+

+  TODO: add return values

+

+**/

+VOID

+InitializeGraphicsMode (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  CIRRUS_LOGIC_5430_VIDEO_MODES   *ModeData

+  )

+{

+  UINT8 Byte;

+  UINTN Index;

+  UINT16 DeviceId;

+  EFI_STATUS Status;

+

+  Status = Private->PciIo->Pci.Read (

+             Private->PciIo,

+             EfiPciIoWidthUint16,

+             PCI_DEVICE_ID_OFFSET,

+             1,

+             &DeviceId

+             );

+  //

+  // Read the PCI Configuration Header from the PCI Device

+  //

+  ASSERT_EFI_ERROR (Status);

+

+  outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);

+  outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);

+

+  for (Index = 0; Index < 15; Index++) {

+    outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);

+  }

+

+  if (DeviceId != CIRRUS_LOGIC_5446_DEVICE_ID) {

+    outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);

+    Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);

+    outb (Private, SEQ_DATA_REGISTER, Byte);

+  }

+

+  outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);

+  outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);

+  outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);

+  outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);

+

+  for (Index = 0; Index < 28; Index++) {

+    outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));

+  }

+

+  for (Index = 0; Index < 9; Index++) {

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));

+  }

+

+  inb (Private, INPUT_STATUS_1_REGISTER);

+

+  for (Index = 0; Index < 21; Index++) {

+    outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);

+    outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);

+  }

+

+  outb (Private, ATT_ADDRESS_REGISTER, 0x20);

+

+  outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);

+  outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);

+  outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);

+  outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);

+

+  SetDefaultPalette (Private);

+  ClearScreen (Private);

+}

+

+EFI_STATUS

+EFIAPI

+InitializeCirrusLogic5430 (

+  IN EFI_HANDLE           ImageHandle,

+  IN EFI_SYSTEM_TABLE     *SystemTable

+  )

+{

+  EFI_STATUS              Status;

+

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             SystemTable,

+             &gCirrusLogic5430DriverBinding,

+             ImageHandle,

+             &gCirrusLogic5430ComponentName,

+             &gCirrusLogic5430ComponentName2

+             );

+  ASSERT_EFI_ERROR (Status);

+

+  //

+  // Install EFI Driver Supported EFI Version Protocol required for

+  // EFI drivers that are on PCI and other plug in cards.

+  //

+  gCirrusLogic5430DriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                  &ImageHandle,

+                  &gEfiDriverSupportedEfiVersionProtocolGuid,

+                  &gCirrusLogic5430DriverSupportedEfiVersion,

+                  NULL

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h
new file mode 100644
index 0000000..5080de5
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h
@@ -0,0 +1,438 @@
+/** @file

+  Cirrus Logic 5430 Controller Driver

+

+  Copyright (c) 2006 - 2011, 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.

+

+**/

+

+//

+// Cirrus Logic 5430 Controller Driver

+//

+

+#ifndef _CIRRUS_LOGIC_5430_H_

+#define _CIRRUS_LOGIC_5430_H_

+

+

+#include <Uefi.h>

+#include <Protocol/UgaDraw.h>

+#include <Protocol/GraphicsOutput.h>

+#include <Protocol/PciIo.h>

+#include <Protocol/DriverSupportedEfiVersion.h>

+#include <Protocol/EdidOverride.h>

+#include <Protocol/EdidDiscovered.h>

+#include <Protocol/EdidActive.h>

+#include <Protocol/DevicePath.h>

+

+#include <Library/DebugLib.h>

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/UefiLib.h>

+#include <Library/PcdLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DevicePathLib.h>

+#include <Library/TimerLib.h>

+

+#include <IndustryStandard/Pci.h>

+//

+// Cirrus Logic 5430 PCI Configuration Header values

+//

+#define CIRRUS_LOGIC_VENDOR_ID                0x1013

+#define CIRRUS_LOGIC_5430_DEVICE_ID           0x00a8

+#define CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID 0x00a0

+#define CIRRUS_LOGIC_5446_DEVICE_ID           0x00b8

+

+//

+// Cirrus Logic Graphical Mode Data

+//

+#define CIRRUS_LOGIC_5430_MODE_COUNT         3

+

+typedef struct {

+  UINT32  ModeNumber;

+  UINT32  HorizontalResolution;

+  UINT32  VerticalResolution;

+  UINT32  ColorDepth;

+  UINT32  RefreshRate;

+} CIRRUS_LOGIC_5430_MODE_DATA;

+

+#define PIXEL_RED_SHIFT   0

+#define PIXEL_GREEN_SHIFT 3

+#define PIXEL_BLUE_SHIFT  6

+

+#define PIXEL_RED_MASK    (BIT7 | BIT6 | BIT5)

+#define PIXEL_GREEN_MASK  (BIT4 | BIT3 | BIT2)

+#define PIXEL_BLUE_MASK   (BIT1 | BIT0)

+

+#define PIXEL_TO_COLOR_BYTE(pixel, mask, shift) ((UINT8) ((pixel & mask) << shift))

+#define PIXEL_TO_RED_BYTE(pixel) PIXEL_TO_COLOR_BYTE(pixel, PIXEL_RED_MASK, PIXEL_RED_SHIFT)

+#define PIXEL_TO_GREEN_BYTE(pixel) PIXEL_TO_COLOR_BYTE(pixel, PIXEL_GREEN_MASK, PIXEL_GREEN_SHIFT)

+#define PIXEL_TO_BLUE_BYTE(pixel) PIXEL_TO_COLOR_BYTE(pixel, PIXEL_BLUE_MASK, PIXEL_BLUE_SHIFT)

+

+#define RGB_BYTES_TO_PIXEL(Red, Green, Blue) \

+  (UINT8) ( (((Red) >> PIXEL_RED_SHIFT) & PIXEL_RED_MASK) | \

+            (((Green) >> PIXEL_GREEN_SHIFT) & PIXEL_GREEN_MASK) | \

+            (((Blue) >> PIXEL_BLUE_SHIFT) & PIXEL_BLUE_MASK) )

+

+#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER  0xffff

+

+//

+// Cirrus Logic 5440 Private Data Structure

+//

+#define CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('C', 'L', '5', '4')

+

+typedef struct {

+  UINT64                                Signature;

+  EFI_HANDLE                            Handle;

+  EFI_PCI_IO_PROTOCOL                   *PciIo;

+  UINT64                                OriginalPciAttributes;

+  EFI_UGA_DRAW_PROTOCOL                 UgaDraw;

+  EFI_GRAPHICS_OUTPUT_PROTOCOL          GraphicsOutput;

+  EFI_EDID_DISCOVERED_PROTOCOL          EdidDiscovered;

+  EFI_EDID_ACTIVE_PROTOCOL              EdidActive;

+  EFI_DEVICE_PATH_PROTOCOL              *GopDevicePath;

+  EFI_DEVICE_PATH_PROTOCOL              *UgaDevicePath;

+  UINTN                                 CurrentMode;

+  UINTN                                 MaxMode;

+  CIRRUS_LOGIC_5430_MODE_DATA           ModeData[CIRRUS_LOGIC_5430_MODE_COUNT];

+  UINT8                                 *LineBuffer;

+  BOOLEAN                               HardwareNeedsStarting;

+} CIRRUS_LOGIC_5430_PRIVATE_DATA;

+

+///

+/// Video Mode structure

+///

+typedef struct {

+  UINT32  Width;

+  UINT32  Height;

+  UINT32  ColorDepth;

+  UINT32  RefreshRate;

+  UINT8   *CrtcSettings;

+  UINT16  *SeqSettings;

+  UINT8   MiscSetting;

+} CIRRUS_LOGIC_5430_VIDEO_MODES;

+

+#define CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS(a) \

+  CR(a, CIRRUS_LOGIC_5430_PRIVATE_DATA, UgaDraw, CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE)

+

+#define CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS(a) \

+  CR(a, CIRRUS_LOGIC_5430_PRIVATE_DATA, GraphicsOutput, CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE)

+

+

+//

+// Global Variables

+//

+extern UINT8                                      AttributeController[];

+extern UINT8                                      GraphicsController[];

+extern UINT8                                      Crtc_640_480_256_60[];

+extern UINT16                                     Seq_640_480_256_60[];

+extern UINT8                                      Crtc_800_600_256_60[];

+extern UINT16                                     Seq_800_600_256_60[];

+extern UINT8                                      Crtc_1024_768_256_60[];

+extern UINT16                                     Seq_1024_768_256_60[];

+extern CIRRUS_LOGIC_5430_VIDEO_MODES              CirrusLogic5430VideoModes[];

+extern EFI_DRIVER_BINDING_PROTOCOL                gCirrusLogic5430DriverBinding;

+extern EFI_COMPONENT_NAME_PROTOCOL                gCirrusLogic5430ComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL               gCirrusLogic5430ComponentName2;

+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL  gCirrusLogic5430DriverSupportedEfiVersion;

+

+//

+// Io Registers defined by VGA

+//

+#define CRTC_ADDRESS_REGISTER   0x3d4

+#define CRTC_DATA_REGISTER      0x3d5

+#define SEQ_ADDRESS_REGISTER    0x3c4

+#define SEQ_DATA_REGISTER       0x3c5

+#define GRAPH_ADDRESS_REGISTER  0x3ce

+#define GRAPH_DATA_REGISTER     0x3cf

+#define ATT_ADDRESS_REGISTER    0x3c0

+#define MISC_OUTPUT_REGISTER    0x3c2

+#define INPUT_STATUS_1_REGISTER 0x3da

+#define DAC_PIXEL_MASK_REGISTER 0x3c6

+#define PALETTE_INDEX_REGISTER  0x3c8

+#define PALETTE_DATA_REGISTER   0x3c9

+

+//

+// UGA Draw Hardware abstraction internal worker functions

+//

+EFI_STATUS

+CirrusLogic5430UgaDrawConstructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  );

+

+EFI_STATUS

+CirrusLogic5430UgaDrawDestructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  );

+

+//

+// Graphics Output Hardware abstraction internal worker functions

+//

+EFI_STATUS

+CirrusLogic5430GraphicsOutputConstructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  );

+

+EFI_STATUS

+CirrusLogic5430GraphicsOutputDestructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  );

+

+

+//

+// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface

+//

+/**

+  TODO: Add function description

+

+  @param  This TODO: add argument description

+  @param  Controller TODO: add argument description

+  @param  RemainingDevicePath TODO: add argument description

+

+  TODO: add return values

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ControllerDriverSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+/**

+  TODO: Add function description

+

+  @param  This TODO: add argument description

+  @param  Controller TODO: add argument description

+  @param  RemainingDevicePath TODO: add argument description

+

+  TODO: add return values

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ControllerDriverStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+/**

+  TODO: Add function description

+

+  @param  This TODO: add argument description

+  @param  Controller TODO: add argument description

+  @param  NumberOfChildren TODO: add argument description

+  @param  ChildHandleBuffer TODO: add argument description

+

+  TODO: add return values

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ControllerDriverStop (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN UINTN                        NumberOfChildren,

+  IN EFI_HANDLE                   *ChildHandleBuffer

+  );

+

+//

+// EFI Component Name Functions

+//

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  );

+

+

+//

+// Local Function Prototypes

+//

+VOID

+InitializeGraphicsMode (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  CIRRUS_LOGIC_5430_VIDEO_MODES   *ModeData

+  );

+

+VOID

+SetPaletteColor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Index,

+  UINT8                           Red,

+  UINT8                           Green,

+  UINT8                           Blue

+  );

+

+VOID

+SetDefaultPalette (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  );

+

+VOID

+DrawLogo (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           ScreenWidth,

+  UINTN                           ScreenHeight

+  );

+

+VOID

+outb (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address,

+  UINT8                           Data

+  );

+

+VOID

+outw (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address,

+  UINT16                          Data

+  );

+

+UINT8

+inb (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address

+  );

+

+UINT16

+inw (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private,

+  UINTN                           Address

+  );

+

+EFI_STATUS

+CirrusLogic5430VideoModeSetup (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  );

+

+#endif

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf
new file mode 100644
index 0000000..fd380d1
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf
@@ -0,0 +1,89 @@
+## @file

+# Component description file for CirrusLogic5430 module

+#

+# Cirrus Logic 5430 Controller Driver.This driver is a sample implementation

+#  of the UGA Draw Protocol for the Cirrus Logic 5430 family of PCI video controllers.

+#  This driver is only usable in the EFI pre-boot environment. This sample is

+#  intended to show how the UGA Draw Protocol is able to function. The UGA I/O

+#  Protocol is not implemented in this sample. A fully compliant EFI UGA driver

+#  requires both the UGA Draw and the UGA I/O Protocol. Please refer to Microsoft's

+#  documentation on UGA for details on how to write a UGA driver that is able

+#  to function both in the EFI pre-boot environment and from the OS runtime.

+# Copyright (c) 2006 - 2011, 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.

+#

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = CirrusLogic5430Dxe

+  FILE_GUID                      = 555F76EA-785F-40d7-9174-153C43636C68

+  MODULE_TYPE                    = UEFI_DRIVER

+  VERSION_STRING                 = 1.0

+

+  ENTRY_POINT                    = InitializeCirrusLogic5430

+

+  PCI_VENDOR_ID  = 0x1013

+  PCI_DEVICE_ID  = 0x00A8

+  PCI_CLASS_CODE = 0x030000

+  PCI_REVISION   = 0x00

+  PCI_COMPRESS   = TRUE

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+#  DRIVER_BINDING                =  gCirrusLogic5430DriverBinding

+#  COMPONENT_NAME                =  gCirrusLogic5430ComponentName

+#

+

+[Sources]

+  ComponentName.c

+  DriverSupportedEfiVersion.c

+  CirrusLogic5430UgaDraw.c

+  CirrusLogic5430GraphicsOutput.c

+  CirrusLogic5430.c

+  CirrusLogic5430.h

+  Edid.c

+  CirrusLogic5430I2c.h

+  CirrusLogic5430I2c.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OptionRomPkg/OptionRomPkg.dec

+

+[LibraryClasses]

+  UefiBootServicesTableLib

+  MemoryAllocationLib

+  UefiLib

+  UefiDriverEntryPoint

+  DebugLib

+  BaseMemoryLib

+  DevicePathLib

+  TimerLib

+

+[Protocols]

+  gEfiDriverSupportedEfiVersionProtocolGuid     # PROTOCOL ALWAYS_PRODUCED

+  gEfiUgaDrawProtocolGuid                       # PROTOCOL BY_START

+  gEfiGraphicsOutputProtocolGuid                # PROTOCOL BY_START

+  gEfiEdidDiscoveredProtocolGuid                # PROTOCOL BY_START

+  gEfiEdidActiveProtocolGuid                    # PROTOCOL BY_START

+  gEfiDevicePathProtocolGuid                    # PROTOCOL BY_START

+  gEfiPciIoProtocolGuid                         # PROTOCOL TO_START

+  gEfiEdidOverrideProtocolGuid                  # PROTOCOL TO_START

+

+

+[FeaturePcd]

+  gOptionRomPkgTokenSpaceGuid.PcdSupportGop

+  gOptionRomPkgTokenSpaceGuid.PcdSupportUga

+

+[Pcd]

+  gOptionRomPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutput.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutput.c
new file mode 100644
index 0000000..4550b25
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutput.c
@@ -0,0 +1,562 @@
+/** @file

+Copyright (c) 2007 - 2012, 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.

+

+Module Name:

+

+  UefiCirrusLogic5430GraphicsOutput.c

+

+Abstract:

+

+  This file produces the graphics abstration of Graphics Output Protocol. It is called by

+  CirrusLogic5430.c file which deals with the EFI 1.1 driver model.

+  This file just does graphics.

+

+**/

+#include "CirrusLogic5430.h"

+#include <IndustryStandard/Acpi.h>

+

+

+STATIC

+VOID

+CirrusLogic5430CompleteModeInfo (

+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info

+  )

+{

+  Info->Version = 0;

+  Info->PixelFormat = PixelBitMask;

+  Info->PixelInformation.RedMask = PIXEL_RED_MASK;

+  Info->PixelInformation.GreenMask = PIXEL_GREEN_MASK;

+  Info->PixelInformation.BlueMask = PIXEL_BLUE_MASK;

+  Info->PixelInformation.ReservedMask = 0;

+  Info->PixelsPerScanLine = Info->HorizontalResolution;

+}

+

+

+STATIC

+EFI_STATUS

+CirrusLogic5430CompleteModeData (

+  IN  CIRRUS_LOGIC_5430_PRIVATE_DATA    *Private,

+  OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode

+  )

+{

+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;

+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR     *FrameBufDesc;

+

+  Info = Mode->Info;

+  CirrusLogic5430CompleteModeInfo (Info);

+

+  Private->PciIo->GetBarAttributes (

+                        Private->PciIo,

+                        0,

+                        NULL,

+                        (VOID**) &FrameBufDesc

+                        );

+

+  Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;

+  Mode->FrameBufferSize = Info->HorizontalResolution * Info->VerticalResolution;

+

+  return EFI_SUCCESS;

+}

+

+

+//

+// Graphics Output Protocol Member Functions

+//

+EFI_STATUS

+EFIAPI

+CirrusLogic5430GraphicsOutputQueryMode (

+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,

+  IN  UINT32                                ModeNumber,

+  OUT UINTN                                 *SizeOfInfo,

+  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info

+  )

+/*++

+

+Routine Description:

+

+  Graphics Output protocol interface to query video mode

+

+  Arguments:

+    This                  - Protocol instance pointer.

+    ModeNumber            - The mode number to return information on.

+    Info                  - Caller allocated buffer that returns information about ModeNumber.

+    SizeOfInfo            - A pointer to the size, in bytes, of the Info buffer.

+

+  Returns:

+    EFI_SUCCESS           - Mode information returned.

+    EFI_BUFFER_TOO_SMALL  - The Info buffer was too small.

+    EFI_DEVICE_ERROR      - A hardware error occurred trying to retrieve the video mode.

+    EFI_NOT_STARTED       - Video display is not initialized. Call SetMode ()

+    EFI_INVALID_PARAMETER - One of the input args was NULL.

+

+--*/

+{

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+

+  Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);

+

+  if (Private->HardwareNeedsStarting) {

+    return EFI_NOT_STARTED;

+  }

+

+  if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));

+  if (*Info == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);

+

+  (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;

+  (*Info)->VerticalResolution   = Private->ModeData[ModeNumber].VerticalResolution;

+  CirrusLogic5430CompleteModeInfo (*Info);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+CirrusLogic5430GraphicsOutputSetMode (

+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *This,

+  IN  UINT32                       ModeNumber

+  )

+/*++

+

+Routine Description:

+

+  Graphics Output protocol interface to set video mode

+

+  Arguments:

+    This             - Protocol instance pointer.

+    ModeNumber       - The mode number to be set.

+

+  Returns:

+    EFI_SUCCESS      - Graphics mode was changed.

+    EFI_DEVICE_ERROR - The device had an error and could not complete the request.

+    EFI_UNSUPPORTED  - ModeNumber is not supported by this device.

+

+--*/

+{

+  CIRRUS_LOGIC_5430_PRIVATE_DATA    *Private;

+  CIRRUS_LOGIC_5430_MODE_DATA       *ModeData;

+

+  Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);

+

+  if (ModeNumber >= This->Mode->MaxMode) {

+    return EFI_UNSUPPORTED;

+  }

+

+  ModeData = &Private->ModeData[ModeNumber];

+

+  if (Private->LineBuffer) {

+    gBS->FreePool (Private->LineBuffer);

+  }

+

+  Private->LineBuffer = NULL;

+  Private->LineBuffer = AllocatePool (ModeData->HorizontalResolution);

+  if (Private->LineBuffer == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[ModeData->ModeNumber]);

+

+  This->Mode->Mode = ModeNumber;

+  This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;

+  This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;

+  This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);

+

+  CirrusLogic5430CompleteModeData (Private, This->Mode);

+

+  Private->HardwareNeedsStarting  = FALSE;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+CirrusLogic5430GraphicsOutputBlt (

+  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer, OPTIONAL

+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION     BltOperation,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+/*++

+

+Routine Description:

+

+  Graphics Output protocol instance to block transfer for CirrusLogic device

+

+Arguments:

+

+  This          - Pointer to Graphics Output protocol instance

+  BltBuffer     - The data to transfer to screen

+  BltOperation  - The operation to perform

+  SourceX       - The X coordinate of the source for BltOperation

+  SourceY       - The Y coordinate of the source for BltOperation

+  DestinationX  - The X coordinate of the destination for BltOperation

+  DestinationY  - The Y coordinate of the destination for BltOperation

+  Width         - The width of a rectangle in the blt rectangle in pixels

+  Height        - The height of a rectangle in the blt rectangle in pixels

+  Delta         - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.

+                  If a Delta of 0 is used, the entire BltBuffer will be operated on.

+                  If a subrectangle of the BltBuffer is used, then Delta represents

+                  the number of bytes in a row of the BltBuffer.

+

+Returns:

+

+  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  EFI_SUCCESS - Blt operation success

+

+--*/

+{

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+  EFI_TPL                         OriginalTPL;

+  UINTN                           DstY;

+  UINTN                           SrcY;

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *Blt;

+  UINTN                           X;

+  UINT8                           Pixel;

+  UINT32                          WidePixel;

+  UINTN                           ScreenWidth;

+  UINTN                           Offset;

+  UINTN                           SourceOffset;

+  UINT32                          CurrentMode;

+

+  Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);

+

+  if ((UINT32)BltOperation >= EfiGraphicsOutputBltOperationMax) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Width == 0 || Height == 0) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // If Delta is zero, then the entire BltBuffer is being used, so Delta

+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,

+  // the number of bytes in each row can be computed.

+  //

+  if (Delta == 0) {

+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);

+  }

+

+  //

+  // We need to fill the Virtual Screen buffer with the blt data.

+  // The virtual screen is upside down, as the first row is the bootom row of

+  // the image.

+  //

+

+  CurrentMode = This->Mode->Mode;

+  //

+  // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters

+  // are valid for the operation and the current screen geometry.

+  //

+  if (BltOperation == EfiBltVideoToBltBuffer) {

+    //

+    // Video to BltBuffer: Source is Video, destination is BltBuffer

+    //

+    if (SourceY + Height > Private->ModeData[CurrentMode].VerticalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+

+    if (SourceX + Width > Private->ModeData[CurrentMode].HorizontalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+  } else {

+    //

+    // BltBuffer to Video: Source is BltBuffer, destination is Video

+    //

+    if (DestinationY + Height > Private->ModeData[CurrentMode].VerticalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+

+    if (DestinationX + Width > Private->ModeData[CurrentMode].HorizontalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+  //

+  // We have to raise to TPL Notify, so we make an atomic write the frame buffer.

+  // We would not want a timer based event (Cursor, ...) to come in while we are

+  // doing this operation.

+  //

+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);

+

+  switch (BltOperation) {

+  case EfiBltVideoToBltBuffer:

+    //

+    // Video to BltBuffer: Source is Video, destination is BltBuffer

+    //

+    for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {

+

+      Offset = (SrcY * Private->ModeData[CurrentMode].HorizontalResolution) + SourceX;

+      if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {

+        Private->PciIo->Mem.Read (

+                              Private->PciIo,

+                              EfiPciIoWidthUint32,

+                              0,

+                              Offset,

+                              Width >> 2,

+                              Private->LineBuffer

+                              );

+      } else {

+        Private->PciIo->Mem.Read (

+                              Private->PciIo,

+                              EfiPciIoWidthUint8,

+                              0,

+                              Offset,

+                              Width,

+                              Private->LineBuffer

+                              );

+      }

+

+      for (X = 0; X < Width; X++) {

+        Blt         = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

+

+        Blt->Red    = PIXEL_TO_RED_BYTE (Private->LineBuffer[X]);

+        Blt->Green  = PIXEL_TO_GREEN_BYTE (Private->LineBuffer[X]);

+        Blt->Blue   = PIXEL_TO_BLUE_BYTE (Private->LineBuffer[X]);

+      }

+    }

+    break;

+

+  case EfiBltVideoToVideo:

+    //

+    // Perform hardware acceleration for Video to Video operations

+    //

+    ScreenWidth   = Private->ModeData[CurrentMode].HorizontalResolution;

+    SourceOffset  = (SourceY * Private->ModeData[CurrentMode].HorizontalResolution) + (SourceX);

+    Offset        = (DestinationY * Private->ModeData[CurrentMode].HorizontalResolution) + (DestinationX);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0000);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0010);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0012);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0014);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0001);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0011);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0013);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0015);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Width << 8) & 0xff00) | 0x20));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Width & 0xff00) | 0x21));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Height << 8) & 0xff00) | 0x22));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Height & 0xff00) | 0x23));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x24));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x25));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x26));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x27));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) << 8) & 0xff00) | 0x28));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 0) & 0xff00) | 0x29));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 8) & 0xff00) | 0x2a));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) << 8) & 0xff00) | 0x2c));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 0) & 0xff00) | 0x2d));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 8) & 0xff00) | 0x2e));

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x002f);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0030);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0d32);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0033);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0034);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0035);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0231);

+

+    outb (Private, GRAPH_ADDRESS_REGISTER, 0x31);

+    while ((inb (Private, GRAPH_DATA_REGISTER) & 0x01) == 0x01)

+      ;

+    break;

+

+  case EfiBltVideoFill:

+    Blt       = BltBuffer;

+    Pixel     = RGB_BYTES_TO_PIXEL (Blt->Red, Blt->Green, Blt->Blue);

+    WidePixel = (Pixel << 8) | Pixel;

+    WidePixel = (WidePixel << 16) | WidePixel;

+

+    if (DestinationX == 0 && Width == Private->ModeData[CurrentMode].HorizontalResolution) {

+      Offset = DestinationY * Private->ModeData[CurrentMode].HorizontalResolution;

+      if (((Offset & 0x03) == 0) && (((Width * Height) & 0x03) == 0)) {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthFillUint32,

+                              0,

+                              Offset,

+                              (Width * Height) >> 2,

+                              &WidePixel

+                              );

+      } else {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthFillUint8,

+                              0,

+                              Offset,

+                              Width * Height,

+                              &Pixel

+                              );

+      }

+    } else {

+      for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {

+        Offset = (DstY * Private->ModeData[CurrentMode].HorizontalResolution) + DestinationX;

+        if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {

+          Private->PciIo->Mem.Write (

+                                Private->PciIo,

+                                EfiPciIoWidthFillUint32,

+                                0,

+                                Offset,

+                                Width >> 2,

+                                &WidePixel

+                                );

+        } else {

+          Private->PciIo->Mem.Write (

+                                Private->PciIo,

+                                EfiPciIoWidthFillUint8,

+                                0,

+                                Offset,

+                                Width,

+                                &Pixel

+                                );

+        }

+      }

+    }

+    break;

+

+  case EfiBltBufferToVideo:

+    for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {

+

+      for (X = 0; X < Width; X++) {

+        Blt =

+          (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (

+              (UINT8 *) BltBuffer +

+              (SrcY * Delta) +

+              ((SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))

+            );

+        Private->LineBuffer[X]  =

+          RGB_BYTES_TO_PIXEL (Blt->Red, Blt->Green, Blt->Blue);

+      }

+

+      Offset = (DstY * Private->ModeData[CurrentMode].HorizontalResolution) + DestinationX;

+

+      if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthUint32,

+                              0,

+                              Offset,

+                              Width >> 2,

+                              Private->LineBuffer

+                              );

+      } else {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthUint8,

+                              0,

+                              Offset,

+                              Width,

+                              Private->LineBuffer

+                              );

+      }

+    }

+    break;

+  default:

+    ASSERT (FALSE);

+  }

+

+  gBS->RestoreTPL (OriginalTPL);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+CirrusLogic5430GraphicsOutputConstructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+{

+  EFI_STATUS                   Status;

+  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;

+

+

+  GraphicsOutput            = &Private->GraphicsOutput;

+  GraphicsOutput->QueryMode = CirrusLogic5430GraphicsOutputQueryMode;

+  GraphicsOutput->SetMode   = CirrusLogic5430GraphicsOutputSetMode;

+  GraphicsOutput->Blt       = CirrusLogic5430GraphicsOutputBlt;

+

+  //

+  // Initialize the private data

+  //

+  Status = gBS->AllocatePool (

+                  EfiBootServicesData,

+                  sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),

+                  (VOID **) &Private->GraphicsOutput.Mode

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  Status = gBS->AllocatePool (

+                  EfiBootServicesData,

+                  sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),

+                  (VOID **) &Private->GraphicsOutput.Mode->Info

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;

+  Private->GraphicsOutput.Mode->Mode    = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;

+  Private->HardwareNeedsStarting        = TRUE;

+  Private->LineBuffer                   = NULL;

+

+  //

+  // Initialize the hardware

+  //

+  GraphicsOutput->SetMode (GraphicsOutput, 0);

+  ASSERT (Private->GraphicsOutput.Mode->Mode < CIRRUS_LOGIC_5430_MODE_COUNT);

+  DrawLogo (

+    Private,

+    Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,

+    Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution

+    );

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+CirrusLogic5430GraphicsOutputDestructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+/*++

+

+Routine Description:

+

+Arguments:

+

+Returns:

+

+  None

+

+--*/

+{

+  if (Private->GraphicsOutput.Mode != NULL) {

+    if (Private->GraphicsOutput.Mode->Info != NULL) {

+      gBS->FreePool (Private->GraphicsOutput.Mode->Info);

+    }

+    gBS->FreePool (Private->GraphicsOutput.Mode);

+  }

+

+  return EFI_SUCCESS;

+}

+

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c
new file mode 100644
index 0000000..3bfc512
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c
@@ -0,0 +1,433 @@
+/** @file

+  I2C Bus implementation upon CirrusLogic.

+

+  Copyright (c) 2008 - 2009, 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.

+

+**/

+

+#include "CirrusLogic5430.h"

+#include "CirrusLogic5430I2c.h"

+

+#define SEQ_ADDRESS_REGISTER    0x3c4

+#define SEQ_DATA_REGISTER       0x3c5

+

+#define I2C_CONTROL             0x08

+#define I2CDAT_IN               7

+#define I2CCLK_IN               2

+#define I2CDAT_OUT              1

+#define I2CCLK_OUT              0

+

+#define I2C_BUS_SPEED           100  //100kbps

+

+/**

+  PCI I/O byte write function.

+

+  @param  PciIo        The pointer to PCI_IO_PROTOCOL.

+  @param  Address      The bit map of I2C Data or I2C Clock pins.

+  @param  Data         The date to write.

+

+**/

+VOID

+I2cOutb (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINTN                  Address,

+  UINT8                  Data

+  )

+{

+  PciIo->Io.Write (

+             PciIo,

+             EfiPciIoWidthUint8,

+             EFI_PCI_IO_PASS_THROUGH_BAR,

+             Address,

+             1,

+             &Data

+             );

+}

+/**

+  PCI I/O byte read function.

+

+  @param  PciIo        The pointer to PCI_IO_PROTOCOL.

+  @param  Address      The bit map of I2C Data or I2C Clock pins.

+

+  return byte value read from PCI I/O space.

+

+**/

+UINT8

+I2cInb (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINTN                  Address

+  )

+{

+  UINT8 Data;

+

+  PciIo->Io.Read (

+             PciIo,

+             EfiPciIoWidthUint8,

+             EFI_PCI_IO_PASS_THROUGH_BAR,

+             Address,

+             1,

+             &Data

+             );

+  return Data;

+}

+

+/**

+  Read status of I2C Data and I2C Clock Pins.

+

+  @param  PciIo        The pointer to PCI_IO_PROTOCOL.

+  @param  Blt          The bit map of I2C Data or I2C Clock pins.

+

+  @retval 0            Low on I2C Data or I2C Clock Pin.

+  @retval 1            High on I2C Data or I2C Clock Pin.

+

+**/

+UINT8

+I2cPinRead (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  Bit

+  )

+{

+  I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);

+  return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe);

+}

+

+

+/**

+  Set/Clear I2C Data and I2C Clock Pins.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+  @param  Blt                The bit map to controller I2C Data or I2C Clock pins.

+  @param  Value              1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins.

+

+**/

+VOID

+I2cPinWrite (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  Bit,

+  UINT8                  Value

+  )

+{

+  UINT8        Byte;

+  I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);

+  Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ;

+  Byte = (UINT8) (Byte | ((Value & 0x01) << Bit));

+  I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40));

+  return;

+}

+

+/**

+  Read/write delay acoording to I2C Bus Speed.

+

+**/

+VOID

+I2cDelay (

+  VOID

+  )

+{

+  MicroSecondDelay (1000 / I2C_BUS_SPEED);

+}

+

+/**

+  Write a 8-bit data onto I2C Data Pin.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+  @param  Data               The byte data to write.

+

+**/

+VOID

+I2cSendByte (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  Data

+  )

+{

+  UINTN                  Index;

+  //

+  // Send byte data onto I2C Bus

+  //

+  for (Index = 0; Index < 8; Index --) {

+    I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index)));

+    I2cPinWrite (PciIo, I2CCLK_OUT, 1);

+    I2cDelay ();

+    I2cPinWrite (PciIo, I2CCLK_OUT, 0);

+  }

+}

+

+/**

+  Read a 8-bit data from I2C Data Pin.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+

+  Return the byte data read from I2C Data Pin.

+**/

+UINT8

+I2cReceiveByte (

+  EFI_PCI_IO_PROTOCOL    *PciIo

+  )

+{

+  UINT8          Data;

+  UINTN          Index;

+

+  Data = 0;

+  //

+  // Read byte data from I2C Bus

+  //

+  for (Index = 0; Index < 8; Index --) {

+    I2cPinWrite (PciIo, I2CCLK_OUT, 1);

+    I2cDelay ();

+    Data = (UINT8) (Data << 1);

+    Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN));

+    I2cPinWrite (PciIo, I2CCLK_OUT, 0);

+  }

+

+  return Data;

+}

+

+/**

+  Receive an ACK signal from I2C Bus.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+

+**/

+BOOLEAN

+I2cWaitAck (

+  EFI_PCI_IO_PROTOCOL    *PciIo

+  )

+{

+  //

+  // Wait for ACK signal

+  //

+  I2cPinWrite (PciIo, I2CDAT_OUT, 1);

+  I2cPinWrite (PciIo, I2CCLK_OUT, 1);

+  I2cDelay ();

+  if (I2cPinRead (PciIo, I2CDAT_IN) == 0) {

+    I2cPinWrite (PciIo, I2CDAT_OUT, 1);

+    return TRUE;

+  } else {

+    return FALSE;

+  }

+}

+

+/**

+  Send an ACK signal onto I2C Bus.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+

+**/

+VOID

+I2cSendAck (

+  EFI_PCI_IO_PROTOCOL    *PciIo

+  )

+{

+  I2cPinWrite (PciIo, I2CCLK_OUT, 1);

+  I2cPinWrite (PciIo, I2CDAT_OUT, 1);

+  I2cPinWrite (PciIo, I2CDAT_OUT, 0);

+  I2cPinWrite (PciIo, I2CCLK_OUT, 0);

+}

+

+/**

+  Start a I2C transfer on I2C Bus.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+

+**/

+VOID

+I2cStart (

+  EFI_PCI_IO_PROTOCOL    *PciIo

+  )

+{

+  //

+  // Init CLK and DAT pins

+  //

+  I2cPinWrite (PciIo, I2CCLK_OUT, 1);

+  I2cPinWrite (PciIo, I2CDAT_OUT, 1);

+  //

+  // Start a I2C transfer, set SDA low from high, when SCL is high

+  //

+  I2cPinWrite (PciIo, I2CDAT_OUT, 0);

+  I2cPinWrite (PciIo, I2CCLK_OUT, 0);

+}

+

+/**

+  Stop a I2C transfer on I2C Bus.

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+

+**/

+VOID

+I2cStop (

+  EFI_PCI_IO_PROTOCOL    *PciIo

+  )

+{

+  //

+  // Stop a I2C transfer, set SDA high from low, when SCL is high

+  //

+  I2cPinWrite (PciIo, I2CDAT_OUT, 0);

+  I2cPinWrite (PciIo, I2CCLK_OUT, 1);

+  I2cPinWrite (PciIo, I2CDAT_OUT, 1);

+}

+

+/**

+  Read one byte data on I2C Bus.

+

+  Read one byte data from the slave device connectet to I2C Bus.

+  If Data is NULL, then ASSERT().

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+  @param  DeviceAddress      Slave device's address.

+  @param  RegisterAddress    The register address on slave device.

+  @param  Data               The pointer to returned data if EFI_SUCCESS returned.

+

+  @retval EFI_DEVICE_ERROR

+  @retval EFI_SUCCESS

+

+**/

+EFI_STATUS

+EFIAPI

+I2cReadByte (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  DeviceAddress,

+  UINT8                  RegisterAddress,

+  UINT8                  *Data

+  )

+{

+  ASSERT (Data != NULL);

+

+  //

+  // Start I2C transfer

+  //

+  I2cStart (PciIo);

+

+  //

+  // Send slave address with enabling write flag

+  //

+  I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));

+

+  //

+  // Wait for ACK signal

+  //

+  if (I2cWaitAck (PciIo) == FALSE) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  //

+  // Send register address

+  //

+  I2cSendByte (PciIo, RegisterAddress);

+

+  //

+  // Wait for ACK signal

+  //

+  if (I2cWaitAck (PciIo) == FALSE) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  //

+  // Send slave address with enabling read flag

+  //

+  I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01));

+

+  //

+  // Wait for ACK signal

+  //

+  if (I2cWaitAck (PciIo) == FALSE) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  //

+  // Read byte data from I2C Bus

+  //

+  *Data = I2cReceiveByte (PciIo);

+

+  //

+  // Send ACK signal onto I2C Bus

+  //

+  I2cSendAck (PciIo);

+

+  //

+  // Stop a I2C transfer

+  //

+  I2cStop (PciIo);

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Write one byte data onto I2C Bus.

+

+  Write one byte data to the slave device connectet to I2C Bus.

+  If Data is NULL, then ASSERT().

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+  @param  DeviceAddress      Slave device's address.

+  @param  RegisterAddress    The register address on slave device.

+  @param  Data               The pointer to write data.

+

+  @retval EFI_DEVICE_ERROR

+  @retval EFI_SUCCESS

+

+**/

+EFI_STATUS

+EFIAPI

+I2cWriteByte (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  DeviceAddress,

+  UINT8                  RegisterAddress,

+  UINT8                  *Data

+  )

+{

+  ASSERT (Data != NULL);

+

+  I2cStart (PciIo);

+  //

+  // Send slave address with enabling write flag

+  //

+  I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));

+

+  //

+  // Wait for ACK signal

+  //

+  if (I2cWaitAck (PciIo) == FALSE) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  //

+  // Send register address

+  //

+  I2cSendByte (PciIo, RegisterAddress);

+

+  //

+  // Wait for ACK signal

+  //

+  if (I2cWaitAck (PciIo) == FALSE) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  //

+  // Send byte data onto I2C Bus

+  //

+  I2cSendByte (PciIo, *Data);

+

+  //

+  // Wait for ACK signal

+  //

+  if (I2cWaitAck (PciIo) == FALSE) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  //

+  // Stop a I2C transfer

+  //

+  I2cStop (PciIo);

+

+  return EFI_SUCCESS;

+}

+

+

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h
new file mode 100644
index 0000000..a8db4c3
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h
@@ -0,0 +1,68 @@
+/** @file

+  I2c Bus byte read/write functions.

+

+  Copyright (c) 2008 - 2009, 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.

+

+**/

+

+#ifndef _CIRRUS_LOGIC_I2C_H_

+#define _CIRRUS_LOGIC_I2C_H_

+

+#include <Protocol/PciIo.h>

+

+/**

+  Read one byte data on I2C Bus.

+

+  Read one byte data from the slave device connectet to I2C Bus.

+  If Data is NULL, then ASSERT().

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+  @param  DeviceAddress      Slave device's address.

+  @param  RegisterAddress    The register address on slave device.

+  @param  Data               The pointer to returned data if EFI_SUCCESS returned.

+

+  @retval EFI_DEVICE_ERROR

+  @retval EFI_SUCCESS

+

+**/

+EFI_STATUS

+EFIAPI

+I2cReadByte (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  DeviceAddress,

+  UINT8                  RegisterAddress,

+  UINT8                  *Data

+  );

+

+/**

+  Write one byte data onto I2C Bus.

+

+  Write one byte data to the slave device connectet to I2C Bus.

+  If Data is NULL, then ASSERT().

+

+  @param  PciIo              The pointer to PCI_IO_PROTOCOL.

+  @param  DeviceAddress      Slave device's address.

+  @param  RegisterAddress    The register address on slave device.

+  @param  Data               The pointer to write data.

+

+  @retval EFI_DEVICE_ERROR

+  @retval EFI_SUCCESS

+

+**/

+EFI_STATUS

+EFIAPI

+I2cWriteByte (

+  EFI_PCI_IO_PROTOCOL    *PciIo,

+  UINT8                  DeviceAddress,

+  UINT8                  RegisterAddress,

+  UINT8                  *Data

+  );

+

+#endif

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c
new file mode 100644
index 0000000..0f20881
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c
@@ -0,0 +1,418 @@
+/** @file

+  This file produces the graphics abstration of UGA Draw. It is called by

+  CirrusLogic5430.c file which deals with the EFI 1.1 driver model.

+  This file just does graphics.

+

+  Copyright (c) 2006 - 2012, 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.

+

+**/

+

+#include "CirrusLogic5430.h"

+

+//

+// UGA Draw Protocol Member Functions

+//

+EFI_STATUS

+EFIAPI

+CirrusLogic5430UgaDrawGetMode (

+  IN  EFI_UGA_DRAW_PROTOCOL *This,

+  OUT UINT32                *HorizontalResolution,

+  OUT UINT32                *VerticalResolution,

+  OUT UINT32                *ColorDepth,

+  OUT UINT32                *RefreshRate

+  )

+{

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+

+  Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);

+

+  if (Private->HardwareNeedsStarting) {

+    return EFI_NOT_STARTED;

+  }

+

+  if ((HorizontalResolution == NULL) ||

+      (VerticalResolution == NULL)   ||

+      (ColorDepth == NULL)           ||

+      (RefreshRate == NULL)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  *HorizontalResolution = Private->ModeData[Private->CurrentMode].HorizontalResolution;

+  *VerticalResolution   = Private->ModeData[Private->CurrentMode].VerticalResolution;

+  *ColorDepth           = Private->ModeData[Private->CurrentMode].ColorDepth;

+  *RefreshRate          = Private->ModeData[Private->CurrentMode].RefreshRate;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+CirrusLogic5430UgaDrawSetMode (

+  IN  EFI_UGA_DRAW_PROTOCOL *This,

+  IN  UINT32                HorizontalResolution,

+  IN  UINT32                VerticalResolution,

+  IN  UINT32                ColorDepth,

+  IN  UINT32                RefreshRate

+  )

+{

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+  UINTN                           Index;

+

+  Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);

+

+  for (Index = 0; Index < Private->MaxMode; Index++) {

+

+    if (HorizontalResolution != Private->ModeData[Index].HorizontalResolution) {

+      continue;

+    }

+

+    if (VerticalResolution != Private->ModeData[Index].VerticalResolution) {

+      continue;

+    }

+

+    if (ColorDepth != Private->ModeData[Index].ColorDepth) {

+      continue;

+    }

+

+    if (RefreshRate != Private->ModeData[Index].RefreshRate) {

+      continue;

+    }

+

+    if (Private->LineBuffer) {

+      gBS->FreePool (Private->LineBuffer);

+    }

+

+    Private->LineBuffer = NULL;

+    Private->LineBuffer = AllocatePool (HorizontalResolution);

+    if (Private->LineBuffer == NULL) {

+      return EFI_OUT_OF_RESOURCES;

+    }

+

+    InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[Private->ModeData[Index].ModeNumber]);

+

+    Private->CurrentMode            = Index;

+

+    Private->HardwareNeedsStarting  = FALSE;

+

+    return EFI_SUCCESS;

+  }

+

+  return EFI_NOT_FOUND;

+}

+

+EFI_STATUS

+EFIAPI

+CirrusLogic5430UgaDrawBlt (

+  IN  EFI_UGA_DRAW_PROTOCOL     *This,

+  IN  EFI_UGA_PIXEL             *BltBuffer, OPTIONAL

+  IN  EFI_UGA_BLT_OPERATION     BltOperation,

+  IN  UINTN                     SourceX,

+  IN  UINTN                     SourceY,

+  IN  UINTN                     DestinationX,

+  IN  UINTN                     DestinationY,

+  IN  UINTN                     Width,

+  IN  UINTN                     Height,

+  IN  UINTN                     Delta

+  )

+{

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;

+  EFI_TPL                         OriginalTPL;

+  UINTN                           DstY;

+  UINTN                           SrcY;

+  EFI_UGA_PIXEL                   *Blt;

+  UINTN                           X;

+  UINT8                           Pixel;

+  UINT32                          WidePixel;

+  UINTN                           ScreenWidth;

+  UINTN                           Offset;

+  UINTN                           SourceOffset;

+

+  Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);

+

+  if ((UINT32)BltOperation >= EfiUgaBltMax) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Width == 0 || Height == 0) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // If Delta is zero, then the entire BltBuffer is being used, so Delta

+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,

+  // the number of bytes in each row can be computed.

+  //

+  if (Delta == 0) {

+    Delta = Width * sizeof (EFI_UGA_PIXEL);

+  }

+

+  //

+  // We need to fill the Virtual Screen buffer with the blt data.

+  // The virtual screen is upside down, as the first row is the bootom row of

+  // the image.

+  //

+

+  //

+  // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters

+  // are valid for the operation and the current screen geometry.

+  //

+  if (BltOperation == EfiUgaVideoToBltBuffer) {

+    //

+    // Video to BltBuffer: Source is Video, destination is BltBuffer

+    //

+    if (SourceY + Height > Private->ModeData[Private->CurrentMode].VerticalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+

+    if (SourceX + Width > Private->ModeData[Private->CurrentMode].HorizontalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+  } else {

+    //

+    // BltBuffer to Video: Source is BltBuffer, destination is Video

+    //

+    if (DestinationY + Height > Private->ModeData[Private->CurrentMode].VerticalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+

+    if (DestinationX + Width > Private->ModeData[Private->CurrentMode].HorizontalResolution) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+  //

+  // We have to raise to TPL Notify, so we make an atomic write the frame buffer.

+  // We would not want a timer based event (Cursor, ...) to come in while we are

+  // doing this operation.

+  //

+  OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);

+

+  switch (BltOperation) {

+  case EfiUgaVideoToBltBuffer:

+    //

+    // Video to BltBuffer: Source is Video, destination is BltBuffer

+    //

+    for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {

+

+      Offset = (SrcY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + SourceX;

+      if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {

+        Private->PciIo->Mem.Read (

+                              Private->PciIo,

+                              EfiPciIoWidthUint32,

+                              0,

+                              Offset,

+                              Width >> 2,

+                              Private->LineBuffer

+                              );

+      } else {

+        Private->PciIo->Mem.Read (

+                              Private->PciIo,

+                              EfiPciIoWidthUint8,

+                              0,

+                              Offset,

+                              Width,

+                              Private->LineBuffer

+                              );

+      }

+

+      for (X = 0; X < Width; X++) {

+        Blt         = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_UGA_PIXEL));

+

+        Blt->Red    = (UINT8) (Private->LineBuffer[X] & 0xe0);

+        Blt->Green  = (UINT8) ((Private->LineBuffer[X] & 0x1c) << 3);

+        Blt->Blue   = (UINT8) ((Private->LineBuffer[X] & 0x03) << 6);

+      }

+    }

+    break;

+

+  case EfiUgaVideoToVideo:

+    //

+    // Perform hardware acceleration for Video to Video operations

+    //

+    ScreenWidth   = Private->ModeData[Private->CurrentMode].HorizontalResolution;

+    SourceOffset  = (SourceY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + (SourceX);

+    Offset        = (DestinationY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + (DestinationX);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0000);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0010);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0012);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0014);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0001);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0011);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0013);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0015);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Width << 8) & 0xff00) | 0x20));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Width & 0xff00) | 0x21));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Height << 8) & 0xff00) | 0x22));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Height & 0xff00) | 0x23));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x24));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x25));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x26));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x27));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) << 8) & 0xff00) | 0x28));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 0) & 0xff00) | 0x29));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 8) & 0xff00) | 0x2a));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) << 8) & 0xff00) | 0x2c));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 0) & 0xff00) | 0x2d));

+    outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 8) & 0xff00) | 0x2e));

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x002f);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0030);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0d32);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0033);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0034);

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0035);

+

+    outw (Private, GRAPH_ADDRESS_REGISTER, 0x0231);

+

+    outb (Private, GRAPH_ADDRESS_REGISTER, 0x31);

+    while ((inb (Private, GRAPH_DATA_REGISTER) & 0x01) == 0x01)

+      ;

+    break;

+

+  case EfiUgaVideoFill:

+    Blt       = BltBuffer;

+    Pixel     = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03));

+    WidePixel = (Pixel << 8) | Pixel;

+    WidePixel = (WidePixel << 16) | WidePixel;

+

+    if (DestinationX == 0 && Width == Private->ModeData[Private->CurrentMode].HorizontalResolution) {

+      Offset = DestinationY * Private->ModeData[Private->CurrentMode].HorizontalResolution;

+      if (((Offset & 0x03) == 0) && (((Width * Height) & 0x03) == 0)) {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthFillUint32,

+                              0,

+                              Offset,

+                              (Width * Height) >> 2,

+                              &WidePixel

+                              );

+      } else {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthFillUint8,

+                              0,

+                              Offset,

+                              Width * Height,

+                              &Pixel

+                              );

+      }

+    } else {

+      for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {

+        Offset = (DstY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + DestinationX;

+        if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {

+          Private->PciIo->Mem.Write (

+                                Private->PciIo,

+                                EfiPciIoWidthFillUint32,

+                                0,

+                                Offset,

+                                Width >> 2,

+                                &WidePixel

+                                );

+        } else {

+          Private->PciIo->Mem.Write (

+                                Private->PciIo,

+                                EfiPciIoWidthFillUint8,

+                                0,

+                                Offset,

+                                Width,

+                                &Pixel

+                                );

+        }

+      }

+    }

+    break;

+

+  case EfiUgaBltBufferToVideo:

+    for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {

+

+      for (X = 0; X < Width; X++) {

+        Blt                     = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + (SourceX + X) * sizeof (EFI_UGA_PIXEL));

+        Private->LineBuffer[X]  = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03));

+      }

+

+      Offset = (DstY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + DestinationX;

+

+      if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthUint32,

+                              0,

+                              Offset,

+                              Width >> 2,

+                              Private->LineBuffer

+                              );

+      } else {

+        Private->PciIo->Mem.Write (

+                              Private->PciIo,

+                              EfiPciIoWidthUint8,

+                              0,

+                              Offset,

+                              Width,

+                              Private->LineBuffer

+                              );

+      }

+    }

+    break;

+

+  default:

+    break;

+  }

+

+  gBS->RestoreTPL (OriginalTPL);

+

+  return EFI_SUCCESS;

+}

+

+//

+// Construction and Destruction functions

+//

+EFI_STATUS

+CirrusLogic5430UgaDrawConstructor (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+{

+  EFI_UGA_DRAW_PROTOCOL *UgaDraw;

+

+  //

+  // Fill in Private->UgaDraw protocol

+  //

+  UgaDraw           = &Private->UgaDraw;

+

+  UgaDraw->GetMode  = CirrusLogic5430UgaDrawGetMode;

+  UgaDraw->SetMode  = CirrusLogic5430UgaDrawSetMode;

+  UgaDraw->Blt      = CirrusLogic5430UgaDrawBlt;

+

+  //

+  // Initialize the private data

+  //

+  Private->CurrentMode            = 0;

+  Private->HardwareNeedsStarting  = TRUE;

+  Private->LineBuffer             = NULL;

+

+  //

+  // Initialize the hardware

+  //

+  UgaDraw->SetMode (

+            UgaDraw,

+            Private->ModeData[Private->CurrentMode].HorizontalResolution,

+            Private->ModeData[Private->CurrentMode].VerticalResolution,

+            Private->ModeData[Private->CurrentMode].ColorDepth,

+            Private->ModeData[Private->CurrentMode].RefreshRate

+            );

+  DrawLogo (

+    Private,

+    Private->ModeData[Private->CurrentMode].HorizontalResolution,

+    Private->ModeData[Private->CurrentMode].VerticalResolution

+    );

+

+  return EFI_SUCCESS;

+}

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c
new file mode 100644
index 0000000..e935bd7
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c
@@ -0,0 +1,209 @@
+/** @file

+  Copyright (c) 2006 - 2011, 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.             

+

+**/

+

+#include "CirrusLogic5430.h"

+

+//

+// EFI Component Name Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gCirrusLogic5430ComponentName = {

+  CirrusLogic5430ComponentNameGetDriverName,

+  CirrusLogic5430ComponentNameGetControllerName,

+  "eng"

+};

+

+//

+// EFI Component Name 2 Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gCirrusLogic5430ComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) CirrusLogic5430ComponentNameGetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) CirrusLogic5430ComponentNameGetControllerName,

+  "en"

+};

+

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mCirrusLogic5430DriverNameTable[] = {

+  { "eng;en", L"Cirrus Logic 5430 Driver" },

+  { NULL , NULL }

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mCirrusLogic5430ControllerNameTable[] = {

+  { "eng;en", L"Cirrus Logic 5430 PCI Adapter" },

+  { NULL , NULL }

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  )

+{

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mCirrusLogic5430DriverNameTable,

+           DriverName,

+           (BOOLEAN)(This == &gCirrusLogic5430ComponentName)

+           );

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+CirrusLogic5430ComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  )

+{

+  EFI_STATUS                      Status;

+

+  //

+  // This is a device driver, so ChildHandle must be NULL.

+  //

+  if (ChildHandle != NULL) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Make sure this driver is currently managing ControllHandle

+  //

+  Status = EfiTestManagedDevice (

+             ControllerHandle,

+             gCirrusLogic5430DriverBinding.DriverBindingHandle,

+             &gEfiPciIoProtocolGuid

+             );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Get the Cirrus Logic 5430's Device structure

+  //

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mCirrusLogic5430ControllerNameTable,

+           ControllerName,

+           (BOOLEAN)(This == &gCirrusLogic5430ComponentName)

+           );

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c
new file mode 100644
index 0000000..8fcfdfa
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c
@@ -0,0 +1,20 @@
+/** @file

+  Copyright (c) 2007, 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.             

+

+  Module Name:  DriverSupportEfiVersion.c

+

+**/

+#include "CirrusLogic5430.h"

+

+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gCirrusLogic5430DriverSupportedEfiVersion = {

+  sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.

+  0                                                   // Version number to be filled at start up.

+};

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/Edid.c b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/Edid.c
new file mode 100644
index 0000000..6ce681a
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/CirrusLogic5430Dxe/Edid.c
@@ -0,0 +1,531 @@
+/** @file

+  Read EDID information and parse EDID information.

+

+  Copyright (c) 2008 - 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.

+

+**/

+

+#include "CirrusLogic5430.h"

+#include "CirrusLogic5430I2c.h"

+

+//

+// EDID block

+//

+typedef struct {

+  UINT8   Header[8];                        //EDID header "00 FF FF FF FF FF FF 00"

+  UINT16  ManufactureName;                  //EISA 3-character ID

+  UINT16  ProductCode;                      //Vendor assigned code

+  UINT32  SerialNumber;                     //32-bit serial number

+  UINT8   WeekOfManufacture;                //Week number

+  UINT8   YearOfManufacture;                //Year

+  UINT8   EdidVersion;                      //EDID Structure Version

+  UINT8   EdidRevision;                     //EDID Structure Revision

+  UINT8   VideoInputDefinition;

+  UINT8   MaxHorizontalImageSize;           //cm

+  UINT8   MaxVerticalImageSize;             //cm

+  UINT8   DisplayTransferCharacteristic;

+  UINT8   FeatureSupport;

+  UINT8   RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0

+  UINT8   BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0

+  UINT8   RedX;                             //Red-x Bits 9 - 2

+  UINT8   RedY;                             //Red-y Bits 9 - 2

+  UINT8   GreenX;                           //Green-x Bits 9 - 2

+  UINT8   GreenY;                           //Green-y Bits 9 - 2

+  UINT8   BlueX;                            //Blue-x Bits 9 - 2

+  UINT8   BlueY;                            //Blue-y Bits 9 - 2

+  UINT8   WhiteX;                           //White-x Bits 9 - 2

+  UINT8   WhiteY;                           //White-x Bits 9 - 2

+  UINT8   EstablishedTimings[3];

+  UINT8   StandardTimingIdentification[16];

+  UINT8   DetailedTimingDescriptions[72];

+  UINT8   ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow

+  UINT8   Checksum;

+} EDID_BLOCK;

+

+#define EDID_BLOCK_SIZE                        128

+#define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17

+

+typedef struct {

+  UINT16  HorizontalResolution;

+  UINT16  VerticalResolution;

+  UINT16  RefreshRate;

+} EDID_TIMING;

+

+typedef struct {

+  UINT32  ValidNumber;

+  UINT32  Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];

+} VALID_EDID_TIMING;

+

+//

+// Standard timing defined by VESA EDID

+//

+EDID_TIMING mVbeEstablishedEdidTiming[] = {

+  //

+  // Established Timing I

+  //

+  {800, 600, 60},

+  {800, 600, 56},

+  {640, 480, 75},

+  {640, 480, 72},

+  {640, 480, 67},

+  {640, 480, 60},

+  {720, 400, 88},

+  {720, 400, 70},

+  //

+  // Established Timing II

+  //

+  {1280, 1024, 75},

+  {1024,  768, 75},

+  {1024,  768, 70},

+  {1024,  768, 60},

+  {1024,  768, 87},

+  {832,   624, 75},

+  {800,   600, 75},

+  {800,   600, 72},

+  //

+  // Established Timing III

+  //

+  {1152, 870, 75}

+};

+

+/**

+  Read EDID information from I2C Bus on CirrusLogic.

+

+  @param  Private             Pointer to CIRRUS_LOGIC_5430_PRIVATE_DATA.

+  @param  EdidDataBlock       Pointer to EDID data block.

+  @param  EdidSize            Returned EDID block size.

+

+  @retval EFI_UNSUPPORTED

+  @retval EFI_SUCCESS

+

+**/

+EFI_STATUS

+ReadEdidData (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA     *Private,

+  UINT8                              **EdidDataBlock,

+  UINTN                              *EdidSize

+  )

+{

+  UINTN             Index;

+  UINT8             EdidData[EDID_BLOCK_SIZE * 2];

+  UINT8             *ValidEdid;

+  UINT64            Signature;

+

+  for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {

+    I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]);

+  }

+

+  //

+  // Search for the EDID signature

+  //

+  ValidEdid = &EdidData[0];

+  Signature = 0x00ffffffffffff00ull;

+  for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++) {

+    if (CompareMem (ValidEdid, &Signature, 8) == 0) {

+      break;

+    }

+  }

+

+  if (Index == 256) {

+    //

+    // No EDID signature found

+    //

+    return EFI_UNSUPPORTED;

+  }

+

+  *EdidDataBlock = AllocateCopyPool (

+                     EDID_BLOCK_SIZE,

+                     ValidEdid

+                     );

+  if (*EdidDataBlock == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  //

+  // Currently only support EDID 1.x

+  //

+  *EdidSize = EDID_BLOCK_SIZE;

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Generate a search key for a specified timing data.

+

+  @param  EdidTiming             Pointer to EDID timing

+

+  @return The 32 bit unique key for search.

+

+**/

+UINT32

+CalculateEdidKey (

+  EDID_TIMING       *EdidTiming

+  )

+{

+  UINT32 Key;

+

+  //

+  // Be sure no conflicts for all standard timing defined by VESA.

+  //

+  Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;

+  return Key;

+}

+

+/**

+  Search a specified Timing in all the valid EDID timings.

+

+  @param  ValidEdidTiming        All valid EDID timing information.

+  @param  EdidTiming             The Timing to search for.

+

+  @retval TRUE                   Found.

+  @retval FALSE                  Not found.

+

+**/

+BOOLEAN

+SearchEdidTiming (

+  VALID_EDID_TIMING *ValidEdidTiming,

+  EDID_TIMING       *EdidTiming

+  )

+{

+  UINT32 Index;

+  UINT32 Key;

+

+  Key = CalculateEdidKey (EdidTiming);

+

+  for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {

+    if (Key == ValidEdidTiming->Key[Index]) {

+      return TRUE;

+    }

+  }

+

+  return FALSE;

+}

+

+/**

+  Parse the Established Timing and Standard Timing in EDID data block.

+

+  @param  EdidBuffer             Pointer to EDID data block

+  @param  ValidEdidTiming        Valid EDID timing information

+

+  @retval TRUE                   The EDID data is valid.

+  @retval FALSE                  The EDID data is invalid.

+

+**/

+BOOLEAN

+ParseEdidData (

+  UINT8                         *EdidBuffer,

+  VALID_EDID_TIMING             *ValidEdidTiming

+  )

+{

+  UINT8        CheckSum;

+  UINT32       Index;

+  UINT32       ValidNumber;

+  UINT32       TimingBits;

+  UINT8        *BufferIndex;

+  UINT16       HorizontalResolution;

+  UINT16       VerticalResolution;

+  UINT8        AspectRatio;

+  UINT8        RefreshRate;

+  EDID_TIMING  TempTiming;

+  EDID_BLOCK   *EdidDataBlock;

+

+  EdidDataBlock = (EDID_BLOCK *) EdidBuffer;

+

+  //

+  // Check the checksum of EDID data

+  //

+  CheckSum = 0;

+  for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {

+    CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);

+  }

+  if (CheckSum != 0) {

+    return FALSE;

+  }

+

+  ValidNumber = 0;

+  SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);

+

+  if ((EdidDataBlock->EstablishedTimings[0] != 0) ||

+      (EdidDataBlock->EstablishedTimings[1] != 0) ||

+      (EdidDataBlock->EstablishedTimings[2] != 0)

+      ) {

+    //

+    // Established timing data

+    //

+    TimingBits = EdidDataBlock->EstablishedTimings[0] |

+                 (EdidDataBlock->EstablishedTimings[1] << 8) |

+                 ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;

+    for (Index = 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {

+      if (TimingBits & 0x1) {

+        ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mVbeEstablishedEdidTiming[Index]);

+        ValidNumber ++;

+      }

+      TimingBits = TimingBits >> 1;

+    }

+  } else {

+    //

+    // If no Established timing data, read the standard timing data

+    //

+    BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];

+    for (Index = 0; Index < 8; Index ++) {

+      if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){

+        //

+        // A valid Standard Timing

+        //

+        HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);

+        AspectRatio = (UINT8) (BufferIndex[1] >> 6);

+        switch (AspectRatio) {

+          case 0:

+            VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);

+            break;

+          case 1:

+            VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);

+            break;

+          case 2:

+            VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);

+            break;

+          case 3:

+            VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);

+            break;

+          default:

+            VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);

+            break;

+        }

+        RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);

+        TempTiming.HorizontalResolution = HorizontalResolution;

+        TempTiming.VerticalResolution = VerticalResolution;

+        TempTiming.RefreshRate = RefreshRate;

+        ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);

+        ValidNumber ++;

+      }

+      BufferIndex += 2;

+    }

+  }

+

+  ValidEdidTiming->ValidNumber = ValidNumber;

+  return TRUE;

+}

+

+/**

+  Construct the valid video modes for CirrusLogic5430.

+

+**/

+EFI_STATUS

+CirrusLogic5430VideoModeSetup (

+  CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private

+  )

+{

+  EFI_STATUS                             Status;

+  UINT32                                 Index;

+  BOOLEAN                                EdidFound;

+  EFI_EDID_OVERRIDE_PROTOCOL             *EdidOverride;

+  UINT32                                 EdidAttributes;

+  BOOLEAN                                EdidOverrideFound;

+  UINTN                                  EdidOverrideDataSize;

+  UINT8                                  *EdidOverrideDataBlock;

+  UINTN                                  EdidDiscoveredDataSize;

+  UINT8                                  *EdidDiscoveredDataBlock;

+  UINTN                                  EdidActiveDataSize;

+  UINT8                                  *EdidActiveDataBlock;

+  VALID_EDID_TIMING                      ValidEdidTiming;

+  UINT32                                 ValidModeCount;

+  CIRRUS_LOGIC_5430_MODE_DATA            *ModeData;

+  BOOLEAN                                TimingMatch;

+  CIRRUS_LOGIC_5430_VIDEO_MODES          *VideoMode;

+  EDID_TIMING                            TempTiming;

+

+  //

+  // setup EDID information

+  //

+  Private->EdidDiscovered.Edid       = NULL;

+  Private->EdidDiscovered.SizeOfEdid = 0;

+  Private->EdidActive.Edid           = NULL;

+  Private->EdidActive.SizeOfEdid     = 0;

+

+  EdidFound               = FALSE;

+  EdidOverrideFound       = FALSE;

+  EdidAttributes          = 0xff;

+  EdidOverrideDataSize    = 0;

+  EdidOverrideDataBlock   = NULL;

+  EdidActiveDataSize      = 0;

+  EdidActiveDataBlock     = NULL;

+  EdidDiscoveredDataBlock = NULL;

+

+  //

+  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.

+  //

+  Status = gBS->LocateProtocol (

+                   &gEfiEdidOverrideProtocolGuid,

+                   NULL,

+                   (VOID **) &EdidOverride

+                   );

+  if (!EFI_ERROR (Status)) {

+    //

+    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow

+    //

+    EdidOverrideDataBlock = AllocatePool (EDID_BLOCK_SIZE * 2);

+    if (NULL == EdidOverrideDataBlock) {

+  		Status = EFI_OUT_OF_RESOURCES;

+      goto Done;

+    }

+

+    Status = EdidOverride->GetEdid (

+                             EdidOverride,

+                             Private->Handle,

+                             &EdidAttributes,

+                             &EdidOverrideDataSize,

+                             (UINT8 **) &EdidOverrideDataBlock

+                             );

+    if (!EFI_ERROR (Status)  &&

+         EdidAttributes == 0 &&

+         EdidOverrideDataSize != 0) {

+      //

+      // Succeeded to get EDID Override Data

+      //

+      EdidOverrideFound = TRUE;

+    }

+  }

+

+  if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {

+    //

+    // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,

+    // read EDID information through I2C Bus

+    //

+    if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {

+      Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;

+     	Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (

+                                                          EdidDiscoveredDataSize,

+                                                          EdidDiscoveredDataBlock

+     																										  );

+

+      if (NULL == Private->EdidDiscovered.Edid) {

+     	  Status = EFI_OUT_OF_RESOURCES;

+        goto Done;

+      }

+

+      EdidActiveDataSize  = Private->EdidDiscovered.SizeOfEdid;

+      EdidActiveDataBlock = Private->EdidDiscovered.Edid;

+

+      EdidFound = TRUE;

+    }

+  }

+

+  if (EdidFound != TRUE && EdidOverrideFound == TRUE) {

+    EdidActiveDataSize  = EdidOverrideDataSize;

+    EdidActiveDataBlock = EdidOverrideDataBlock;

+    EdidFound = TRUE;

+ 	}

+

+ 	if (EdidFound == TRUE) {

+    //

+    // Parse EDID data structure to retrieve modes supported by monitor

+    //

+    if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {

+      //

+      // Copy EDID Override Data to EDID Active Data

+      //

+      Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;

+      Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (

+                                             EdidActiveDataSize,

+                                             EdidActiveDataBlock

+                                             );

+      if (NULL == Private->EdidActive.Edid) {

+   		  Status = EFI_OUT_OF_RESOURCES;

+        goto Done;

+      }

+    }

+  } else {

+    Private->EdidActive.SizeOfEdid = 0;

+    Private->EdidActive.Edid = NULL;

+    EdidFound = FALSE;

+  }

+

+  if (EdidFound) {

+    //

+    // Initialize the private mode data with the supported modes.

+    //

+    ValidModeCount = 0;

+    ModeData = &Private->ModeData[0];

+    VideoMode = &CirrusLogic5430VideoModes[0];

+    for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index++) {

+

+      TimingMatch = TRUE;

+

+      //

+      // Check whether match with CirrusLogic5430 video mode

+      //

+      TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;

+      TempTiming.VerticalResolution   = (UINT16) VideoMode->Height;

+      TempTiming.RefreshRate          = (UINT16) VideoMode->RefreshRate;

+      if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {

+        TimingMatch = FALSE;

+      }

+

+      //

+      // Not export Mode 0x0 as GOP mode, this is not defined in spec.

+      //

+      if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {

+        TimingMatch = FALSE;

+      }

+

+      if (TimingMatch) {

+        ModeData->ModeNumber = Index;

+        ModeData->HorizontalResolution          = VideoMode->Width;

+        ModeData->VerticalResolution            = VideoMode->Height;

+        ModeData->ColorDepth                    = VideoMode->ColorDepth;

+        ModeData->RefreshRate                   = VideoMode->RefreshRate;

+

+        ModeData ++;

+        ValidModeCount ++;

+      }

+

+      VideoMode ++;

+    }

+

+    Private->MaxMode = ValidModeCount;

+

+  } else {

+    //

+    // If EDID information wasn't found

+    //

+    ModeData = &Private->ModeData[0];

+    VideoMode = &CirrusLogic5430VideoModes[0];

+    for (Index = 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index ++) {

+      ModeData->ModeNumber = Index;

+      ModeData->HorizontalResolution          = VideoMode->Width;

+      ModeData->VerticalResolution            = VideoMode->Height;

+      ModeData->ColorDepth                    = VideoMode->ColorDepth;

+      ModeData->RefreshRate                   = VideoMode->RefreshRate;

+

+      ModeData ++ ;

+      VideoMode ++;

+    }

+    Private->MaxMode = CIRRUS_LOGIC_5430_MODE_COUNT;

+  }

+

+  if (EdidOverrideDataBlock != NULL) {

+    FreePool (EdidOverrideDataBlock);

+  }

+

+  return EFI_SUCCESS;

+

+Done:

+  if (EdidOverrideDataBlock != NULL) {

+    FreePool (EdidOverrideDataBlock);

+  }

+  if (Private->EdidDiscovered.Edid != NULL) {

+    FreePool (Private->EdidDiscovered.Edid);

+  }

+  if (Private->EdidDiscovered.Edid != NULL) {

+    FreePool (Private->EdidActive.Edid);

+  }

+

+  return EFI_DEVICE_ERROR;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/Contributions.txt b/uefi/linaro-edk2/OptionRomPkg/Contributions.txt
new file mode 100644
index 0000000..f87cbd7
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Contributions.txt
@@ -0,0 +1,218 @@
+

+======================

+= Code Contributions =

+======================

+

+To make a contribution to a TianoCore project, follow these steps.

+1. Create a change description in the format specified below to

+   use in the source control commit log.

+2. Your commit message must include your "Signed-off-by" signature,

+   and "Contributed-under" message.

+3. Your "Contributed-under" message explicitly states that the

+   contribution is made under the terms of the specified

+   contribution agreement.  Your "Contributed-under" message

+   must include the name of contribution agreement and version.

+   For example: Contributed-under: TianoCore Contribution Agreement 1.0

+   The "TianoCore Contribution Agreement" is included below in

+   this document.

+4. Submit your code to the TianoCore project using the process

+   that the project documents on its web page.  If the process is

+   not documented, then submit the code on development email list

+   for the project.

+5. It is preferred that contributions are submitted using the same

+   copyright license as the base project. When that is not possible,

+   then contributions using the following licenses can be accepted:

+   * BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause

+   * BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause

+   * MIT: http://opensource.org/licenses/MIT

+   * Python-2.0: http://opensource.org/licenses/Python-2.0

+   * Zlib: http://opensource.org/licenses/Zlib

+

+   Contributions of code put into the public domain can also be

+   accepted.

+

+   Contributions using other licenses might be accepted, but further

+   review will be required.

+

+=====================================================

+= Change Description / Commit Message / Patch Email =

+=====================================================

+

+Your change description should use the standard format for a

+commit message, and must include your "Signed-off-by" signature

+and the "Contributed-under" message.

+

+== Sample Change Description / Commit Message =

+

+=== Start of sample patch email message ===

+

+From: Contributor Name <contributor@example.com>

+Subject: [PATCH] CodeModule: Brief-single-line-summary

+

+Full-commit-message

+

+Contributed-under: TianoCore Contribution Agreement 1.0

+Signed-off-by: Contributor Name <contributor@example.com>

+---

+

+An extra message for the patch email which will not be considered part

+of the commit message can be added here.

+

+Patch content inline or attached

+

+=== End of sample patch email message ===

+

+=== Notes for sample patch email ===

+

+* The first line of commit message is taken from the email's subject

+  line following [PATCH]. The remaining portion of the commit message

+  is the email's content until the '---' line.

+* git format-patch is one way to create this format

+

+=== Definitions for sample patch email ===

+

+* "CodeModule" is a short idenfier for the affected code.  For

+  example MdePkg, or MdeModulePkg UsbBusDxe.

+* "Brief-single-line-summary" is a short summary of the change.

+* The entire first line should be less than ~70 characters.

+* "Full-commit-message" a verbose multiple line comment describing

+  the change.  Each line should be less than ~70 characters.

+* "Contributed-under" explicitely states that the contribution is

+  made under the terms of the contribtion agreement.  This

+  agreement is included below in this document.

+* "Signed-off-by" is the contributor's signature identifying them

+  by their real/legal name and their email address.

+

+========================================

+= TianoCore Contribution Agreement 1.0 =

+========================================

+

+INTEL CORPORATION ("INTEL") MAKES AVAILABLE SOFTWARE, DOCUMENTATION,

+INFORMATION AND/OR OTHER MATERIALS FOR USE IN THE TIANOCORE OPEN SOURCE

+PROJECT (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE

+TERMS AND CONDITIONS OF THIS AGREEMENT BETWEEN YOU AND INTEL AND/OR THE

+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR

+REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE

+CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS

+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED

+BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS

+AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE

+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT

+USE THE CONTENT.

+

+Unless otherwise indicated, all Content made available on the TianoCore

+site is provided to you under the terms and conditions of the BSD

+License ("BSD"). A copy of the BSD License is available at

+http://opensource.org/licenses/bsd-license.php

+or when applicable, in the associated License.txt file.

+

+Certain other content may be made available under other licenses as

+indicated in or with such Content. (For example, in a License.txt file.)

+

+You accept and agree to the following terms and conditions for Your

+present and future Contributions submitted to TianoCore site. Except

+for the license granted to Intel hereunder, You reserve all right,

+title, and interest in and to Your Contributions.

+

+== SECTION 1: Definitions ==

+* "You" or "Contributor" shall mean the copyright owner or legal

+  entity authorized by the copyright owner that is making a

+  Contribution hereunder. All other entities that control, are

+  controlled by, or are under common control with that entity are

+  considered to be a single Contributor. For the purposes of this

+  definition, "control" means (i) the power, direct or indirect, to

+  cause the direction or management of such entity, whether by

+  contract or otherwise, or (ii) ownership of fifty percent (50%)

+  or more of the outstanding shares, or (iii) beneficial ownership

+  of such entity.

+* "Contribution" shall mean any original work of authorship,

+  including any modifications or additions to an existing work,

+  that is intentionally submitted by You to the TinaoCore site for

+  inclusion in, or documentation of, any of the Content. For the

+  purposes of this definition, "submitted" means any form of

+  electronic, verbal, or written communication sent to the

+  TianoCore site or its representatives, including but not limited

+  to communication on electronic mailing lists, source code

+  control systems, and issue tracking systems that are managed by,

+  or on behalf of, the TianoCore site for the purpose of

+  discussing and improving the Content, but excluding

+  communication that is conspicuously marked or otherwise

+  designated in writing by You as "Not a Contribution."

+

+== SECTION 2: License for Contributions ==

+* Contributor hereby agrees that redistribution and use of the

+  Contribution in source and binary forms, with or without

+  modification, are permitted provided that the following

+  conditions are met:

+** Redistributions of source code must retain the Contributor's

+   copyright notice, this list of conditions and the following

+   disclaimer.

+** Redistributions in binary form must reproduce the Contributor's

+   copyright notice, this list of conditions and the following

+   disclaimer in the documentation and/or other materials provided

+   with the distribution.

+* Disclaimer. None of the names of Contributor, Intel, or the names

+  of their respective contributors may be used to endorse or

+  promote products derived from this software without specific

+  prior written permission.

+* Contributor grants a license (with the right to sublicense) under

+  claims of Contributor's patents that Contributor can license that

+  are infringed by the Contribution (as delivered by Contributor) to

+  make, use, distribute, sell, offer for sale, and import the

+  Contribution and derivative works thereof solely to the minimum

+  extent necessary for licensee to exercise the granted copyright

+  license; this patent license applies solely to those portions of

+  the Contribution that are unmodified. No hardware per se is

+  licensed.

+* EXCEPT AS EXPRESSLY SET FORTH IN SECTION 3 BELOW, THE

+  CONTRIBUTION IS PROVIDED BY THE CONTRIBUTOR "AS IS" AND ANY

+  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,

+  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A

+  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

+  CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT

+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR

+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE

+  CONTRIBUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH

+  DAMAGE.

+

+== SECTION 3: Representations ==

+* You represent that You are legally entitled to grant the above

+  license. If your employer(s) has rights to intellectual property

+  that You create that includes Your Contributions, You represent

+  that You have received permission to make Contributions on behalf

+  of that employer, that Your employer has waived such rights for

+  Your Contributions.

+* You represent that each of Your Contributions is Your original

+  creation (see Section 4 for submissions on behalf of others).

+  You represent that Your Contribution submissions include complete

+  details of any third-party license or other restriction

+  (including, but not limited to, related patents and trademarks)

+  of which You are personally aware and which are associated with

+  any part of Your Contributions.

+

+== SECTION 4: Third Party Contributions ==

+* Should You wish to submit work that is not Your original creation,

+  You may submit it to TianoCore site separately from any

+  Contribution, identifying the complete details of its source

+  and of any license or other restriction (including, but not

+  limited to, related patents, trademarks, and license agreements)

+  of which You are personally aware, and conspicuously marking the

+  work as "Submitted on behalf of a third-party: [named here]".

+

+== SECTION 5: Miscellaneous ==

+* Applicable Laws. Any claims arising under or relating to this

+  Agreement shall be governed by the internal substantive laws of

+  the State of Delaware or federal courts located in Delaware,

+  without regard to principles of conflict of laws.

+* Language. This Agreement is in the English language only, which

+  language shall be controlling in all respects, and all versions

+  of this Agreement in any other language shall be for accommodation

+  only and shall not be binding. All communications and notices made

+  or given pursuant to this Agreement, and all documentation and

+  support to be provided, unless otherwise noted, shall be in the

+  English language.

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Include/Library/BltLib.h b/uefi/linaro-edk2/OptionRomPkg/Include/Library/BltLib.h
new file mode 100644
index 0000000..98d49e5
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Include/Library/BltLib.h
@@ -0,0 +1,259 @@
+/** @file

+  Library for performing video blt operations

+

+  Copyright (c) 2009 - 2011, 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.

+

+**/

+

+#ifndef __BLT_LIB__

+#define __BLT_LIB__

+

+#include <Protocol/GraphicsOutput.h>

+

+

+/**

+  Configure the BltLib for a frame-buffer

+

+  @param[in] FrameBuffer      Pointer to the start of the frame buffer

+  @param[in] FrameBufferInfo  Describes the frame buffer characteristics

+

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibConfigure (

+  IN  VOID                                 *FrameBuffer,

+  IN  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt operation.

+

+  @param[in,out] BltBuffer     - The data to transfer to screen

+  @param[in]     BltOperation  - The operation to perform

+  @param[in]     SourceX       - The X coordinate of the source for BltOperation

+  @param[in]     SourceY       - The Y coordinate of the source for BltOperation

+  @param[in]     DestinationX  - The X coordinate of the destination for BltOperation

+  @param[in]     DestinationY  - The Y coordinate of the destination for BltOperation

+  @param[in]     Width         - The width of a rectangle in the blt rectangle in pixels

+  @param[in]     Height        - The height of a rectangle in the blt rectangle in pixels

+  @param[in]     Delta         - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.

+                                 If a Delta of 0 is used, the entire BltBuffer will be operated on.

+                                 If a subrectangle of the BltBuffer is used, then Delta represents

+                                 the number of bytes in a row of the BltBuffer.

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibGopBlt (

+  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL      *BltBuffer, OPTIONAL

+  IN     EFI_GRAPHICS_OUTPUT_BLT_OPERATION  BltOperation,

+  IN     UINTN                              SourceX,

+  IN     UINTN                              SourceY,

+  IN     UINTN                              DestinationX,

+  IN     UINTN                              DestinationY,

+  IN     UINTN                              Width,

+  IN     UINTN                              Height,

+  IN     UINTN                              Delta

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video Fill.

+

+  @param[in]  Color         Color to fill the region with

+  @param[in]  DestinationX  X location to start fill operation

+  @param[in]  DestinationY  Y location to start fill operation

+  @param[in]  Width         Width (in pixels) to fill

+  @param[in]  Height        Height to fill

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoFill (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *Color,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation.

+

+  @param[out] BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToBltBuffer (

+  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation

+  with extended parameters.

+

+  @param[out] BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  DestinationX  X location within BltBuffer

+  @param[in]  DestinationY  Y location within BltBuffer

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+  @param[in]  Delta         Number of bytes in a row of BltBuffer

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToBltBufferEx (

+  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation.

+

+  @param[in]  BltBuffer     Output buffer for pixel color data

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibBufferToVideo (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation

+  with extended parameters.

+

+  @param[in]  BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within BltBuffer

+  @param[in]  SourceY       Y location within BltBuffer

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+  @param[in]  Delta         Number of bytes in a row of BltBuffer

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibBufferToVideoEx (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  );

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Video operation

+

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToVideo (

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  );

+

+

+/**

+  Returns the sizes related to the video device

+

+  @param[out]  Width   Width (in pixels)

+  @param[out]  Height  Height (in pixels)

+

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibGetSizes (

+  OUT UINTN                                 *Width,  OPTIONAL

+  OUT UINTN                                 *Height  OPTIONAL

+  );

+

+#endif

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c b/uefi/linaro-edk2/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c
new file mode 100644
index 0000000..7138ebf
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c
@@ -0,0 +1,752 @@
+/** @file

+  FrameBufferBltLib - Library to perform blt operations on a frame buffer.

+

+  Copyright (c) 2007 - 2011, 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.

+

+**/

+

+#include "PiDxe.h"

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/BltLib.h>

+#include <Library/DebugLib.h>

+

+#if 0

+#define VDEBUG DEBUG

+#else

+#define VDEBUG(x)

+#endif

+

+#define MAX_LINE_BUFFER_SIZE (SIZE_4KB * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))

+

+UINTN                           mBltLibColorDepth;

+UINTN                           mBltLibWidthInBytes;

+UINTN                           mBltLibBytesPerPixel;

+UINTN                           mBltLibWidthInPixels;

+UINTN                           mBltLibHeight;

+UINT8                           mBltLibLineBuffer[MAX_LINE_BUFFER_SIZE];

+UINT8                           *mBltLibFrameBuffer;

+EFI_GRAPHICS_PIXEL_FORMAT       mPixelFormat;

+EFI_PIXEL_BITMASK               mPixelBitMasks;

+INTN                            mPixelShl[4]; // R-G-B-Rsvd

+INTN                            mPixelShr[4]; // R-G-B-Rsvd

+

+

+VOID

+ConfigurePixelBitMaskFormat (

+  IN EFI_PIXEL_BITMASK          *BitMask

+  )

+{

+  UINTN   Loop;

+  UINT32  *Masks;

+  UINT32  MergedMasks;

+

+  MergedMasks = 0;

+  Masks = (UINT32*) BitMask;

+  for (Loop = 0; Loop < 3; Loop++) {

+    ASSERT ((Loop == 3) || (Masks[Loop] != 0));

+    ASSERT ((MergedMasks & Masks[Loop]) == 0);

+    mPixelShl[Loop] = HighBitSet32 (Masks[Loop]) - 23 + (Loop * 8);

+    if (mPixelShl[Loop] < 0) {

+      mPixelShr[Loop] = -mPixelShl[Loop];

+      mPixelShl[Loop] = 0;

+    } else {

+      mPixelShr[Loop] = 0;

+    }

+    MergedMasks = (UINT32) (MergedMasks | Masks[Loop]);

+    DEBUG ((EFI_D_INFO, "%d: shl:%d shr:%d mask:%x\n", Loop, mPixelShl[Loop], mPixelShr[Loop], Masks[Loop]));

+  }

+  MergedMasks = (UINT32) (MergedMasks | Masks[3]);

+

+  ASSERT (MergedMasks != 0);

+  mBltLibBytesPerPixel = (UINTN) ((HighBitSet32 (MergedMasks) + 7) / 8);

+

+  DEBUG ((EFI_D_INFO, "Bytes per pixel: %d\n", mBltLibBytesPerPixel));

+

+  CopyMem (&mPixelBitMasks, BitMask, sizeof (*BitMask));

+}

+

+

+/**

+  Configure the FrameBufferLib instance

+

+  @param[in] FrameBuffer      Pointer to the start of the frame buffer

+  @param[in] FrameBufferInfo  Describes the frame buffer characteristics

+

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter

+  @retval  EFI_UNSUPPORTED - The BltLib does not support this configuration

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibConfigure (

+  IN  VOID                                 *FrameBuffer,

+  IN  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo

+  )

+{

+  STATIC EFI_PIXEL_BITMASK  RgbPixelMasks =

+    { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };

+  STATIC EFI_PIXEL_BITMASK  BgrPixelMasks =

+    { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };

+

+  switch (FrameBufferInfo->PixelFormat) {

+  case PixelRedGreenBlueReserved8BitPerColor:

+    ConfigurePixelBitMaskFormat (&RgbPixelMasks);

+    break;

+  case PixelBlueGreenRedReserved8BitPerColor:

+    ConfigurePixelBitMaskFormat (&BgrPixelMasks);

+    break;

+  case PixelBitMask:

+    ConfigurePixelBitMaskFormat (&(FrameBufferInfo->PixelInformation));

+    break;

+  case PixelBltOnly:

+    ASSERT (FrameBufferInfo->PixelFormat != PixelBltOnly);

+    return EFI_UNSUPPORTED;

+  default:

+    ASSERT (FALSE);

+    return EFI_INVALID_PARAMETER;

+  }

+  mPixelFormat = FrameBufferInfo->PixelFormat;

+

+  mBltLibFrameBuffer = (UINT8*) FrameBuffer;

+  mBltLibWidthInPixels = (UINTN) FrameBufferInfo->HorizontalResolution;

+  mBltLibHeight = (UINTN) FrameBufferInfo->VerticalResolution;

+  mBltLibWidthInBytes = mBltLibWidthInPixels * mBltLibBytesPerPixel;

+

+  ASSERT (mBltLibWidthInBytes < sizeof (mBltLibLineBuffer));

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt operation.

+

+  @param[in,out] BltBuffer     - The data to transfer to screen

+  @param[in]     BltOperation  - The operation to perform

+  @param[in]     SourceX       - The X coordinate of the source for BltOperation

+  @param[in]     SourceY       - The Y coordinate of the source for BltOperation

+  @param[in]     DestinationX  - The X coordinate of the destination for BltOperation

+  @param[in]     DestinationY  - The Y coordinate of the destination for BltOperation

+  @param[in]     Width         - The width of a rectangle in the blt rectangle in pixels

+  @param[in]     Height        - The height of a rectangle in the blt rectangle in pixels

+  @param[in]     Delta         - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.

+                                 If a Delta of 0 is used, the entire BltBuffer will be operated on.

+                                 If a subrectangle of the BltBuffer is used, then Delta represents

+                                 the number of bytes in a row of the BltBuffer.

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibGopBlt (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer, OPTIONAL

+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION     BltOperation,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  switch (BltOperation) {

+  case EfiBltVideoToBltBuffer:

+    return BltLibVideoToBltBufferEx (

+             BltBuffer,

+             SourceX,

+             SourceY,

+             DestinationX,

+             DestinationY,

+             Width,

+             Height,

+             Delta

+             );

+

+  case EfiBltVideoToVideo:

+    return BltLibVideoToVideo (

+             SourceX,

+             SourceY,

+             DestinationX,

+             DestinationY,

+             Width,

+             Height

+             );

+

+  case EfiBltVideoFill:

+    return BltLibVideoFill (

+             BltBuffer,

+             DestinationX,

+             DestinationY,

+             Width,

+             Height

+             );

+

+  case EfiBltBufferToVideo:

+    return BltLibBufferToVideoEx (

+             BltBuffer,

+             SourceX,

+             SourceY,

+             DestinationX,

+             DestinationY,

+             Width,

+             Height,

+             Delta

+             );

+  default:

+    return EFI_INVALID_PARAMETER;

+  }

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video Fill.

+

+  @param[in]  Color         Color to fill the region with

+  @param[in]  DestinationX  X location to start fill operation

+  @param[in]  DestinationY  Y location to start fill operation

+  @param[in]  Width         Width (in pixels) to fill

+  @param[in]  Height        Height to fill

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoFill (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *Color,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  UINTN                           DstY;

+  VOID                            *BltMemSrc;

+  VOID                            *BltMemDst;

+  UINTN                           X;

+  UINT8                           Uint8;

+  UINT32                          Uint32;

+  UINT64                          WideFill;

+  BOOLEAN                         UseWideFill;

+  BOOLEAN                         LineBufferReady;

+  UINTN                           Offset;

+  UINTN                           WidthInBytes;

+  UINTN                           SizeInBytes;

+

+  //

+  // BltBuffer to Video: Source is BltBuffer, destination is Video

+  //

+  if (DestinationY + Height > mBltLibHeight) {

+    DEBUG ((EFI_D_INFO, "VideoFill: Past screen (Y)\n"));

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (DestinationX + Width > mBltLibWidthInPixels) {

+    DEBUG ((EFI_D_INFO, "VideoFill: Past screen (X)\n"));

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Width == 0 || Height == 0) {

+    DEBUG ((EFI_D_INFO, "VideoFill: Width or Height is 0\n"));

+    return EFI_INVALID_PARAMETER;

+  }

+

+  WidthInBytes = Width * mBltLibBytesPerPixel;

+

+  Uint32 = *(UINT32*) Color;

+  WideFill =

+    (UINT32) (

+        (((Uint32 << mPixelShl[0]) >> mPixelShr[0]) & mPixelBitMasks.RedMask) |

+        (((Uint32 << mPixelShl[1]) >> mPixelShr[1]) & mPixelBitMasks.GreenMask) |

+        (((Uint32 << mPixelShl[2]) >> mPixelShr[2]) & mPixelBitMasks.BlueMask)

+      );

+  VDEBUG ((EFI_D_INFO, "VideoFill: color=0x%x, wide-fill=0x%x\n", Uint32, WideFill));

+

+  //

+  // If the size of the pixel data evenly divides the sizeof

+  // WideFill, then a wide fill operation can be used

+  //

+  UseWideFill = TRUE;

+  if ((sizeof (WideFill) % mBltLibBytesPerPixel) == 0) {

+    for (X = mBltLibBytesPerPixel; X < sizeof (WideFill); X++) {

+      ((UINT8*)&WideFill)[X] = ((UINT8*)&WideFill)[X % mBltLibBytesPerPixel];

+    }

+  } else {

+    //

+    // If all the bytes in the pixel are the same value, then use

+    // a wide fill operation.

+    //

+    for (

+      X = 1, Uint8 = ((UINT8*)&WideFill)[0];

+      X < mBltLibBytesPerPixel;

+      X++) {

+      if (Uint8 != ((UINT8*)&WideFill)[X]) {

+        UseWideFill = FALSE;

+        break;

+      }

+    }

+    if (UseWideFill) {

+      SetMem ((VOID*) &WideFill, sizeof (WideFill), Uint8);

+    }

+  }

+

+  if (UseWideFill && (DestinationX == 0) && (Width == mBltLibWidthInPixels)) {

+    VDEBUG ((EFI_D_INFO, "VideoFill (wide, one-shot)\n"));

+    Offset = DestinationY * mBltLibWidthInPixels;

+    Offset = mBltLibBytesPerPixel * Offset;

+    BltMemDst = (VOID*) (mBltLibFrameBuffer + Offset);

+    SizeInBytes = WidthInBytes * Height;

+    if (SizeInBytes >= 8) {

+      SetMem32 (BltMemDst, SizeInBytes & ~3, (UINT32) WideFill);

+      SizeInBytes = SizeInBytes & 3;

+    }

+    if (SizeInBytes > 0) {

+      SetMem (BltMemDst, SizeInBytes, (UINT8)(UINTN) WideFill);

+    }

+  } else {

+    LineBufferReady = FALSE;

+    for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {

+      Offset = (DstY * mBltLibWidthInPixels) + DestinationX;

+      Offset = mBltLibBytesPerPixel * Offset;

+      BltMemDst = (VOID*) (mBltLibFrameBuffer + Offset);

+

+      if (UseWideFill && (((UINTN) BltMemDst & 7) == 0)) {

+        VDEBUG ((EFI_D_INFO, "VideoFill (wide)\n"));

+        SizeInBytes = WidthInBytes;

+        if (SizeInBytes >= 8) {

+          SetMem64 (BltMemDst, SizeInBytes & ~7, WideFill);

+          SizeInBytes = SizeInBytes & 7;

+        }

+        if (SizeInBytes > 0) {

+          CopyMem (BltMemDst, (VOID*) &WideFill, SizeInBytes);

+        }

+      } else {

+        VDEBUG ((EFI_D_INFO, "VideoFill (not wide)\n"));

+        if (!LineBufferReady) {

+          CopyMem (mBltLibLineBuffer, &WideFill, mBltLibBytesPerPixel);

+          for (X = 1; X < Width; ) {

+            CopyMem(

+              (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)),

+              mBltLibLineBuffer,

+              MIN (X, Width - X) * mBltLibBytesPerPixel

+              );

+            X = X + MIN (X, Width - X);

+          }

+          BltMemSrc = (VOID *) mBltLibLineBuffer;

+          LineBufferReady = TRUE;

+        }

+        CopyMem (BltMemDst, mBltLibLineBuffer, WidthInBytes);

+      }

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation.

+

+  @param[out] BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToBltBuffer (

+  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  return BltLibVideoToBltBufferEx (

+           BltBuffer,

+           SourceX,

+           SourceY,

+           0,

+           0,

+           Width,

+           Height,

+           0

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation

+  with extended parameters.

+

+  @param[out] BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  DestinationX  X location within BltBuffer

+  @param[in]  DestinationY  Y location within BltBuffer

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+  @param[in]  Delta         Number of bytes in a row of BltBuffer

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToBltBufferEx (

+  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  UINTN                           DstY;

+  UINTN                           SrcY;

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *Blt;

+  VOID                            *BltMemSrc;

+  VOID                            *BltMemDst;

+  UINTN                           X;

+  UINT32                          Uint32;

+  UINTN                           Offset;

+  UINTN                           WidthInBytes;

+

+  //

+  // Video to BltBuffer: Source is Video, destination is BltBuffer

+  //

+  if (SourceY + Height > mBltLibHeight) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (SourceX + Width > mBltLibWidthInPixels) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Width == 0 || Height == 0) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // If Delta is zero, then the entire BltBuffer is being used, so Delta

+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,

+  // the number of bytes in each row can be computed.

+  //

+  if (Delta == 0) {

+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);

+  }

+

+  WidthInBytes = Width * mBltLibBytesPerPixel;

+

+  //

+  // Video to BltBuffer: Source is Video, destination is BltBuffer

+  //

+  for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {

+

+    Offset = (SrcY * mBltLibWidthInPixels) + SourceX;

+    Offset = mBltLibBytesPerPixel * Offset;

+    BltMemSrc = (VOID *) (mBltLibFrameBuffer + Offset);

+

+    if (mPixelFormat == PixelBlueGreenRedReserved8BitPerColor) {

+      BltMemDst =

+        (VOID *) (

+            (UINT8 *) BltBuffer +

+            (DstY * Delta) +

+            (DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))

+          );

+    } else {

+      BltMemDst = (VOID *) mBltLibLineBuffer;

+    }

+

+    CopyMem (BltMemDst, BltMemSrc, WidthInBytes);

+

+    if (mPixelFormat != PixelBlueGreenRedReserved8BitPerColor) {

+      for (X = 0; X < Width; X++) {

+        Blt         = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

+        Uint32 = *(UINT32*) (mBltLibLineBuffer + (X * mBltLibBytesPerPixel));

+        *(UINT32*) Blt =

+          (UINT32) (

+              (((Uint32 & mPixelBitMasks.RedMask)   >> mPixelShl[0]) << mPixelShr[0]) |

+              (((Uint32 & mPixelBitMasks.GreenMask) >> mPixelShl[1]) << mPixelShr[1]) |

+              (((Uint32 & mPixelBitMasks.BlueMask)  >> mPixelShl[2]) << mPixelShr[2])

+            );

+      }

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation.

+

+  @param[in]  BltBuffer     Output buffer for pixel color data

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibBufferToVideo (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  return BltLibBufferToVideoEx (

+           BltBuffer,

+           0,

+           0,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           0

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation

+  with extended parameters.

+

+  @param[in]  BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within BltBuffer

+  @param[in]  SourceY       Y location within BltBuffer

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+  @param[in]  Delta         Number of bytes in a row of BltBuffer

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibBufferToVideoEx (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  UINTN                           DstY;

+  UINTN                           SrcY;

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *Blt;

+  VOID                            *BltMemSrc;

+  VOID                            *BltMemDst;

+  UINTN                           X;

+  UINT32                          Uint32;

+  UINTN                           Offset;

+  UINTN                           WidthInBytes;

+

+  //

+  // BltBuffer to Video: Source is BltBuffer, destination is Video

+  //

+  if (DestinationY + Height > mBltLibHeight) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (DestinationX + Width > mBltLibWidthInPixels) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Width == 0 || Height == 0) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // If Delta is zero, then the entire BltBuffer is being used, so Delta

+  // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,

+  // the number of bytes in each row can be computed.

+  //

+  if (Delta == 0) {

+    Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);

+  }

+

+  WidthInBytes = Width * mBltLibBytesPerPixel;

+

+  for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {

+

+    Offset = (DstY * mBltLibWidthInPixels) + DestinationX;

+    Offset = mBltLibBytesPerPixel * Offset;

+    BltMemDst = (VOID*) (mBltLibFrameBuffer + Offset);

+

+    if (mPixelFormat == PixelBlueGreenRedReserved8BitPerColor) {

+      BltMemSrc = (VOID *) ((UINT8 *) BltBuffer + (SrcY * Delta));

+    } else {

+      for (X = 0; X < Width; X++) {

+        Blt =

+          (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (

+              (UINT8 *) BltBuffer +

+              (SrcY * Delta) +

+              ((SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))

+            );

+        Uint32 = *(UINT32*) Blt;

+        *(UINT32*) (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)) =

+          (UINT32) (

+              (((Uint32 << mPixelShl[0]) >> mPixelShr[0]) & mPixelBitMasks.RedMask) |

+              (((Uint32 << mPixelShl[1]) >> mPixelShr[1]) & mPixelBitMasks.GreenMask) |

+              (((Uint32 << mPixelShl[2]) >> mPixelShr[2]) & mPixelBitMasks.BlueMask)

+            );

+      }

+      BltMemSrc = (VOID *) mBltLibLineBuffer;

+    }

+

+    CopyMem (BltMemDst, BltMemSrc, WidthInBytes);

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Video operation

+

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToVideo (

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  VOID                            *BltMemSrc;

+  VOID                            *BltMemDst;

+  UINTN                           Offset;

+  UINTN                           WidthInBytes;

+  INTN                            LineStride;

+

+  //

+  // Video to Video: Source is Video, destination is Video

+  //

+  if (SourceY + Height > mBltLibHeight) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (SourceX + Width > mBltLibWidthInPixels) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (DestinationY + Height > mBltLibHeight) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (DestinationX + Width > mBltLibWidthInPixels) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (Width == 0 || Height == 0) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  WidthInBytes = Width * mBltLibBytesPerPixel;

+

+  Offset = (SourceY * mBltLibWidthInPixels) + SourceX;

+  Offset = mBltLibBytesPerPixel * Offset;

+  BltMemSrc = (VOID *) (mBltLibFrameBuffer + Offset);

+

+  Offset = (DestinationY * mBltLibWidthInPixels) + DestinationX;

+  Offset = mBltLibBytesPerPixel * Offset;

+  BltMemDst = (VOID *) (mBltLibFrameBuffer + Offset);

+

+  LineStride = mBltLibWidthInBytes;

+  if ((UINTN) BltMemDst > (UINTN) BltMemSrc) {

+    LineStride = -LineStride;

+  }

+

+  while (Height > 0) {

+    CopyMem (BltMemDst, BltMemSrc, WidthInBytes);

+

+    BltMemSrc = (VOID*) ((UINT8*) BltMemSrc + LineStride);

+    BltMemDst = (VOID*) ((UINT8*) BltMemDst + LineStride);

+    Height--;

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Returns the sizes related to the video device

+

+  @param[out]  Width   Width (in pixels)

+  @param[out]  Height  Height (in pixels)

+

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibGetSizes (

+  OUT UINTN                                 *Width,  OPTIONAL

+  OUT UINTN                                 *Height  OPTIONAL

+  )

+{

+  if (Width != NULL) {

+    *Width = mBltLibWidthInPixels;

+  }

+  if (Height != NULL) {

+    *Height = mBltLibHeight;

+  }

+

+  return EFI_SUCCESS;

+}

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf b/uefi/linaro-edk2/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
new file mode 100644
index 0000000..b94b52a
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
@@ -0,0 +1,35 @@
+## @file

+#  FrameBufferBltLib - Library to perform blt operations on a frame buffer.

+#

+#  Copyright (c) 2006 - 2011, 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.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = FrameBufferBltLib

+  FILE_GUID                      = 2a40f516-c852-4baa-b7a8-0e9ea090d659

+  MODULE_TYPE                    = BASE

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = BltLib

+

+[Sources.common]

+  FrameBufferBltLib.c

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OptionRomPkg/OptionRomPkg.dec

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Library/GopBltLib/GopBltLib.c b/uefi/linaro-edk2/OptionRomPkg/Library/GopBltLib/GopBltLib.c
new file mode 100644
index 0000000..1fb34fa
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Library/GopBltLib/GopBltLib.c
@@ -0,0 +1,455 @@
+/** @file

+  GopBltLib - Library to perform blt using the UEFI Graphics Output Protocol.

+

+  Copyright (c) 2007 - 2011, 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.

+

+**/

+

+#include "PiDxe.h"

+

+#include <Protocol/GraphicsOutput.h>

+

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/BltLib.h>

+#include <Library/DebugLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+

+EFI_GRAPHICS_OUTPUT_PROTOCOL         *mGop = NULL;

+

+

+/**

+  Configure the FrameBufferLib instance

+

+  @param[in] FrameBuffer      Pointer to the start of the frame buffer

+  @param[in] FrameBufferInfo  Describes the frame buffer characteristics

+

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter

+  @retval  EFI_UNSUPPORTED - The BltLib does not support this configuration

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibConfigure (

+  IN  VOID                                 *FrameBuffer,

+  IN  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo

+  )

+{

+  EFI_STATUS                      Status;

+  EFI_HANDLE                      *HandleBuffer;

+  UINTN                           HandleCount;

+  UINTN                           Index;

+  EFI_GRAPHICS_OUTPUT_PROTOCOL    *Gop;

+

+  Status = gBS->LocateHandleBuffer (

+                  ByProtocol,

+                  &gEfiGraphicsOutputProtocolGuid,

+                  NULL,

+                  &HandleCount,

+                  &HandleBuffer

+                  );

+  if (!EFI_ERROR (Status)) {

+    for (Index = 0; Index < HandleCount; Index++) {

+      Status = gBS->HandleProtocol (

+                      HandleBuffer[Index],

+                      &gEfiGraphicsOutputProtocolGuid,

+                      (VOID*) &Gop

+                      );

+      if (!EFI_ERROR (Status) &&

+          (FrameBuffer == (VOID*)(UINTN) Gop->Mode->FrameBufferBase)) {

+        mGop = Gop;

+        FreePool (HandleBuffer);

+        return EFI_SUCCESS;

+      }

+    }

+

+    FreePool (HandleBuffer);

+  }

+

+  return EFI_UNSUPPORTED;

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt operation.

+

+  @param[in,out] BltBuffer     - The data to transfer to screen

+  @param[in]     BltOperation  - The operation to perform

+  @param[in]     SourceX       - The X coordinate of the source for BltOperation

+  @param[in]     SourceY       - The Y coordinate of the source for BltOperation

+  @param[in]     DestinationX  - The X coordinate of the destination for BltOperation

+  @param[in]     DestinationY  - The Y coordinate of the destination for BltOperation

+  @param[in]     Width         - The width of a rectangle in the blt rectangle in pixels

+  @param[in]     Height        - The height of a rectangle in the blt rectangle in pixels

+  @param[in]     Delta         - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.

+                                 If a Delta of 0 is used, the entire BltBuffer will be operated on.

+                                 If a subrectangle of the BltBuffer is used, then Delta represents

+                                 the number of bytes in a row of the BltBuffer.

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+InternalGopBltCommon (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer, OPTIONAL

+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION     BltOperation,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  if (mGop == NULL) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  return mGop->Blt (

+                 mGop,

+                 BltBuffer,

+                 BltOperation,

+                 SourceX,

+                 SourceY,

+                 DestinationX,

+                 DestinationY,

+                 Width,

+                 Height,

+                 Delta

+                 );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt operation.

+

+  @param[in,out] BltBuffer     - The data to transfer to screen

+  @param[in]     BltOperation  - The operation to perform

+  @param[in]     SourceX       - The X coordinate of the source for BltOperation

+  @param[in]     SourceY       - The Y coordinate of the source for BltOperation

+  @param[in]     DestinationX  - The X coordinate of the destination for BltOperation

+  @param[in]     DestinationY  - The Y coordinate of the destination for BltOperation

+  @param[in]     Width         - The width of a rectangle in the blt rectangle in pixels

+  @param[in]     Height        - The height of a rectangle in the blt rectangle in pixels

+  @param[in]     Delta         - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.

+                                 If a Delta of 0 is used, the entire BltBuffer will be operated on.

+                                 If a subrectangle of the BltBuffer is used, then Delta represents

+                                 the number of bytes in a row of the BltBuffer.

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - Blt operation success

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibGopBlt (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer, OPTIONAL

+  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION     BltOperation,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  return InternalGopBltCommon (

+           BltBuffer,

+           BltOperation,

+           SourceX,

+           SourceY,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           Delta

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video Fill.

+

+  @param[in]  Color         Color to fill the region with

+  @param[in]  DestinationX  X location to start fill operation

+  @param[in]  DestinationY  Y location to start fill operation

+  @param[in]  Width         Width (in pixels) to fill

+  @param[in]  Height        Height to fill

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoFill (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *Color,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  return InternalGopBltCommon (

+           Color,

+           EfiBltVideoFill,

+           0,

+           0,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           0

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation.

+

+  @param[out] BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToBltBuffer (

+  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  return InternalGopBltCommon (

+           BltBuffer,

+           EfiBltVideoToBltBuffer,

+           SourceX,

+           SourceY,

+           0,

+           0,

+           Width,

+           Height,

+           0

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation

+  with extended parameters.

+

+  @param[out] BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  DestinationX  X location within BltBuffer

+  @param[in]  DestinationY  Y location within BltBuffer

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+  @param[in]  Delta         Number of bytes in a row of BltBuffer

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToBltBufferEx (

+  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  return InternalGopBltCommon (

+           BltBuffer,

+           EfiBltVideoToBltBuffer,

+           SourceX,

+           SourceY,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           Delta

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation.

+

+  @param[in]  BltBuffer     Output buffer for pixel color data

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibBufferToVideo (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  return InternalGopBltCommon (

+           BltBuffer,

+           EfiBltBufferToVideo,

+           0,

+           0,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           0

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation

+  with extended parameters.

+

+  @param[in]  BltBuffer     Output buffer for pixel color data

+  @param[in]  SourceX       X location within BltBuffer

+  @param[in]  SourceY       Y location within BltBuffer

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+  @param[in]  Delta         Number of bytes in a row of BltBuffer

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibBufferToVideoEx (

+  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL         *BltBuffer,

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height,

+  IN  UINTN                                 Delta

+  )

+{

+  return InternalGopBltCommon (

+           BltBuffer,

+           EfiBltBufferToVideo,

+           SourceX,

+           SourceY,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           Delta

+           );

+}

+

+

+/**

+  Performs a UEFI Graphics Output Protocol Blt Video to Video operation

+

+  @param[in]  SourceX       X location within video

+  @param[in]  SourceY       Y location within video

+  @param[in]  DestinationX  X location within video

+  @param[in]  DestinationY  Y location within video

+  @param[in]  Width         Width (in pixels)

+  @param[in]  Height        Height

+

+  @retval  EFI_DEVICE_ERROR - A hardware error occured

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibVideoToVideo (

+  IN  UINTN                                 SourceX,

+  IN  UINTN                                 SourceY,

+  IN  UINTN                                 DestinationX,

+  IN  UINTN                                 DestinationY,

+  IN  UINTN                                 Width,

+  IN  UINTN                                 Height

+  )

+{

+  return InternalGopBltCommon (

+           NULL,

+           EfiBltVideoToVideo,

+           SourceX,

+           SourceY,

+           DestinationX,

+           DestinationY,

+           Width,

+           Height,

+           0

+           );

+}

+

+/**

+  Returns the sizes related to the video device

+

+  @param[out]  Width   Width (in pixels)

+  @param[out]  Height  Height (in pixels)

+

+  @retval  EFI_INVALID_PARAMETER - Invalid parameter passed in

+  @retval  EFI_SUCCESS - The sizes were returned

+

+**/

+EFI_STATUS

+EFIAPI

+BltLibGetSizes (

+  OUT UINTN                                 *Width,  OPTIONAL

+  OUT UINTN                                 *Height  OPTIONAL

+  )

+{

+  ASSERT (mGop != NULL);

+

+  if (Width != NULL) {

+    *Width = mGop->Mode->Info->HorizontalResolution;

+  }

+  if (Height != NULL) {

+    *Height = mGop->Mode->Info->VerticalResolution;

+  }

+

+  return EFI_SUCCESS;

+}

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/Library/GopBltLib/GopBltLib.inf b/uefi/linaro-edk2/OptionRomPkg/Library/GopBltLib/GopBltLib.inf
new file mode 100644
index 0000000..8a09696
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/Library/GopBltLib/GopBltLib.inf
@@ -0,0 +1,37 @@
+## @file

+#  GopBltLib - Library to perform blt using the UEFI Graphics Output Protocol.

+#

+#  Copyright (c) 2006 - 2011, 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.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = GopBltLib

+  FILE_GUID                      = b75b91f0-a0b4-42fe-ba62-849027999b39

+  MODULE_TYPE                    = BASE

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = BltLib

+

+[Sources.common]

+  GopBltLib.c

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  MemoryAllocationLib

+  UefiBootServicesTableLib

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OptionRomPkg/OptionRomPkg.dec

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/License.txt b/uefi/linaro-edk2/OptionRomPkg/License.txt
new file mode 100644
index 0000000..be68999
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/License.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2012, Intel Corporation. All rights reserved.

+

+Redistribution and use in source and binary forms, with or without

+modification, are permitted provided that the following conditions

+are met:

+

+* Redistributions of source code must retain the above copyright

+  notice, this list of conditions and the following disclaimer.

+* Redistributions in binary form must reproduce the above copyright

+  notice, this list of conditions and the following disclaimer in

+  the documentation and/or other materials provided with the

+  distribution.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,

+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN

+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

+POSSIBILITY OF SUCH DAMAGE.

diff --git a/uefi/linaro-edk2/OptionRomPkg/OptionRomPkg.dec b/uefi/linaro-edk2/OptionRomPkg/OptionRomPkg.dec
new file mode 100644
index 0000000..ea4d57b
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/OptionRomPkg.dec
@@ -0,0 +1,47 @@
+## @file

+# Option Rom Package Reference Implementations.

+#

+# This package is designed to interoperate with the EDK II open source project

+# at http://www.tianocore.org, and this package is required to build PCI compliant

+# Option ROM image for all CPU architectures, including EBC target.

+# A single driver can support mixes of EFI 1.1, UEFI 2.0 and UEFI 2.1.

+#

+# Copyright (c) 2007 - 2010, 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.

+#

+##

+

+[Defines]

+  DEC_SPECIFICATION              = 0x00010005

+  PACKAGE_NAME                   = OptionRomPkg

+  PACKAGE_GUID                   = AA3865E8-7F30-4f59-8696-99F560101852

+  PACKAGE_VERSION                = 0.1

+

+[Includes]

+  Include

+

+[LibraryClasses]

+  ##  @libraryclass  Provides an interface for performing UEFI Graphics

+  ##                 Output Protocol Video blt operations

+  ##

+  BltLib|Include/Library/BltLib.h

+

+[Guids]

+  gOptionRomPkgTokenSpaceGuid = { 0x1e43298f, 0x3478, 0x41a7, { 0xb5, 0x77, 0x86, 0x6, 0x46, 0x35, 0xc7, 0x28 } }

+

+[PcdsFeatureFlag]

+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN|0x00010001

+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEAN|0x00010002

+  gOptionRomPkgTokenSpaceGuid.PcdSupportGop|TRUE|BOOLEAN|0x00010004

+  gOptionRomPkgTokenSpaceGuid.PcdSupportUga|TRUE|BOOLEAN|0x00010005

+

+[PcdsFixedAtBuild, PcdsPatchableInModule]

+  gOptionRomPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion|0x0002000a|UINT32|0x00010003

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/OptionRomPkg.dsc b/uefi/linaro-edk2/OptionRomPkg/OptionRomPkg.dsc
new file mode 100644
index 0000000..03592f8
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/OptionRomPkg.dsc
@@ -0,0 +1,110 @@
+## @file

+# Option Rom Package build validation file for All Architectures.

+#

+# This package is designed to interoperate with the EDK II open source project

+# at http://www.tianocore.org, and this package is required to build PCI compliant

+# Option ROM image for all CPU architectures, including EBC target.

+# A single driver can support mixes of EFI 1.1, UEFI 2.0 and UEFI 2.1.

+#

+# Copyright (c) 2007 - 2013, 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.

+#

+##

+

+################################################################################

+#

+# Defines Section - statements that will be processed to create a Makefile.

+#

+################################################################################

+[Defines]

+  PLATFORM_NAME                  = OptionRomPkg

+  PLATFORM_GUID                  = C7B25F37-B1F4-4c46-99CB-3EA7DCF5FCDC

+  PLATFORM_VERSION               = 0.1

+  DSC_SPECIFICATION              = 0x00010005

+  OUTPUT_DIRECTORY               = Build/OptionRomPkg

+  SUPPORTED_ARCHITECTURES        = IA32|IPF|X64|EBC

+  BUILD_TARGETS                  = DEBUG|RELEASE

+  SKUID_IDENTIFIER               = DEFAULT

+

+################################################################################

+#

+# SKU Identification section - list of all SKU IDs supported by this

+#                              Platform.

+#

+################################################################################

+[SkuIds]

+  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.

+

+[LibraryClasses]

+  DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf

+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf  

+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf

+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf

+  BltLib|OptionRomPkg/Library/GopBltLib/GopBltLib.inf

+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf

+  TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf

+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf

+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf

+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf

+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf

+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf

+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf

+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf

+  UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf

+  UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf

+

+################################################################################

+#

+# Pcd Section - list of all EDK II PCD Entries defined by this Platform

+#

+################################################################################

+[PcdsFeatureFlag]

+  gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE

+  gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE

+

+[PcdsFixedAtBuild]

+  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x27

+  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000042

+  gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|0x0

+  gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|0x0

+  gOptionRomPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion|0x0002000a # EFI_2_10_SYSTEM_TABLE_REVISION

+

+###################################################################################################

+#

+# Components Section - list of the modules and components that will be processed by compilation

+#                      tools and the EDK II tools to generate PE32/PE32+/Coff image files.

+#

+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed

+#       into firmware volume images. This section is just a list of modules to compile from

+#       source into UEFI-compliant binaries.

+#       It is the FDF file that contains information on combining binary files into firmware

+#       volume images, whose concept is beyond UEFI and is described in PI specification.

+#       Binary modules do not need to be listed in this section, as they should be

+#       specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),

+#       Logo (Logo.bmp), and etc.

+#       There may also be modules listed in this section that are not required in the FDF file,

+#       When a module listed here is excluded from FDF file, then UEFI-compliant binary will be

+#       generated for it, but the binary will not be put into any firmware volume.

+#

+###################################################################################################

+

+[Components]

+  OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf

+  OptionRomPkg/Library/GopBltLib/GopBltLib.inf

+

+  OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf

+  OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf

+  OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf

+  OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf

+

+[Components.IA32, Components.X64, Components.IPF]

+  OptionRomPkg/Application/BltLibSample/BltLibSample.inf

diff --git a/uefi/linaro-edk2/OptionRomPkg/ReadMe.txt b/uefi/linaro-edk2/OptionRomPkg/ReadMe.txt
new file mode 100644
index 0000000..5eb81cb
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/ReadMe.txt
@@ -0,0 +1,19 @@
+AtapiPassThru:

+  For now, AtapiPassThru driver in this package is to test Scsi Bus support:

+  ScsiBus driver should support both/either ScsiPassThru and ExtScsiPassThru

+  installed on a controller handle.

+   

+  AtapiPassThru driver in this package can selectively produce ScsiPassThru

+  and/or ExtScsiPassThru protocol based on feature flags of PcdSupportScsiPassThru

+  and PcdSupportExtScsiPassThru.

+

+CirrusLogic5430:

+  Sample implementation of UGA Draw or Graphics Output Protocol for the Cirrus

+  Logic 5430 family of PCI video card. It provides reference code for the GOP/UGA,

+  Component Name (2), EFI driver supported Verison protocol.

+

+Build Validation:

+MYTOOLS(VS2005) IA32 X64 IPF EBC

+ICC             IA32 X64 IPF

+CYGWINGCC       IA32 X64

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/ComponentName.c b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/ComponentName.c
new file mode 100644
index 0000000..405c6fb
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/ComponentName.c
@@ -0,0 +1,365 @@
+/** @file

+    UEFI Component Name(2) protocol implementation for EFI UNDI32 driver.

+

+Copyright (c) 2012, 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.

+

+**/

+

+

+#include "Undi32.h"

+

+//

+// EFI Component Name Functions

+//

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UndiComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UndiComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  );

+

+

+//

+// EFI Component Name Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gUndiComponentName = {

+  UndiComponentNameGetDriverName,

+  UndiComponentNameGetControllerName,

+  "eng"

+};

+

+//

+// EFI Component Name 2 Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUndiComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UndiComponentNameGetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UndiComponentNameGetControllerName,

+  "en"

+};

+

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUndiDriverNameTable[] = {

+  {

+    "eng;en",

+    L"UNDI32 Driver"

+  },

+  {

+    NULL,

+    NULL

+  }

+};

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUndiControllerNameTable[] = {

+  {

+    "eng;en",

+    L"UNDI32 Controller"

+  },

+  {

+    NULL,

+    NULL

+  }

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UndiComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  )

+{

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mUndiDriverNameTable,

+           DriverName,

+           (BOOLEAN)(This == &gUndiComponentName)

+           );

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+  Currently not implemented.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+UndiComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  )

+{

+  EFI_STATUS                                Status;

+  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;

+

+  if (ChildHandle != NULL) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Make sure this driver is currently managing ControllHandle

+  //

+  Status = EfiTestManagedDevice (

+             ControllerHandle,

+             gUndiDriverBinding.DriverBindingHandle,

+             &gEfiPciIoProtocolGuid

+             );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // Retrieve an instance of a produced protocol from ControllerHandle

+  //

+  Status = gBS->OpenProtocol (

+                   ControllerHandle,

+                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,

+                  (VOID **)&Nii,

+                   NULL,

+                   NULL,

+                   EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                   );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mUndiControllerNameTable,

+           ControllerName,

+           (BOOLEAN)(This == &gUndiComponentName)

+           );

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Decode.c b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Decode.c
new file mode 100644
index 0000000..5f85347
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Decode.c
@@ -0,0 +1,1521 @@
+/** @file

+  Provides the basic UNID functions.

+

+Copyright (c) 2006 - 2013, 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.

+

+**/

+

+#include "Undi32.h"

+

+//

+// Global variables defined in this file

+//

+UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] = { \

+  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, (UINT16)(ANY_STATE),UNDI_GetState },\

+  {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,0,(UINT16)(ANY_STATE),UNDI_Start },\

+  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UNDI_Stop },\

+  {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STARTED, UNDI_GetInitInfo },\

+  {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_STARTED, UNDI_GetConfigInfo },\

+  {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),MUST_BE_STARTED,UNDI_Initialize },\

+  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Reset },\

+  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, MUST_BE_INITIALIZED,UNDI_Shutdown },\

+  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Interrupt },\

+  {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_RecFilter },\

+  {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_StnAddr },\

+  {PXE_CPBSIZE_NOT_USED, (UINT16)(DONT_CHECK), (UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Statistics },\

+  {sizeof(PXE_CPB_MCAST_IP_TO_MAC),sizeof(PXE_DB_MCAST_IP_TO_MAC), (UINT16)(DONT_CHECK),MUST_BE_INITIALIZED, UNDI_ip2mac },\

+  {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_NVData },\

+  {PXE_CPBSIZE_NOT_USED,(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Status },\

+  {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_FillHeader },\

+  {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Transmit },\

+  {sizeof(PXE_CPB_RECEIVE),sizeof(PXE_DB_RECEIVE),0,MUST_BE_INITIALIZED, UNDI_Receive } \

+};

+

+//

+// end of global variables

+//

+

+

+/**

+  This routine determines the operational state of the UNDI.  It updates the state flags in the

+  Command Descriptor Block based on information derived from the AdapterInfo instance data.

+  To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of

+  the command execution.

+  The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command

+  has successfully completed.

+  Keep in mind the AdapterInfo->State is the active state of the adapter (based on software

+  interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected

+  to the caller of the UNDI API.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_GetState (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->State);

+  return ;

+}

+

+

+/**

+  This routine is used to change the operational state of the UNDI from stopped to started.

+  It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise

+  the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the

+  UNDI as having already been started.

+  This routine is modified to reflect the undi 1.1 specification changes. The

+  changes in the spec are mainly in the callback routines, the new spec adds

+  3 more callbacks and a unique id.

+  Since this UNDI supports both old and new undi specifications,

+  The NIC's data structure is filled in with the callback routines (depending

+  on the version) pointed to in the caller's CpbPtr.  This seeds the Delay,

+  Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem

+  and Sync_Mem routines and a unique id variable for the new version.

+  This is the function which an external entity (SNP, O/S, etc) would call

+  to provide it's I/O abstraction to the UNDI.

+  It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Start (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_CPB_START_30  *CpbPtr;

+  PXE_CPB_START_31  *CpbPtr_31;

+

+  //

+  // check if it is already started.

+  //

+  if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_STOPPED) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_ALREADY_STARTED;

+    return ;

+  }

+

+  if (CdbPtr->CPBsize != sizeof(PXE_CPB_START_30) &&

+      CdbPtr->CPBsize != sizeof(PXE_CPB_START_31)) {

+

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  CpbPtr    = (PXE_CPB_START_30 *) (UINTN) (CdbPtr->CPBaddr);

+  CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);

+

+  if (AdapterInfo->VersionFlag == 0x30) {

+    AdapterInfo->Delay_30     = (bsptr_30) (UINTN) CpbPtr->Delay;

+    AdapterInfo->Virt2Phys_30 = (virtphys_30) (UINTN) CpbPtr->Virt2Phys;

+    AdapterInfo->Block_30     = (block_30) (UINTN) CpbPtr->Block;

+    //

+    // patch for old buggy 3.0 code:

+    // In EFI1.0 undi used to provide the full (absolute) I/O address to the

+    // i/o calls and SNP used to provide a callback that used GlobalIoFncs and

+    // everything worked fine! In EFI 1.1, UNDI is not using the full

+    // i/o or memory address to access the device, The base values for the i/o

+    // and memory address is abstracted by the device specific PciIoFncs and

+    // UNDI only uses the offset values. Since UNDI3.0 cannot provide any

+    // identification to SNP, SNP cannot use nic specific PciIoFncs callback!

+    //

+    // To fix this and make undi3.0 work with SNP in EFI1.1 we

+    // use a TmpMemIo function that is defined in init.c

+    // This breaks the runtime driver feature of undi, but what to do

+    // if we have to provide the 3.0 compatibility (including the 3.0 bugs)

+    //

+    // This TmpMemIo function also takes a UniqueId parameter

+    // (as in undi3.1 design) and so initialize the UniqueId as well here

+    // Note: AdapterInfo->Mem_Io_30 is just filled for consistency with other

+    // parameters but never used, we only use Mem_Io field in the In/Out routines

+    // inside e100b.c.

+    //

+    AdapterInfo->Mem_Io_30  = (mem_io_30) (UINTN) CpbPtr->Mem_IO;

+    AdapterInfo->Mem_Io     = (mem_io) (UINTN) TmpMemIo;

+    AdapterInfo->Unique_ID  = (UINT64) (UINTN) AdapterInfo;

+

+  } else {

+    AdapterInfo->Delay      = (bsptr) (UINTN) CpbPtr_31->Delay;

+    AdapterInfo->Virt2Phys  = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;

+    AdapterInfo->Block      = (block) (UINTN) CpbPtr_31->Block;

+    AdapterInfo->Mem_Io     = (mem_io) (UINTN) CpbPtr_31->Mem_IO;

+

+    AdapterInfo->Map_Mem    = (map_mem) (UINTN) CpbPtr_31->Map_Mem;

+    AdapterInfo->UnMap_Mem  = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;

+    AdapterInfo->Sync_Mem   = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;

+    AdapterInfo->Unique_ID  = CpbPtr_31->Unique_ID;

+  }

+

+  AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;

+

+  return ;

+}

+

+

+/**

+  This routine is used to change the operational state of the UNDI from started to stopped.

+  It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise

+  the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the

+  UNDI as having already not been shut down.

+  The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..

+  It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Stop (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_NOT_SHUTDOWN;

+    return ;

+  }

+

+  AdapterInfo->Delay_30     = 0;

+  AdapterInfo->Virt2Phys_30 = 0;

+  AdapterInfo->Block_30     = 0;

+

+  AdapterInfo->Delay        = 0;

+  AdapterInfo->Virt2Phys    = 0;

+  AdapterInfo->Block        = 0;

+

+  AdapterInfo->Map_Mem      = 0;

+  AdapterInfo->UnMap_Mem    = 0;

+  AdapterInfo->Sync_Mem     = 0;

+

+  AdapterInfo->State        = PXE_STATFLAGS_GET_STATE_STOPPED;

+

+  return ;

+}

+

+

+/**

+  This routine is used to retrieve the initialization information that is needed by drivers and

+  applications to initialize the UNDI.  This will fill in data in the Data Block structure that is

+  pointed to by the caller's CdbPtr->DBaddr.  The fields filled in are as follows:

+  MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,

+  MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.

+  In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection.  (APRIORI knowledge)

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_GetInitInfo (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_DB_GET_INIT_INFO  *DbPtr;

+

+  DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);

+

+  DbPtr->MemoryRequired = MEMORY_NEEDED;

+  DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;

+  DbPtr->LinkSpeeds[0] = 10;

+  DbPtr->LinkSpeeds[1] = 100;

+  DbPtr->LinkSpeeds[2] = DbPtr->LinkSpeeds[3] = 0;

+  DbPtr->NvCount = MAX_EEPROM_LEN;

+  DbPtr->NvWidth = 4;

+  DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;

+  DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;

+  DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;

+

+  DbPtr->TxBufCnt = TX_BUFFER_COUNT;

+  DbPtr->TxBufSize = (UINT16) sizeof (TxCB);

+  DbPtr->RxBufCnt = RX_BUFFER_COUNT;

+  DbPtr->RxBufSize = (UINT16) sizeof (RxFD);

+

+  DbPtr->IFtype = PXE_IFTYPE_ETHERNET;

+  DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED |

+                  PXE_DUPLEX_FORCE_FULL_SUPPORTED;

+  DbPtr->SupportedLoopBackModes = PXE_LOOPBACK_INTERNAL_SUPPORTED |

+                    PXE_LOOPBACK_EXTERNAL_SUPPORTED;

+

+  CdbPtr->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |

+                        PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED);

+  return ;

+}

+

+

+/**

+  This routine is used to retrieve the configuration information about the NIC being controlled by

+  this driver.  This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.

+  The fields filled in are as follows:

+  DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.

+  In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_GetConfigInfo (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16                  Index;

+  PXE_DB_GET_CONFIG_INFO  *DbPtr;

+

+  DbPtr               = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);

+

+  DbPtr->pci.BusType  = PXE_BUSTYPE_PCI;

+  DbPtr->pci.Bus      = AdapterInfo->Bus;

+  DbPtr->pci.Device   = AdapterInfo->Device;

+  DbPtr->pci.Function = AdapterInfo->Function;

+

+  for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {

+    DbPtr->pci.Config.Dword[Index] = AdapterInfo->Config[Index];

+  }

+

+  return ;

+}

+

+

+/**

+  This routine resets the network adapter and initializes the UNDI using the parameters supplied in

+  the CPB.  This command must be issued before the network adapter can be setup to transmit and

+  receive packets.

+  Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block

+  of non-swappable memory may need to be allocated.  The address of this memory must be passed to

+  UNDI during the Initialize in the CPB.  This memory is used primarily for transmit and receive buffers.

+  The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with information

+  that was passed in the CPB and the NIC is initialized.

+  If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED

+  Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of

+  the UNDI is now initialized.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Initialize (

+  IN  PXE_CDB       *CdbPtr,

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_CPB_INITIALIZE  *CpbPtr;

+

+  if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&

+      (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  //

+  // check if it is already initialized

+  //

+  if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_ALREADY_INITIALIZED;

+    return ;

+  }

+

+  CpbPtr  = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;

+

+  if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;

+    return ;

+  }

+

+  //

+  // default behaviour is to detect the cable, if the 3rd param is 1,

+  // do not do that

+  //

+  AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);

+  AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed;

+  AdapterInfo->DuplexReq    = CpbPtr->DuplexMode;

+  AdapterInfo->LoopBack     = CpbPtr->LoopBackMode;

+  AdapterInfo->MemoryPtr    = CpbPtr->MemoryAddr;

+  AdapterInfo->MemoryLength = CpbPtr->MemoryLength;

+

+  CdbPtr->StatCode          = (PXE_STATCODE) E100bInit (AdapterInfo);

+

+  if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+  } else {

+    AdapterInfo->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;

+  }

+

+  return ;

+}

+

+

+/**

+  This routine resets the network adapter and initializes the UNDI using the parameters supplied in

+  the CPB.  The transmit and receive queues are emptied and any pending interrupts are cleared.

+  If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Reset (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&

+      CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&

+      CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS ) {

+

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  CdbPtr->StatCode = (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags);

+

+  if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+  }

+}

+

+

+/**

+  This routine resets the network adapter and leaves it in a safe state for another driver to

+  initialize.  Any pending transmits or receives are lost.  Receive filters and external

+  interrupt enables are disabled.  Once the UNDI has been shutdown, it can then be stopped

+  or initialized again.

+  If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED

+  Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing the state of

+  the NIC as being started.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Shutdown (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  //

+  // do the shutdown stuff here

+  //

+  CdbPtr->StatCode = (UINT16) E100bShutdown (AdapterInfo);

+

+  if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+  } else {

+    AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;

+  }

+

+  return ;

+}

+

+

+/**

+  This routine can be used to read and/or change the current external interrupt enable

+  settings.  Disabling an external interrupt enable prevents and external (hardware)

+  interrupt from being signaled by the network device.  Internally the interrupt events

+  can still be polled by using the UNDI_GetState command.

+  The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Interrupt (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT8 IntMask;

+

+  IntMask = (UINT8)(UINTN)(CdbPtr->OpFlags & (PXE_OPFLAGS_INTERRUPT_RECEIVE |

+                                              PXE_OPFLAGS_INTERRUPT_TRANSMIT |

+                                              PXE_OPFLAGS_INTERRUPT_COMMAND |

+                                              PXE_OPFLAGS_INTERRUPT_SOFTWARE));

+

+  switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {

+  case PXE_OPFLAGS_INTERRUPT_READ:

+    break;

+

+  case PXE_OPFLAGS_INTERRUPT_ENABLE:

+    if (IntMask == 0) {

+      CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+      CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+      return ;

+    }

+

+    AdapterInfo->int_mask = IntMask;

+    E100bSetInterruptState (AdapterInfo);

+    break;

+

+  case PXE_OPFLAGS_INTERRUPT_DISABLE:

+    if (IntMask != 0) {

+      AdapterInfo->int_mask = (UINT16) (AdapterInfo->int_mask & ~(IntMask));

+      E100bSetInterruptState (AdapterInfo);

+      break;

+    }

+

+  //

+  // else fall thru.

+  //

+  default:

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {

+    CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;

+

+  }

+

+  if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {

+    CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;

+

+  }

+

+  if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {

+    CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;

+

+  }

+

+  return ;

+}

+

+

+/**

+  This routine is used to read and change receive filters and, if supported, read

+  and change multicast MAC address filter list.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_RecFilter (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16                  NewFilter;

+  UINT16                  OpFlags;

+  PXE_DB_RECEIVE_FILTERS  *DbPtr;

+  UINT8                   *MacAddr;

+  UINTN                   MacCount;

+  UINT16                  Index;

+  UINT16                  copy_len;

+  UINT8                   *ptr1;

+  UINT8                   *ptr2;

+  BOOLEAN                 InvalidMacAddr;

+    

+  OpFlags   = CdbPtr->OpFlags;

+  NewFilter = (UINT16) (OpFlags & 0x1F);

+

+  switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {

+  case PXE_OPFLAGS_RECEIVE_FILTER_READ:

+

+    //

+    // not expecting a cpb, not expecting any filter bits

+    //

+    if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {

+      goto BadCdb;

+

+    }

+

+    if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {

+      goto JustRead;

+

+    }

+

+    NewFilter = (UINT16) (NewFilter | AdapterInfo->Rx_Filter);

+    //

+    // all other flags are ignored except mcast_reset

+    //

+    break;

+

+  case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:

+    //

+    // there should be atleast one other filter bit set.

+    //

+    if (NewFilter == 0) {

+      //

+      // nothing to enable

+      //

+      goto BadCdb;

+    }

+

+    if (CdbPtr->CPBsize != 0) {

+      //

+      // this must be a multicast address list!

+      // don't accept the list unless selective_mcast is set

+      // don't accept confusing mcast settings with this

+      //

+      if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||

+          ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||

+          ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||

+          ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) {

+        goto BadCdb;

+      }

+

+      MacAddr   = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr));

+      MacCount  = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR);

+

+      //

+      // The format of Ethernet multicast address for IPv6 is defined in RFC2464,

+      // for IPv4 is defined in RFC1112. Check whether the address is valid.

+      //

+      InvalidMacAddr = FALSE;

+      

+      for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) {

+        if (MacAddr[0] == 0x01) {

+          //

+          // This multicast MAC address is mapped from IPv4 address.

+          //

+          if (MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) {

+            InvalidMacAddr = TRUE;

+          }          

+        } else if (MacAddr[0] == 0x33) {

+          //

+          // This multicast MAC address is mapped from IPv6 address.

+          //

+          if (MacAddr[1] != 0x33) {

+            InvalidMacAddr = TRUE;

+          }

+        } else {

+          InvalidMacAddr = TRUE;

+        }

+

+        if (InvalidMacAddr) {

+          CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+          CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;

+          return ;

+        }

+      }

+    }

+

+    //

+    // check selective mcast case enable case

+    //

+    if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {

+      if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||

+          ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) {

+        goto BadCdb;

+

+      }

+      //

+      // if no cpb, make sure we have an old list

+      //

+      if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) {

+        goto BadCdb;

+      }

+    }

+    //

+    // if you want to enable anything, you got to have unicast

+    // and you have what you already enabled!

+    //

+    NewFilter = (UINT16) (NewFilter | (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter));

+

+    break;

+

+  case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:

+

+    //

+    // mcast list not expected, i.e. no cpb here!

+    //

+    if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {

+      goto BadCdb;

+    }

+

+    NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter);

+

+    break;

+

+  default:

+    goto BadCdb;

+  }

+

+  if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {

+    AdapterInfo->mcast_list.list_len = 0;

+    NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);

+  }

+

+  E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);

+

+JustRead:

+  //

+  // give the current mcast list

+  //

+  if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) {

+    //

+    // copy the mc list to db

+    //

+

+    DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;

+    ptr1  = (UINT8 *) (&DbPtr->MCastList[0]);

+

+    //

+    // DbPtr->mc_count = AdapterInfo->mcast_list.list_len;

+    //

+    copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH);

+

+    if (copy_len > CdbPtr->DBsize) {

+      copy_len = CdbPtr->DBsize;

+

+    }

+

+    ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]);

+    for (Index = 0; Index < copy_len; Index++) {

+      ptr1[Index] = ptr2[Index];

+    }

+  }

+  //

+  // give the stat flags here

+  //

+  if (AdapterInfo->Receive_Started) {

+    CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->Rx_Filter);

+

+  }

+

+  return ;

+

+BadCdb:

+  CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+  CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+}

+

+

+/**

+  This routine is used to get the current station and broadcast MAC addresses, and to change the

+  current station MAC address.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_StnAddr (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_CPB_STATION_ADDRESS *CpbPtr;

+  PXE_DB_STATION_ADDRESS  *DbPtr;

+  UINT16                  Index;

+

+  if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {

+    //

+    // configure the permanent address.

+    // change the AdapterInfo->CurrentNodeAddress field.

+    //

+    if (CompareMem (

+          &AdapterInfo->CurrentNodeAddress[0],

+          &AdapterInfo->PermNodeAddress[0],

+          PXE_MAC_LENGTH

+          ) != 0) {

+      for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {

+        AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];

+      }

+

+      E100bSetupIAAddr (AdapterInfo);

+    }

+  }

+

+  if (CdbPtr->CPBaddr != (UINT64) 0) {

+    CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);

+    //

+    // configure the new address

+    //

+    for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {

+      AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index];

+    }

+

+    E100bSetupIAAddr (AdapterInfo);

+  }

+

+  if (CdbPtr->DBaddr != (UINT64) 0) {

+    DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);

+    //

+    // fill it with the new values

+    //

+    for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {

+      DbPtr->StationAddr[Index]   = AdapterInfo->CurrentNodeAddress[Index];

+      DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index];

+      DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index];

+    }

+  }

+

+  return ;

+}

+

+

+/**

+  This routine is used to read and clear the NIC traffic statistics.  This command is supported only

+  if the !PXE structure's Implementation flags say so.

+  Results will be parsed out in the following manner:

+  CdbPtr->DBaddr.Data[0]   R  Total Frames (Including frames with errors and dropped frames)

+  CdbPtr->DBaddr.Data[1]   R  Good Frames (All frames copied into receive buffer)

+  CdbPtr->DBaddr.Data[2]   R  Undersize Frames (Frames below minimum length for media <64 for ethernet)

+  CdbPtr->DBaddr.Data[4]   R  Dropped Frames (Frames that were dropped because receive buffers were full)

+  CdbPtr->DBaddr.Data[8]   R  CRC Error Frames (Frames with alignment or CRC errors)

+  CdbPtr->DBaddr.Data[A]   T  Total Frames (Including frames with errors and dropped frames)

+  CdbPtr->DBaddr.Data[B]   T  Good Frames (All frames copied into transmit buffer)

+  CdbPtr->DBaddr.Data[C]   T  Undersize Frames (Frames below minimum length for media <64 for ethernet)

+  CdbPtr->DBaddr.Data[E]   T  Dropped Frames (Frames that were dropped because of collisions)

+  CdbPtr->DBaddr.Data[14]  T  Total Collision Frames (Total collisions on this subnet)

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Statistics (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {

+    //

+    // Reset the statistics

+    //

+    CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0);

+  } else {

+    CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize);

+  }

+

+  return ;

+}

+

+

+/**

+  This routine is used to translate a multicast IP address to a multicast MAC address.

+  This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP

+  address being appended to it.  Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_ip2mac (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;

+  PXE_DB_MCAST_IP_TO_MAC  *DbPtr;

+  UINT8                   *TmpPtr;

+

+  CpbPtr  = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;

+  DbPtr   = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;

+

+  if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {

+    //

+    // for now this is not supported

+    //

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;

+    return ;

+  }

+

+  TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4);

+  //

+  // check if the ip given is a mcast IP

+  //

+  if ((TmpPtr[0] & 0xF0) != 0xE0) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;

+  }

+  //

+  // take the last 23 bits in IP.

+  // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur

+  // casting the mac array (in the middle) to a UINT32 pointer and accessing

+  // the UINT32 content hung the system...

+  //

+  DbPtr->MAC[0] = 0x01;

+  DbPtr->MAC[1] = 0x00;

+  DbPtr->MAC[2] = 0x5e;

+  DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);

+  DbPtr->MAC[4] = (UINT8) TmpPtr[2];

+  DbPtr->MAC[5] = (UINT8) TmpPtr[3];

+

+  return ;

+}

+

+

+/**

+  This routine is used to read and write non-volatile storage on the NIC (if supported).  The NVRAM

+  could be EEPROM, FLASH, or battery backed RAM.

+  This is an optional function according to the UNDI specification  (or will be......)

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_NVData (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_DB_NVDATA *DbPtr;

+  UINT16        Index;

+

+  if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {

+

+    if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) {

+      CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+      CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+      return ;

+    }

+

+    DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;

+

+    for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {

+      DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index];

+

+    }

+

+  } else {

+    //

+    // no write for now

+    //

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;

+  }

+

+  return ;

+}

+

+

+/**

+  This routine returns the current interrupt status and/or the transmitted buffer addresses.

+  If the current interrupt status is returned, pending interrupts will be acknowledged by this

+  command.  Transmitted buffer addresses that are written to the DB are removed from the transmit

+  buffer queue.

+  Normally, this command would be polled with interrupts disabled.

+  The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].

+  The interrupt status is returned in CdbPtr->StatFlags.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Status (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_DB_GET_STATUS *DbPtr;

+  PXE_DB_GET_STATUS TmpGetStatus;

+  UINT16            Index;

+  UINT16            Status;

+  UINT16            NumEntries;

+  RxFD              *RxPtr;

+

+  //

+  // Fill in temporary GetStatus storage.

+  //

+  RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];

+

+  if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {

+    TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;

+  } else {

+    TmpGetStatus.RxFrameLen = 0;

+  }

+

+  TmpGetStatus.reserved = 0;

+

+  //

+  // Fill in size of next available receive packet and

+  // reserved field in caller's DB storage.

+  //

+  DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;

+

+  if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {

+    CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);

+  } else {

+    CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);

+  }

+

+  //

+  //

+  //

+  if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {

+    //

+    // DBsize of zero is invalid if Tx buffers are requested.

+    //

+    if (CdbPtr->DBsize == 0) {

+      CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+      CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+      return ;

+    }

+

+    //

+    // remember this b4 we overwrite

+    //

+    NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));

+

+    //

+    // We already filled in 2 UINT32s.

+    //

+    CdbPtr->DBsize = (UINT16) (sizeof (UINT32) * 2);

+

+    //

+    // will claim any hanging free CBs

+    //

+    CheckCBList (AdapterInfo);

+

+    if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {

+      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;

+    } else {

+      for (Index = 0; ((Index < MAX_XMIT_BUFFERS) && (NumEntries >= sizeof (UINT64))); Index++, NumEntries -= sizeof (UINT64)) {

+        if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {

+          DbPtr->TxBuffer[Index]      = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];

+          AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);

+          CdbPtr->DBsize += sizeof (UINT64);

+        } else {

+          break;

+        }

+      }

+    }

+

+    if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {

+      CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;

+

+    }

+    //

+    // check for a receive buffer and give it's size in db

+    //

+  }

+  //

+  //

+  //

+  if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {

+

+    Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);

+    AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status);

+

+    //

+    // acknoledge the interrupts

+    //

+    OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));

+

+    //

+    // report all the outstanding interrupts

+    //

+    Status = AdapterInfo->Int_Status;

+    if ((Status & SCB_STATUS_FR) != 0) {

+      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;

+    }

+

+    if ((Status & SCB_STATUS_SWI) != 0) {

+      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;

+    }

+  }

+

+  //

+  // Return current media status

+  //

+  if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {

+    AdapterInfo->PhyAddress = 0xFF;

+    AdapterInfo->CableDetect = 1;

+

+    if (!PhyDetect (AdapterInfo)) {

+      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;

+    }

+  }

+

+  return ;

+}

+

+

+/**

+  This routine is used to fill media header(s) in transmit packet(s).

+  Copies the MAC address into the media header whether it is dealing

+  with fragmented or non-fragmented packets.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_FillHeader (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PXE_CPB_FILL_HEADER             *Cpb;

+  PXE_CPB_FILL_HEADER_FRAGMENTED  *Cpbf;

+  EtherHeader                     *MacHeader;

+  UINTN                           Index;

+

+  if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {

+    Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;

+

+    //

+    // assume 1st fragment is big enough for the mac header

+    //

+    if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {

+      //

+      // no buffers given

+      //

+      CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+      CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+      return ;

+    }

+

+    MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr;

+    //

+    // we don't swap the protocol bytes

+    //

+    MacHeader->type = Cpbf->Protocol;

+

+    for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+      MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index];

+      MacHeader->src_addr[Index]  = Cpbf->SrcAddr[Index];

+    }

+  } else {

+    Cpb       = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;

+

+    MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader;

+    //

+    // we don't swap the protocol bytes

+    //

+    MacHeader->type = Cpb->Protocol;

+

+    for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+      MacHeader->dest_addr[Index] = Cpb->DestAddr[Index];

+      MacHeader->src_addr[Index]  = Cpb->SrcAddr[Index];

+    }

+  }

+

+  return ;

+}

+

+

+/**

+  This routine is used to place a packet into the transmit queue.  The data buffers given to

+  this command are to be considered locked and the application or network driver loses

+  ownership of these buffers and must not free or relocate them until the ownership returns.

+  When the packets are transmitted, a transmit complete interrupt is generated (if interrupts

+  are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status

+  command.

+  Some implementations and adapters support transmitting multiple packets with one transmit

+  command.  If this feature is supported, the transmit CPBs can be linked in one transmit

+  command.

+  All UNDIs support fragmented frames, now all network devices or protocols do.  If a fragmented

+  frame CPB is given to UNDI and the network device does not support fragmented frames

+  (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer

+  before transmitting.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Transmit (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+

+  if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags);

+

+  if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+  }

+

+  return ;

+}

+

+

+/**

+  When the network adapter has received a frame, this command is used to copy the frame

+  into the driver/application storage location.  Once a frame has been copied, it is

+  removed from the receive queue.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+VOID

+UNDI_Receive (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+

+  //

+  // check if RU has started...

+  //

+  if (!AdapterInfo->Receive_Started) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;

+    return ;

+  }

+

+

+  CdbPtr->StatCode  = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr);

+  if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+

+  }

+

+  return ;

+}

+

+

+

+/**

+  This is the main SW UNDI API entry using the newer nii protocol.

+  The parameter passed in is a 64 bit flat model virtual

+  address of the cdb.  We then jump into the common routine for both old and

+  new nii protocol entries.

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+// TODO:    cdb - add argument and description to function comment

+VOID

+UNDI_APIEntry_new (

+  IN  UINT64 cdb

+  )

+{

+  PXE_CDB           *CdbPtr;

+  NIC_DATA_INSTANCE *AdapterInfo;

+

+  if (cdb == (UINT64) 0) {

+    return ;

+

+  }

+

+  CdbPtr = (PXE_CDB *) (UINTN) cdb;

+

+  if (CdbPtr->IFnum >= (pxe_31->IFcnt | pxe_31->IFcntExt << 8) ) {

+    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+    return ;

+  }

+

+  AdapterInfo               = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);

+  //

+  // entering from older entry point

+  //

+  AdapterInfo->VersionFlag  = 0x31;

+  UNDI_APIEntry_Common (cdb);

+}

+

+

+/**

+  This is the common routine for both old and new entry point procedures.

+  The parameter passed in is a 64 bit flat model virtual

+  address of the cdb.  We then jump into the service routine pointed to by the

+  Api_Table[OpCode].

+

+  @param  CdbPtr               Pointer to the command descriptor block.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @return None

+

+**/

+// TODO:    cdb - add argument and description to function comment

+VOID

+UNDI_APIEntry_Common (

+  IN  UINT64 cdb

+  )

+{

+  PXE_CDB           *CdbPtr;

+  NIC_DATA_INSTANCE *AdapterInfo;

+  UNDI_CALL_TABLE   *tab_ptr;

+

+  CdbPtr = (PXE_CDB *) (UINTN) cdb;

+

+  //

+  // check the OPCODE range

+  //

+  if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||

+      (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||

+      (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||

+      (CdbPtr->IFnum >= (pxe_31->IFcnt |  pxe_31->IFcntExt << 8))) {

+    goto badcdb;

+

+  }

+

+  if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {

+    if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {

+      goto badcdb;

+    }

+  } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {

+    goto badcdb;

+  }

+

+  if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {

+    if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {

+      goto badcdb;

+    }

+  } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {

+    goto badcdb;

+  }

+

+  //

+  // check if cpbsize and dbsize are as needed

+  // check if opflags are as expected

+  //

+  tab_ptr = &api_table[CdbPtr->OpCode];

+

+  if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {

+    goto badcdb;

+  }

+

+  if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {

+    goto badcdb;

+  }

+

+  if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {

+    goto badcdb;

+

+  }

+

+  AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);

+

+  //

+  // check if UNDI_State is valid for this call

+  //

+  if (tab_ptr->state != (UINT16) (-1)) {

+    //

+    // should atleast be started

+    //

+    if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {

+      CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+      CdbPtr->StatCode  = PXE_STATCODE_NOT_STARTED;

+      return ;

+    }

+    //

+    // check if it should be initialized

+    //

+    if (tab_ptr->state == 2) {

+      if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {

+        CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;

+        CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+        return ;

+      }

+    }

+  }

+  //

+  // set the return variable for success case here

+  //

+  CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;

+  CdbPtr->StatCode  = PXE_STATCODE_SUCCESS;

+

+  tab_ptr->api_ptr (CdbPtr, AdapterInfo);

+  return ;

+  //

+  // %% AVL - check for command linking

+  //

+badcdb:

+  CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;

+  CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;

+  return ;

+}

+

+

+/**

+  When called with a null NicPtr, this routine decrements the number of NICs

+  this UNDI is supporting and removes the NIC_DATA_POINTER from the array.

+  Otherwise, it increments the number of NICs this UNDI is supported and

+  updates the pxe.Fudge to ensure a proper check sum results.

+

+  @param  NicPtr               Pointer to the NIC data structure.

+

+  @return None

+

+**/

+VOID

+PxeUpdate (

+  IN  NIC_DATA_INSTANCE *NicPtr,

+  IN PXE_SW_UNDI        *PxePtr

+  )

+{

+  UINT16 NicNum;

+  NicNum = (PxePtr->IFcnt | PxePtr->IFcntExt << 8);

+  

+  if (NicPtr == NULL) {

+    if (NicNum > 0) {

+      //

+      // number of NICs this undi supports

+      //

+      NicNum --;

+    }

+    goto done;

+  }

+

+  //

+  // number of NICs this undi supports

+  //

+  NicNum++;

+  

+done: 

+  PxePtr->IFcnt = (UINT8)(NicNum & 0xFF);

+  PxePtr->IFcntExt = (UINT8) ((NicNum & 0xFF00) >> 8);

+  PxePtr->Fudge = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));

+  return ;

+}

+

+

+/**

+  Initialize the !PXE structure

+

+  @param  PxePtr               Pointer to SW_UNDI data structure.

+

+  @retval EFI_SUCCESS          This driver is added to Controller.

+  @retval other                This driver does not support this device.

+

+**/

+VOID

+PxeStructInit (

+  IN PXE_SW_UNDI *PxePtr

+  )

+{

+  //

+  // Initialize the !PXE structure

+  //

+  PxePtr->Signature = PXE_ROMID_SIGNATURE;

+  PxePtr->Len       = (UINT8) sizeof (PXE_SW_UNDI);

+  //

+  // cksum

+  //

+  PxePtr->Fudge     = 0;

+  //

+  // number of NICs this undi supports

+  //

+  PxePtr->IFcnt = 0;

+  PxePtr->IFcntExt = 0;

+  PxePtr->Rev       = PXE_ROMID_REV;

+  PxePtr->MajorVer  = PXE_ROMID_MAJORVER;

+  PxePtr->MinorVer  = PXE_ROMID_MINORVER;

+  PxePtr->reserved1 = 0;

+

+  PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |

+    PXE_ROMID_IMP_FRAG_SUPPORTED |

+    PXE_ROMID_IMP_CMD_LINK_SUPPORTED |

+    PXE_ROMID_IMP_NVDATA_READ_ONLY |

+    PXE_ROMID_IMP_STATION_ADDR_SETTABLE |

+    PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |

+    PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |

+    PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |

+    PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |

+    PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |

+    PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;

+

+  PxePtr->EntryPoint  = (UINT64) (UINTN) UNDI_APIEntry_new;

+  PxePtr->MinorVer    = PXE_ROMID_MINORVER_31;

+

+  PxePtr->reserved2[0]  = 0;

+  PxePtr->reserved2[1]  = 0;

+  PxePtr->reserved2[2]  = 0;

+  PxePtr->BusCnt        = 1;

+  PxePtr->BusType[0]    = PXE_BUSTYPE_PCI;

+

+  PxePtr->Fudge         = (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) PxePtr, PxePtr->Len));

+}

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/E100b.c b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/E100b.c
new file mode 100644
index 0000000..8b29c7e
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/E100b.c
@@ -0,0 +1,3547 @@
+/** @file

+  Provides basic function upon network adapter card.

+

+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.

+

+**/

+

+#include "Undi32.h"

+

+UINT8 basic_config_cmd[22] = {

+                    22,        0x08,

+                    0,           0,

+                    0, (UINT8)0x80,

+                    0x32,        0x03,

+                    1,            0,

+                    0x2E,           0,

+                    0x60,           0,

+                    (UINT8)0xf2,        0x48,

+                    0,        0x40,

+                    (UINT8)0xf2, (UINT8)0x80, // 0x40=Force full-duplex

+                    0x3f,       0x05,

+};

+

+//

+// How to wait for the command unit to accept a command.

+// Typically this takes 0 ticks.

+//

+#define wait_for_cmd_done(cmd_ioaddr) \

+{                      \

+  INT16 wait_count = 2000;              \

+  while ((InByte (AdapterInfo, cmd_ioaddr) != 0) && --wait_count >= 0)  \

+    DelayIt (AdapterInfo, 10);  \

+  if (wait_count == 0) \

+    DelayIt (AdapterInfo, 50);    \

+}

+

+

+/**

+  This function calls the MemIo callback to read a byte from the device's

+  address space

+  Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)

+  which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have

+  to make undi3.0 a special case

+

+  @param  Port                            Which port to read from.

+

+  @retval Results                         The data read from the port.

+

+**/

+// TODO:    AdapterInfo - add argument and description to function comment

+UINT8

+InByte (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT32            Port

+  )

+{

+  UINT8 Results;

+

+  (*AdapterInfo->Mem_Io) (

+    AdapterInfo->Unique_ID,

+    PXE_MEM_READ,

+    1,

+    (UINT64)Port,

+    (UINT64) (UINTN) &Results

+    );

+  return Results;

+}

+

+

+/**

+  This function calls the MemIo callback to read a word from the device's

+  address space

+  Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)

+  which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have

+  to make undi3.0 a special case

+

+  @param  Port                            Which port to read from.

+

+  @retval Results                         The data read from the port.

+

+**/

+// TODO:    AdapterInfo - add argument and description to function comment

+UINT16

+InWord (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT32            Port

+  )

+{

+  UINT16  Results;

+

+  (*AdapterInfo->Mem_Io) (

+    AdapterInfo->Unique_ID,

+    PXE_MEM_READ,

+    2,

+    (UINT64)Port,

+    (UINT64)(UINTN)&Results

+    );

+  return Results;

+}

+

+

+/**

+  This function calls the MemIo callback to read a dword from the device's

+  address space

+  Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)

+  which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have

+  to make undi3.0 a special case

+

+  @param  Port                            Which port to read from.

+

+  @retval Results                         The data read from the port.

+

+**/

+// TODO:    AdapterInfo - add argument and description to function comment

+UINT32

+InLong (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT32            Port

+  )

+{

+  UINT32  Results;

+

+  (*AdapterInfo->Mem_Io) (

+    AdapterInfo->Unique_ID,

+    PXE_MEM_READ,

+    4,

+    (UINT64)Port,

+    (UINT64)(UINTN)&Results

+    );

+  return Results;

+}

+

+

+/**

+  This function calls the MemIo callback to write a byte from the device's

+  address space

+  Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)

+  which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have

+  to make undi3.0 a special case

+

+  @param  Data                            Data to write to Port.

+  @param  Port                            Which port to write to.

+

+  @return none

+

+**/

+// TODO:    AdapterInfo - add argument and description to function comment

+VOID

+OutByte (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT8             Data,

+  IN UINT32            Port

+  )

+{

+  UINT8 Val;

+

+  Val = Data;

+  (*AdapterInfo->Mem_Io) (

+     AdapterInfo->Unique_ID,

+     PXE_MEM_WRITE,

+     1,

+     (UINT64)Port,

+     (UINT64)(UINTN)(UINTN)&Val

+     );

+  return ;

+}

+

+

+/**

+  This function calls the MemIo callback to write a word from the device's

+  address space

+  Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)

+  which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have

+  to make undi3.0 a special case

+

+  @param  Data                            Data to write to Port.

+  @param  Port                            Which port to write to.

+

+  @return none

+

+**/

+// TODO:    AdapterInfo - add argument and description to function comment

+VOID

+OutWord (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT16            Data,

+  IN UINT32            Port

+  )

+{

+  UINT16  Val;

+

+  Val = Data;

+  (*AdapterInfo->Mem_Io) (

+     AdapterInfo->Unique_ID,

+     PXE_MEM_WRITE,

+     2,

+     (UINT64)Port,

+     (UINT64)(UINTN)&Val

+     );

+  return ;

+}

+

+

+/**

+  This function calls the MemIo callback to write a dword from the device's

+  address space

+  Since UNDI3.0 uses the TmpMemIo function (instead of the callback routine)

+  which also takes the UniqueId parameter (as in UNDI3.1 spec) we don't have

+  to make undi3.0 a special case

+

+  @param  Data                            Data to write to Port.

+  @param  Port                            Which port to write to.

+

+  @return none

+

+**/

+// TODO:    AdapterInfo - add argument and description to function comment

+VOID

+OutLong (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT32            Data,

+  IN UINT32            Port

+  )

+{

+  UINT32  Val;

+

+  Val = Data;

+  (*AdapterInfo->Mem_Io) (

+     AdapterInfo->Unique_ID,

+     PXE_MEM_WRITE,

+     4,

+     (UINT64)Port,

+     (UINT64)(UINTN)&Val

+     );

+  return ;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  MemAddr                         TODO: add argument description

+  @param  Size                            TODO: add argument description

+  @param  Direction                       TODO: add argument description

+  @param  MappedAddr                      TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINTN

+MapIt (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT64            MemAddr,

+  IN UINT32            Size,

+  IN UINT32            Direction,

+  OUT UINT64           MappedAddr

+  )

+{

+  UINT64  *PhyAddr;

+

+  PhyAddr = (UINT64 *) (UINTN) MappedAddr;

+  //

+  // mapping is different for theold and new NII protocols

+  //

+  if (AdapterInfo->VersionFlag == 0x30) {

+    if (AdapterInfo->Virt2Phys_30 == (VOID *) NULL) {

+      *PhyAddr = (UINT64) AdapterInfo->MemoryPtr;

+    } else {

+      (*AdapterInfo->Virt2Phys_30) (MemAddr, (UINT64) (UINTN) PhyAddr);

+    }

+

+    if (*PhyAddr > FOUR_GIGABYTE) {

+      return PXE_STATCODE_INVALID_PARAMETER;

+    }

+  } else {

+    if (AdapterInfo->Map_Mem == (VOID *) NULL) {

+      //

+      // this UNDI cannot handle addresses beyond 4 GB without a map routine

+      //

+      if (MemAddr > FOUR_GIGABYTE) {

+        return PXE_STATCODE_INVALID_PARAMETER;

+      } else {

+        *PhyAddr = MemAddr;

+      }

+    } else {

+      (*AdapterInfo->Map_Mem) (

+        AdapterInfo->Unique_ID,

+        MemAddr,

+        Size,

+        Direction,

+        MappedAddr

+        );

+    }

+  }

+

+  return PXE_STATCODE_SUCCESS;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  MemAddr                         TODO: add argument description

+  @param  Size                            TODO: add argument description

+  @param  Direction                       TODO: add argument description

+  @param  MappedAddr                      TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+VOID

+UnMapIt (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT64            MemAddr,

+  IN UINT32            Size,

+  IN UINT32            Direction,

+  IN UINT64            MappedAddr

+  )

+{

+  if (AdapterInfo->VersionFlag > 0x30) {

+    //

+    // no mapping service

+    //

+    if (AdapterInfo->UnMap_Mem != (VOID *) NULL) {

+      (*AdapterInfo->UnMap_Mem) (

+        AdapterInfo->Unique_ID,

+        MemAddr,

+        Size,

+        Direction,

+        MappedAddr

+        );

+

+    }

+  }

+

+  return ;

+}

+

+

+/**

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+

+**/

+// TODO:    MicroSeconds - add argument and description to function comment

+VOID

+DelayIt (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  UINT16               MicroSeconds

+  )

+{

+  if (AdapterInfo->VersionFlag == 0x30) {

+    (*AdapterInfo->Delay_30) (MicroSeconds);

+  } else {

+    (*AdapterInfo->Delay) (AdapterInfo->Unique_ID, MicroSeconds);

+  }

+}

+

+

+/**

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+

+**/

+// TODO:    flag - add argument and description to function comment

+VOID

+BlockIt (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  UINT32               flag

+  )

+{

+  if (AdapterInfo->VersionFlag == 0x30) {

+    (*AdapterInfo->Block_30) (flag);

+  } else {

+    (*AdapterInfo->Block) (AdapterInfo->Unique_ID, flag);

+  }

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+Load_Base_Regs (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  //

+  // we will use the linear (flat) memory model and fill our base registers

+  // with 0's so that the entire physical address is our offset

+  //

+  //

+  // we reset the statistics totals here because this is where we are loading stats addr

+  //

+  AdapterInfo->RxTotals = 0;

+  AdapterInfo->TxTotals = 0;

+

+  //

+  // Load the statistics block address.

+  //

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+  OutLong (AdapterInfo, (UINT32) AdapterInfo->stat_phy_addr, AdapterInfo->ioaddr + SCBPointer);

+  OutByte (AdapterInfo, CU_STATSADDR, AdapterInfo->ioaddr + SCBCmd);

+  AdapterInfo->statistics->done_marker = 0;

+

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+  OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);

+  OutByte (AdapterInfo, RX_ADDR_LOAD, AdapterInfo->ioaddr + SCBCmd);

+

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+  OutLong (AdapterInfo, 0, AdapterInfo->ioaddr + SCBPointer);

+  OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  cmd_ptr                         TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+IssueCB (

+  NIC_DATA_INSTANCE *AdapterInfo,

+  TxCB              *cmd_ptr

+  )

+{

+  UINT16  status;

+

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+  //

+  // read the CU status, if it is idle, write the address of cb_ptr

+  // in the scbpointer and issue a cu_start,

+  // if it is suspended, remove the suspend bit in the previous command

+  // block and issue a resume

+  //

+  // Ensure that the CU Active Status bit is not on from previous CBs.

+  //

+  status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);

+

+  //

+  // Skip acknowledging the interrupt if it is not already set

+  //

+

+  //

+  // ack only the cna the integer

+  //

+  if ((status & SCB_STATUS_CNA) != 0) {

+    OutWord (AdapterInfo, SCB_STATUS_CNA, AdapterInfo->ioaddr + SCBStatus);

+

+  }

+

+  if ((status & SCB_STATUS_CU_MASK) == SCB_STATUS_CU_IDLE) {

+    //

+    // give a cu_start

+    //

+    OutLong (AdapterInfo, cmd_ptr->PhysTCBAddress, AdapterInfo->ioaddr + SCBPointer);

+    OutByte (AdapterInfo, CU_START, AdapterInfo->ioaddr + SCBCmd);

+  } else {

+    //

+    // either active or suspended, give a resume

+    //

+

+    cmd_ptr->PrevTCBVirtualLinkPtr->cb_header.command &= ~(CmdSuspend | CmdIntr);

+    OutByte (AdapterInfo, CU_RESUME, AdapterInfo->ioaddr + SCBCmd);

+  }

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+Configure (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  //

+  // all command blocks are of TxCB format

+  //

+  TxCB  *cmd_ptr;

+  UINT8 *data_ptr;

+  volatile INT16 Index;

+  UINT8 my_filter;

+

+  cmd_ptr   = GetFreeCB (AdapterInfo);

+  ASSERT (cmd_ptr != NULL);

+  data_ptr  = (UINT8 *) cmd_ptr + sizeof (struct CB_Header);

+

+  //

+  // start the config data right after the command header

+  //

+  for (Index = 0; Index < sizeof (basic_config_cmd); Index++) {

+    data_ptr[Index] = basic_config_cmd[Index];

+  }

+

+  my_filter = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) ? 1 : 0);

+  my_filter = (UINT8) (my_filter | ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) ? 0 : 2));

+

+  data_ptr[15]  = (UINT8) (data_ptr[15] | my_filter);

+  data_ptr[19]  = (UINT8) (AdapterInfo->Duplex ? 0xC0 : 0x80);

+  data_ptr[21]  = (UINT8) ((AdapterInfo->Rx_Filter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) ? 0x0D : 0x05);

+

+  //

+  // check if we have to use the AUI port instead

+  //

+  if ((AdapterInfo->PhyRecord[0] & 0x8000) != 0) {

+    data_ptr[15] |= 0x80;

+    data_ptr[8] = 0;

+  }

+

+  BlockIt (AdapterInfo, TRUE);

+  cmd_ptr->cb_header.command = CmdSuspend | CmdConfigure;

+

+  IssueCB (AdapterInfo, cmd_ptr);

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+  BlockIt (AdapterInfo, FALSE);

+

+  CommandWaitForCompletion (cmd_ptr, AdapterInfo);

+

+  //

+  // restore the cb values for tx

+  //

+  cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;

+  cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;

+  //

+  // fields beyond the immediatedata are assumed to be safe

+  // add the CB to the free list again

+  //

+  SetFreeCB (AdapterInfo, cmd_ptr);

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+E100bSetupIAAddr (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  //

+  // all command blocks are of TxCB format

+  //

+  TxCB    *cmd_ptr;

+  UINT16  *data_ptr;

+  UINT16  *eaddrs;

+

+  eaddrs    = (UINT16 *) AdapterInfo->CurrentNodeAddress;

+

+  cmd_ptr   = GetFreeCB (AdapterInfo);

+  ASSERT (cmd_ptr != NULL);

+  data_ptr  = (UINT16 *) ((UINT8 *) cmd_ptr +sizeof (struct CB_Header));

+

+  //

+  // AVOID a bug (?!) here by marking the command already completed.

+  //

+  cmd_ptr->cb_header.command  = (CmdSuspend | CmdIASetup);

+  cmd_ptr->cb_header.status   = 0;

+  data_ptr[0]                 = eaddrs[0];

+  data_ptr[1]                 = eaddrs[1];

+  data_ptr[2]                 = eaddrs[2];

+

+  BlockIt (AdapterInfo, TRUE);

+  IssueCB (AdapterInfo, cmd_ptr);

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+  BlockIt (AdapterInfo, FALSE);

+

+  CommandWaitForCompletion (cmd_ptr, AdapterInfo);

+

+  //

+  // restore the cb values for tx

+  //

+  cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;

+  cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;

+  //

+  // fields beyond the immediatedata are assumed to be safe

+  // add the CB to the free list again

+  //

+  SetFreeCB (AdapterInfo, cmd_ptr);

+  return 0;

+}

+

+

+/**

+  Instructs the NIC to stop receiving packets.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+

+**/

+VOID

+StopRU (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  if (AdapterInfo->Receive_Started) {

+

+    //

+    // Todo: verify that we must wait for previous command completion.

+    //

+    wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+    //

+    // Disable interrupts, and stop the chip's Rx process.

+    //

+    OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);

+    OutWord (AdapterInfo, INT_MASK | RX_ABORT, AdapterInfo->ioaddr + SCBCmd);

+

+    AdapterInfo->Receive_Started = FALSE;

+  }

+

+  return ;

+}

+

+

+/**

+  Instructs the NIC to start receiving packets.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+  @retval 0                               Successful

+  @retval -1                              Already Started

+

+**/

+INT8

+StartRU (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+

+  if (AdapterInfo->Receive_Started) {

+    //

+    // already started

+    //

+    return -1;

+  }

+

+  AdapterInfo->cur_rx_ind = 0;

+  AdapterInfo->Int_Status = 0;

+

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+  OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);

+  OutByte (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);

+

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+  AdapterInfo->Receive_Started = TRUE;

+  return 0;

+}

+

+

+/**

+  Configures the chip.  This routine expects the NIC_DATA_INSTANCE structure to be filled in.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+  @retval 0                               Successful

+  @retval PXE_STATCODE_NOT_ENOUGH_MEMORY  Insufficient length of locked memory

+  @retval other                           Failure initializing chip

+

+**/

+UINTN

+E100bInit (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  PCI_CONFIG_HEADER *CfgHdr;

+  UINTN             stat;

+  UINTN             rx_size;

+  UINTN             tx_size;

+

+  if (AdapterInfo->MemoryLength < MEMORY_NEEDED) {

+    return PXE_STATCODE_NOT_ENOUGH_MEMORY;

+  }

+

+  stat = MapIt (

+          AdapterInfo,

+          AdapterInfo->MemoryPtr,

+          AdapterInfo->MemoryLength,

+          TO_AND_FROM_DEVICE,

+          (UINT64)(UINTN) &AdapterInfo->Mapped_MemoryPtr

+          );

+

+  if (stat != 0) {

+    return stat;

+  }

+

+  CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);

+

+  //

+  // fill in the ioaddr, int... from the config space

+  //

+  AdapterInfo->int_num = CfgHdr->int_line;

+

+  //

+  // we don't need to validate integer number, what if they don't want to assign one?

+  // if (AdapterInfo->int_num == 0 || AdapterInfo->int_num == 0xff)

+  // return PXE_STATCODE_DEVICE_FAILURE;

+  //

+  AdapterInfo->ioaddr       = 0;

+  AdapterInfo->VendorID     = CfgHdr->VendorID;

+  AdapterInfo->DeviceID     = CfgHdr->DeviceID;

+  AdapterInfo->RevID        = CfgHdr->RevID;

+  AdapterInfo->SubVendorID  = CfgHdr->SubVendorID;

+  AdapterInfo->SubSystemID  = CfgHdr->SubSystemID;

+  AdapterInfo->flash_addr   = 0;

+

+  //

+  // Read the station address EEPROM before doing the reset.

+  // Perhaps this should even be done before accepting the device,

+  // then we wouldn't have a device name with which to report the error.

+  //

+  if (E100bReadEepromAndStationAddress (AdapterInfo) != 0) {

+    return PXE_STATCODE_DEVICE_FAILURE;

+

+  }

+  //

+  // ## calculate the buffer #s depending on memory given

+  // ## calculate the rx and tx ring pointers

+  //

+

+  AdapterInfo->TxBufCnt       = TX_BUFFER_COUNT;

+  AdapterInfo->RxBufCnt       = RX_BUFFER_COUNT;

+  rx_size                     = (AdapterInfo->RxBufCnt * sizeof (RxFD));

+  tx_size                     = (AdapterInfo->TxBufCnt * sizeof (TxCB));

+  AdapterInfo->rx_ring        = (RxFD *) (UINTN) (AdapterInfo->MemoryPtr);

+  AdapterInfo->tx_ring        = (TxCB *) (UINTN) (AdapterInfo->MemoryPtr + rx_size);

+  AdapterInfo->statistics     = (struct speedo_stats *) (UINTN) (AdapterInfo->MemoryPtr + rx_size + tx_size);

+

+  AdapterInfo->rx_phy_addr    = AdapterInfo->Mapped_MemoryPtr;

+  AdapterInfo->tx_phy_addr    = AdapterInfo->Mapped_MemoryPtr + rx_size;

+  AdapterInfo->stat_phy_addr  = AdapterInfo->tx_phy_addr + tx_size;

+

+  //

+  // auto detect.

+  //

+  AdapterInfo->PhyAddress     = 0xFF;

+  AdapterInfo->Rx_Filter            = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;

+  AdapterInfo->Receive_Started      = FALSE;

+  AdapterInfo->mcast_list.list_len  = 0;

+  return InitializeChip (AdapterInfo);

+}

+

+

+/**

+  Sets the interrupt state for the NIC.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+  @retval 0                               Successful

+

+**/

+UINT8

+E100bSetInterruptState (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  //

+  // don't set receive interrupt if receiver is disabled...

+  //

+  UINT16  cmd_word;

+

+  if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {

+    cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd);

+    cmd_word &= ~INT_MASK;

+    OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd);

+  } else {

+    //

+    // disable ints, should not be given for SW Int.

+    //

+    OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);

+  }

+

+  if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_SOFTWARE) != 0) {

+    //

+    // reset the bit in our mask, it is only one time!!

+    //

+    AdapterInfo->int_mask &= ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE);

+    cmd_word = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd);

+    cmd_word |= DRVR_INT;

+    OutWord (AdapterInfo, cmd_word, AdapterInfo->ioaddr + SCBCmd);

+  }

+

+  return 0;

+}

+//

+// we are not going to disable broadcast for the WOL's sake!

+//

+

+/**

+  Instructs the NIC to start receiving packets.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on.. new_filter

+                                              - cpb                             -

+                                          cpbsize                         -

+

+  @retval 0                               Successful

+  @retval -1                              Already Started

+

+**/

+UINTN

+E100bSetfilter (

+  NIC_DATA_INSTANCE *AdapterInfo,

+  UINT16            new_filter,

+  UINT64            cpb,

+  UINT32            cpbsize

+  )

+{

+  PXE_CPB_RECEIVE_FILTERS *mc_list = (PXE_CPB_RECEIVE_FILTERS *) (UINTN)cpb;

+  UINT16                  cfg_flt;

+  UINT16                  old_filter;

+  UINT16                  Index;

+  UINT16                  Index2;

+  UINT16                  mc_count;

+  TxCB                    *cmd_ptr;

+  struct MC_CB_STRUCT     *data_ptr;

+  UINT16                  mc_byte_cnt;

+

+  old_filter  = AdapterInfo->Rx_Filter;

+

+  //

+  // only these bits need a change in the configuration

+  // actually change in bcast requires configure but we ignore that change

+  //

+  cfg_flt = PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS |

+            PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;

+

+  if ((old_filter & cfg_flt) != (new_filter & cfg_flt)) {

+    XmitWaitForCompletion (AdapterInfo);

+

+    if (AdapterInfo->Receive_Started) {

+      StopRU (AdapterInfo);

+    }

+

+    AdapterInfo->Rx_Filter = (UINT8) (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST);

+    Configure (AdapterInfo);

+  }

+

+  //

+  // check if mcast setting changed

+  //

+  if ( ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=

+       (old_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) ) ||

+       (mc_list != NULL) ) {

+

+

+    if (mc_list != NULL) {

+      mc_count = AdapterInfo->mcast_list.list_len = (UINT16) (cpbsize / PXE_MAC_LENGTH);

+

+      for (Index = 0; (Index < mc_count && Index < MAX_MCAST_ADDRESS_CNT); Index++) {

+        for (Index2 = 0; Index2 < PXE_MAC_LENGTH; Index2++) {

+          AdapterInfo->mcast_list.mc_list[Index][Index2] = mc_list->MCastList[Index][Index2];

+        }

+      }

+    }

+

+    //

+    // are we setting the list or resetting??

+    //

+    if ((new_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {

+      //

+      // we are setting a new list!

+      //

+      mc_count = AdapterInfo->mcast_list.list_len;

+      //

+      // count should be the actual # of bytes in the list

+      // so multiply this with 6

+      //

+      mc_byte_cnt = (UINT16) ((mc_count << 2) + (mc_count << 1));

+      AdapterInfo->Rx_Filter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;

+    } else {

+      //

+      // disabling the list in the NIC.

+      //

+      mc_byte_cnt = mc_count = 0;

+      AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);

+    }

+

+    //

+    // before issuing any new command!

+    //

+    XmitWaitForCompletion (AdapterInfo);

+

+    if (AdapterInfo->Receive_Started) {

+      StopRU (AdapterInfo);

+

+    }

+

+    cmd_ptr = GetFreeCB (AdapterInfo);

+    if (cmd_ptr == NULL) {

+      return PXE_STATCODE_QUEUE_FULL;

+    }

+    //

+    // fill the command structure and issue

+    //

+    data_ptr = (struct MC_CB_STRUCT *) (&cmd_ptr->PhysTBDArrayAddres);

+    //

+    // first 2 bytes are the count;

+    //

+    data_ptr->count = mc_byte_cnt;

+    for (Index = 0; Index < mc_count; Index++) {

+      for (Index2 = 0; Index2 < PXE_HWADDR_LEN_ETHER; Index2++) {

+        data_ptr->m_list[Index][Index2] = AdapterInfo->mcast_list.mc_list[Index][Index2];

+      }

+    }

+

+    cmd_ptr->cb_header.command  = CmdSuspend | CmdMulticastList;

+    cmd_ptr->cb_header.status   = 0;

+

+    BlockIt (AdapterInfo, TRUE);

+    IssueCB (AdapterInfo, cmd_ptr);

+    wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+    BlockIt (AdapterInfo, FALSE);

+

+    CommandWaitForCompletion (cmd_ptr, AdapterInfo);

+

+    cmd_ptr->PhysTBDArrayAddres = cmd_ptr->PhysArrayAddr;

+    cmd_ptr->ByteCount = cmd_ptr->Threshold = cmd_ptr->TBDCount = 0;

+    //

+    // fields beyond the immediatedata are assumed to be safe

+    // add the CB to the free list again

+    //

+    SetFreeCB (AdapterInfo, cmd_ptr);

+  }

+

+  if (new_filter != 0) {

+    //

+    // enable unicast and start the RU

+    //

+    AdapterInfo->Rx_Filter = (UINT8) (AdapterInfo->Rx_Filter | (new_filter | PXE_OPFLAGS_RECEIVE_FILTER_UNICAST));

+    StartRU (AdapterInfo);

+  } else {

+    //

+    // may be disabling everything!

+    //

+    if (AdapterInfo->Receive_Started) {

+      StopRU (AdapterInfo);

+    }

+

+    AdapterInfo->Rx_Filter |= (~PXE_OPFLAGS_RECEIVE_FILTER_UNICAST);

+  }

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  cpb                             TODO: add argument description

+  @param  opflags                         TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINTN

+E100bTransmit (

+  NIC_DATA_INSTANCE *AdapterInfo,

+  UINT64            cpb,

+  UINT16            opflags

+  )

+{

+  PXE_CPB_TRANSMIT_FRAGMENTS  *tx_ptr_f;

+  PXE_CPB_TRANSMIT            *tx_ptr_1;

+  TxCB                        *tcb_ptr;

+  UINT64                      Tmp_ptr;

+  UINTN                       stat;

+  INT32                       Index;

+  UINT16                      wait_sec;

+

+  tx_ptr_1  = (PXE_CPB_TRANSMIT *) (UINTN) cpb;

+  tx_ptr_f  = (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb;

+  Tmp_ptr = 0;

+

+  //

+  // stop reentrancy here

+  //

+  if (AdapterInfo->in_transmit) {

+    return PXE_STATCODE_BUSY;

+

+  }

+

+  AdapterInfo->in_transmit = TRUE;

+

+  //

+  // Prevent interrupts from changing the Tx ring from underneath us.

+  //

+  // Calculate the Tx descriptor entry.

+  //

+  if ((tcb_ptr = GetFreeCB (AdapterInfo)) == NULL) {

+    AdapterInfo->in_transmit = FALSE;

+    return PXE_STATCODE_QUEUE_FULL;

+  }

+

+  AdapterInfo->TxTotals++;

+

+  tcb_ptr->cb_header.command  = (CmdSuspend | CmdTx | CmdTxFlex);

+  tcb_ptr->cb_header.status   = 0;

+

+  //

+  // no immediate data, set EOF in the ByteCount

+  //

+  tcb_ptr->ByteCount = 0x8000;

+

+  //

+  // The data region is always in one buffer descriptor, Tx FIFO

+  // threshold of 256.

+  // 82557 multiplies the threashold value by 8, so give 256/8

+  //

+  tcb_ptr->Threshold = 32;

+  if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {

+

+    if (tx_ptr_f->FragCnt > MAX_XMIT_FRAGMENTS) {

+      SetFreeCB (AdapterInfo, tcb_ptr);

+      AdapterInfo->in_transmit = FALSE;

+      return PXE_STATCODE_INVALID_PARAMETER;

+    }

+

+    tcb_ptr->TBDCount = (UINT8) tx_ptr_f->FragCnt;

+

+    for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {

+      stat = MapIt (

+              AdapterInfo,

+              tx_ptr_f->FragDesc[Index].FragAddr,

+              tx_ptr_f->FragDesc[Index].FragLen,

+              TO_DEVICE,

+              (UINT64)(UINTN) &Tmp_ptr

+              );

+      if (stat != 0) {

+        SetFreeCB (AdapterInfo, tcb_ptr);

+        AdapterInfo->in_transmit = FALSE;

+        return PXE_STATCODE_INVALID_PARAMETER;

+      }

+

+      tcb_ptr->TBDArray[Index].phys_buf_addr  = (UINT32) Tmp_ptr;

+      tcb_ptr->TBDArray[Index].buf_len        = tx_ptr_f->FragDesc[Index].FragLen;

+    }

+

+    tcb_ptr->free_data_ptr = tx_ptr_f->FragDesc[0].FragAddr;

+

+  } else {

+    //

+    // non fragmented case

+    //

+    tcb_ptr->TBDCount = 1;

+    stat = MapIt (

+            AdapterInfo,

+            tx_ptr_1->FrameAddr,

+            tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,

+            TO_DEVICE,

+            (UINT64)(UINTN) &Tmp_ptr

+            );

+    if (stat != 0) {

+      SetFreeCB (AdapterInfo, tcb_ptr);

+      AdapterInfo->in_transmit = FALSE;

+      return PXE_STATCODE_INVALID_PARAMETER;

+    }

+

+    tcb_ptr->TBDArray[0].phys_buf_addr  = (UINT32) (Tmp_ptr);

+    tcb_ptr->TBDArray[0].buf_len        = tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen;

+    tcb_ptr->free_data_ptr              = tx_ptr_1->FrameAddr;

+  }

+

+  //

+  // must wait for previous command completion only if it was a non-transmit

+  //

+  BlockIt (AdapterInfo, TRUE);

+  IssueCB (AdapterInfo, tcb_ptr);

+  BlockIt (AdapterInfo, FALSE);

+

+  //

+  // see if we need to wait for completion here

+  //

+  if ((opflags & PXE_OPFLAGS_TRANSMIT_BLOCK) != 0) {

+    //

+    // don't wait for more than 1 second!!!

+    //

+    wait_sec = 1000;

+    while (tcb_ptr->cb_header.status == 0) {

+      DelayIt (AdapterInfo, 10);

+      wait_sec--;

+      if (wait_sec == 0) {

+        break;

+      }

+    }

+    //

+    // we need to un-map any mapped buffers here

+    //

+    if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) {

+

+      for (Index = 0; Index < tx_ptr_f->FragCnt; Index++) {

+        Tmp_ptr = tcb_ptr->TBDArray[Index].phys_buf_addr;

+        UnMapIt (

+          AdapterInfo,

+          tx_ptr_f->FragDesc[Index].FragAddr,

+          tx_ptr_f->FragDesc[Index].FragLen,

+          TO_DEVICE,

+          (UINT64) Tmp_ptr

+          );

+      }

+    } else {

+      Tmp_ptr = tcb_ptr->TBDArray[0].phys_buf_addr;

+      UnMapIt (

+        AdapterInfo,

+        tx_ptr_1->FrameAddr,

+        tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen,

+        TO_DEVICE,

+        (UINT64) Tmp_ptr

+        );

+    }

+

+    if (tcb_ptr->cb_header.status == 0) {

+      SetFreeCB (AdapterInfo, tcb_ptr);

+      AdapterInfo->in_transmit = FALSE;

+      return PXE_STATCODE_DEVICE_FAILURE;

+    }

+

+    SetFreeCB (AdapterInfo, tcb_ptr);

+  }

+  //

+  // CB will be set free later in get_status (or when we run out of xmit buffers

+  //

+  AdapterInfo->in_transmit = FALSE;

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  cpb                             TODO: add argument description

+  @param  db                              TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINTN

+E100bReceive (

+  NIC_DATA_INSTANCE *AdapterInfo,

+  UINT64            cpb,

+  UINT64            db

+  )

+{

+  PXE_CPB_RECEIVE *rx_cpbptr;

+  PXE_DB_RECEIVE  *rx_dbptr;

+  RxFD            *rx_ptr;

+  INT32           status;

+  INT32           Index;

+  UINT16          pkt_len;

+  UINT16          ret_code;

+  PXE_FRAME_TYPE  pkt_type;

+  UINT16          Tmp_len;

+  EtherHeader     *hdr_ptr;

+  ret_code  = PXE_STATCODE_NO_DATA;

+  pkt_type  = PXE_FRAME_TYPE_NONE;

+  status    = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);

+  AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | status);

+  //

+  // acknoledge the interrupts

+  //

+  OutWord (AdapterInfo, (UINT16) (status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));

+

+  //

+  // include the prev ints as well

+  //

+  status = AdapterInfo->Int_Status;

+  rx_cpbptr = (PXE_CPB_RECEIVE *) (UINTN) cpb;

+  rx_dbptr  = (PXE_DB_RECEIVE *) (UINTN) db;

+

+  rx_ptr    = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];

+

+  //

+  // be in a loop just in case (we may drop a pkt)

+  //

+  while ((status = rx_ptr->cb_header.status) & RX_COMPLETE) {

+

+    AdapterInfo->RxTotals++;

+    //

+    // If we own the next entry, it's a new packet. Send it up.

+    //

+    if (rx_ptr->forwarded) {

+      goto FreeRFD;

+

+    }

+

+    //

+    // discard bad frames

+    //

+

+    //

+    // crc, align, dma overrun, too short, receive error (v22 no coll)

+    //

+    if ((status & 0x0D90) != 0) {

+      goto FreeRFD;

+

+    }

+

+    //

+    // make sure the status is OK

+    //

+    if ((status & 0x02000) == 0) {

+      goto FreeRFD;

+    }

+

+    pkt_len = (UINT16) (rx_ptr->ActualCount & 0x3fff);

+

+    if (pkt_len != 0) {

+

+      Tmp_len = pkt_len;

+      if (pkt_len > rx_cpbptr->BufferLen) {

+        Tmp_len = (UINT16) rx_cpbptr->BufferLen;

+      }

+

+      CopyMem ((INT8 *) (UINTN) rx_cpbptr->BufferAddr, (INT8 *) &rx_ptr->RFDBuffer, Tmp_len);

+

+      hdr_ptr = (EtherHeader *) &rx_ptr->RFDBuffer;

+      //

+      // fill the CDB and break the loop

+      //

+

+      //

+      // includes header

+      //

+      rx_dbptr->FrameLen = pkt_len;

+      rx_dbptr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;

+

+      for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+        if (hdr_ptr->dest_addr[Index] != AdapterInfo->CurrentNodeAddress[Index]) {

+          break;

+        }

+      }

+

+      if (Index >= PXE_HWADDR_LEN_ETHER) {

+        pkt_type = PXE_FRAME_TYPE_UNICAST;

+      } else {

+        for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+          if (hdr_ptr->dest_addr[Index] != AdapterInfo->BroadcastNodeAddress[Index]) {

+            break;

+          }

+        }

+

+        if (Index >= PXE_HWADDR_LEN_ETHER) {

+          pkt_type = PXE_FRAME_TYPE_BROADCAST;

+        } else {

+          if ((hdr_ptr->dest_addr[0] & 1) == 1) {

+            //

+            // mcast

+            //

+

+            pkt_type = PXE_FRAME_TYPE_FILTERED_MULTICAST;

+          } else {

+            pkt_type = PXE_FRAME_TYPE_PROMISCUOUS;

+          }

+        }

+      }

+

+      rx_dbptr->Type      = pkt_type;

+      rx_dbptr->Protocol  = hdr_ptr->type;

+

+      for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+        rx_dbptr->SrcAddr[Index]  = hdr_ptr->src_addr[Index];

+        rx_dbptr->DestAddr[Index] = hdr_ptr->dest_addr[Index];

+      }

+

+      rx_ptr->forwarded = TRUE;

+      //

+      // success

+      //

+      ret_code          = 0;

+      Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind);

+      AdapterInfo->cur_rx_ind++;

+      if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) {

+        AdapterInfo->cur_rx_ind = 0;

+      }

+      break;

+    }

+

+FreeRFD:

+    Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind);

+    AdapterInfo->cur_rx_ind++;

+    if (AdapterInfo->cur_rx_ind == AdapterInfo->RxBufCnt) {

+      AdapterInfo->cur_rx_ind = 0;

+    }

+

+    rx_ptr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];

+  }

+

+  if (pkt_type == PXE_FRAME_TYPE_NONE) {

+    AdapterInfo->Int_Status &= (~SCB_STATUS_FR);

+  }

+

+  status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);

+  if ((status & SCB_RUS_NO_RESOURCES) != 0) {

+    //

+    // start the receive unit here!

+    // leave all the filled frames,

+    //

+    SetupReceiveQueues (AdapterInfo);

+    OutLong (AdapterInfo, (UINT32) AdapterInfo->rx_phy_addr, AdapterInfo->ioaddr + SCBPointer);

+    OutWord (AdapterInfo, RX_START, AdapterInfo->ioaddr + SCBCmd);

+    AdapterInfo->cur_rx_ind = 0;

+  }

+

+  return ret_code;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+INT16

+E100bReadEepromAndStationAddress (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  INT32   Index;

+  INT32   Index2;

+  UINT16  sum;

+  UINT16  eeprom_len;

+  UINT8   addr_len;

+  UINT16  *eedata;

+

+  eedata    = (UINT16 *) (&AdapterInfo->NVData[0]);

+

+  sum       = 0;

+  addr_len  = E100bGetEepromAddrLen (AdapterInfo);

+

+  //

+  // in words

+  //

+  AdapterInfo->NVData_Len = eeprom_len = (UINT16) (1 << addr_len);

+  for (Index2 = 0, Index = 0; ((Index2 < PXE_MAC_LENGTH - 1) && (Index < eeprom_len)); Index++) {

+    UINT16  value;

+    value         = E100bReadEeprom (AdapterInfo, Index, addr_len);

+    eedata[Index] = value;

+    sum           = (UINT16) (sum + value);

+    if (Index < 3) {

+      AdapterInfo->PermNodeAddress[Index2++]  = (UINT8) value;

+      AdapterInfo->PermNodeAddress[Index2++]  = (UINT8) (value >> 8);

+    }

+  }

+

+  if (sum != 0xBABA) {

+    return -1;

+  }

+

+  for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+    AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];

+  }

+

+  for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {

+    AdapterInfo->BroadcastNodeAddress[Index] = 0xff;

+  }

+

+  for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) {

+    AdapterInfo->CurrentNodeAddress[Index]    = 0;

+    AdapterInfo->PermNodeAddress[Index]       = 0;

+    AdapterInfo->BroadcastNodeAddress[Index]  = 0;

+  }

+

+  return 0;

+}

+

+//

+//  CBList is a circular linked list

+//  1) When all are free, Tail->next == Head and FreeCount == # allocated

+//  2) When none are free, Tail == Head and FreeCount == 0

+//  3) when one is free, Tail == Head and Freecount == 1

+//  4) First non-Free frame is always at Tail->next

+//

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+SetupCBlink (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  TxCB  *head_ptr;

+  TxCB  *tail_ptr;

+  TxCB  *cur_ptr;

+  INT32 Index;

+  UINTN array_off;

+

+  cur_ptr   = &(AdapterInfo->tx_ring[0]);

+  array_off = (UINTN) (&cur_ptr->TBDArray) - (UINTN) cur_ptr;

+  for (Index = 0; Index < AdapterInfo->TxBufCnt; Index++) {

+    cur_ptr[Index].cb_header.status   = 0;

+    cur_ptr[Index].cb_header.command  = 0;

+

+    cur_ptr[Index].PhysTCBAddress     =

+    (UINT32) AdapterInfo->tx_phy_addr + (Index * sizeof (TxCB));

+

+    cur_ptr[Index].PhysArrayAddr      = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);

+    cur_ptr[Index].PhysTBDArrayAddres = (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off);

+

+    cur_ptr->free_data_ptr = (UINT64) 0;

+

+    if (Index < AdapterInfo->TxBufCnt - 1) {

+      cur_ptr[Index].cb_header.link             = cur_ptr[Index].PhysTCBAddress + sizeof (TxCB);

+      cur_ptr[Index].NextTCBVirtualLinkPtr      = &cur_ptr[Index + 1];

+      cur_ptr[Index + 1].PrevTCBVirtualLinkPtr  = &cur_ptr[Index];

+    }

+  }

+

+  head_ptr                        = &cur_ptr[0];

+  tail_ptr                        = &cur_ptr[AdapterInfo->TxBufCnt - 1];

+  tail_ptr->cb_header.link        = head_ptr->PhysTCBAddress;

+  tail_ptr->NextTCBVirtualLinkPtr = head_ptr;

+  head_ptr->PrevTCBVirtualLinkPtr = tail_ptr;

+

+  AdapterInfo->FreeCBCount        = AdapterInfo->TxBufCnt;

+  AdapterInfo->FreeTxHeadPtr      = head_ptr;

+  //

+  // set tail of the free list, next to this would be either in use

+  // or the head itself

+  //

+  AdapterInfo->FreeTxTailPtr  = tail_ptr;

+

+  AdapterInfo->xmit_done_head = AdapterInfo->xmit_done_tail = 0;

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+TxCB *

+GetFreeCB (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  TxCB  *free_cb_ptr;

+

+  //

+  // claim any hanging free CBs

+  //

+  if (AdapterInfo->FreeCBCount <= 1) {

+    CheckCBList (AdapterInfo);

+  }

+

+  //

+  // don't use up the last CB problem if the previous CB that the CU used

+  // becomes the last CB we submit because of the SUSPEND bit we set.

+  // the CU thinks it was never cleared.

+  //

+

+  if (AdapterInfo->FreeCBCount <= 1) {

+    return NULL;

+  }

+

+  BlockIt (AdapterInfo, TRUE);

+  free_cb_ptr                 = AdapterInfo->FreeTxHeadPtr;

+  AdapterInfo->FreeTxHeadPtr  = free_cb_ptr->NextTCBVirtualLinkPtr;

+  --AdapterInfo->FreeCBCount;

+  BlockIt (AdapterInfo, FALSE);

+  return free_cb_ptr;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  cb_ptr                          TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+VOID

+SetFreeCB (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN TxCB              *cb_ptr

+  )

+{

+  //

+  // here we assume cb are returned in the order they are taken out

+  // and we link the newly freed cb at the tail of free cb list

+  //

+  cb_ptr->cb_header.status    = 0;

+  cb_ptr->free_data_ptr       = (UINT64) 0;

+

+  AdapterInfo->FreeTxTailPtr  = cb_ptr;

+  ++AdapterInfo->FreeCBCount;

+  return ;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  ind                             TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT16

+next (

+  IN UINT16 ind

+  )

+{

+  UINT16  Tmp;

+

+  Tmp = (UINT16) (ind + 1);

+  if (Tmp >= (TX_BUFFER_COUNT << 1)) {

+    Tmp = 0;

+  }

+

+  return Tmp;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT16

+CheckCBList (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  TxCB    *Tmp_ptr;

+  UINT16  cnt;

+

+  cnt = 0;

+  while (1) {

+    Tmp_ptr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;

+    if ((Tmp_ptr->cb_header.status & CMD_STATUS_MASK) != 0) {

+      //

+      // check if Q is full

+      //

+      if (next (AdapterInfo->xmit_done_tail) != AdapterInfo->xmit_done_head) {

+        ASSERT (AdapterInfo->xmit_done_tail < TX_BUFFER_COUNT << 1);

+        AdapterInfo->xmit_done[AdapterInfo->xmit_done_tail] = Tmp_ptr->free_data_ptr;

+

+        UnMapIt (

+          AdapterInfo,

+          Tmp_ptr->free_data_ptr,

+          Tmp_ptr->TBDArray[0].buf_len,

+          TO_DEVICE,

+          (UINT64) Tmp_ptr->TBDArray[0].phys_buf_addr

+          );

+

+        AdapterInfo->xmit_done_tail = next (AdapterInfo->xmit_done_tail);

+      }

+

+      SetFreeCB (AdapterInfo, Tmp_ptr);

+    } else {

+      break;

+    }

+  }

+

+  return cnt;

+}

+//

+// Description : Initialize the RFD list list by linking each element together

+//               in a circular list.  The simplified memory model is used.

+//               All data is in the RFD.  The RFDs are linked together and the

+//               last one points back to the first one.  When the current RFD

+//               is processed (frame received), its EL bit is set and the EL

+//               bit in the previous RXFD is cleared.

+//               Allocation done during INIT, this is making linked list.

+//

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+SetupReceiveQueues (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  RxFD    *rx_ptr;

+  RxFD    *tail_ptr;

+  UINT16  Index;

+

+  AdapterInfo->cur_rx_ind = 0;

+  rx_ptr                  = (&AdapterInfo->rx_ring[0]);

+

+  for (Index = 0; Index < AdapterInfo->RxBufCnt; Index++) {

+    rx_ptr[Index].cb_header.status  = 0;

+    rx_ptr[Index].cb_header.command = 0;

+    rx_ptr[Index].RFDSize           = RX_BUFFER_SIZE;

+    rx_ptr[Index].ActualCount       = 0;

+    //

+    // RBDs not used, simple memory model

+    //

+    rx_ptr[Index].rx_buf_addr       = (UINT32) (-1);

+

+    //

+    // RBDs not used, simple memory model

+    //

+    rx_ptr[Index].forwarded = FALSE;

+

+    //

+    // don't use Tmp_ptr if it is beyond the last one

+    //

+    if (Index < AdapterInfo->RxBufCnt - 1) {

+      rx_ptr[Index].cb_header.link = (UINT32) AdapterInfo->rx_phy_addr + ((Index + 1) * sizeof (RxFD));

+    }

+  }

+

+  tail_ptr                    = (&AdapterInfo->rx_ring[AdapterInfo->RxBufCnt - 1]);

+  tail_ptr->cb_header.link    = (UINT32) AdapterInfo->rx_phy_addr;

+

+  //

+  // set the EL bit

+  //

+  tail_ptr->cb_header.command = 0xC000;

+  AdapterInfo->RFDTailPtr = tail_ptr;

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  rx_index                        TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+VOID

+Recycle_RFD (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT16            rx_index

+  )

+{

+  RxFD  *rx_ptr;

+  RxFD  *tail_ptr;

+  //

+  // change the EL bit and change the AdapterInfo->RxTailPtr

+  // rx_ptr is assumed to be the head of the Q

+  // AdapterInfo->rx_forwarded[rx_index] = FALSE;

+  //

+  rx_ptr                    = &AdapterInfo->rx_ring[rx_index];

+  tail_ptr                  = AdapterInfo->RFDTailPtr;

+  //

+  // set el_bit and suspend bit

+  //

+  rx_ptr->cb_header.command = 0xc000;

+  rx_ptr->cb_header.status    = 0;

+  rx_ptr->ActualCount         = 0;

+  rx_ptr->forwarded           = FALSE;

+  AdapterInfo->RFDTailPtr     = rx_ptr;

+  //

+  // resetting the el_bit.

+  //

+  tail_ptr->cb_header.command = 0;

+  //

+  // check the receive unit, fix if there is any problem

+  //

+  return ;

+}

+//

+// Serial EEPROM section.

+//

+//  EEPROM_Ctrl bits.

+//

+#define EE_SHIFT_CLK  0x01  /* EEPROM shift clock. */

+#define EE_CS         0x02  /* EEPROM chip select. */

+#define EE_DI         0x04  /* EEPROM chip data in. */

+#define EE_WRITE_0    0x01

+#define EE_WRITE_1    0x05

+#define EE_DO         0x08  /* EEPROM chip data out. */

+#define EE_ENB        (0x4800 | EE_CS)

+

+//

+// Delay between EEPROM clock transitions.

+// This will actually work with no delay on 33Mhz PCI.

+//

+#define eeprom_delay(nanosec) DelayIt (AdapterInfo, nanosec);

+

+//

+// The EEPROM commands include the alway-set leading bit.

+//

+#define EE_WRITE_CMD  5 // 101b

+#define EE_READ_CMD   6 // 110b

+#define EE_ERASE_CMD  (7 << 6)

+

+VOID

+shift_bits_out (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT16            val,

+  IN UINT8             num_bits

+  )

+/*++

+

+Routine Description:

+

+  TODO: Add function description

+

+Arguments:

+

+  AdapterInfo - TODO: add argument description

+  val         - TODO: add argument description

+  num_bits    - TODO: add argument description

+

+Returns:

+

+  TODO: add return values

+

+--*/

+{

+  INT32   Index;

+  UINT8   Tmp;

+  UINT32  EEAddr;

+

+  EEAddr = AdapterInfo->ioaddr + SCBeeprom;

+

+  for (Index = num_bits; Index >= 0; Index--) {

+    INT16 dataval;

+

+    //

+    // will be 0 or 4

+    //

+    dataval = (INT16) ((val & (1 << Index)) ? EE_DI : 0);

+

+    //

+    // mask off the data_in bit

+    //

+    Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) &~EE_DI);

+    Tmp = (UINT8) (Tmp | dataval);

+    OutByte (AdapterInfo, Tmp, EEAddr);

+    eeprom_delay (100);

+    //

+    // raise the eeprom clock

+    //

+    OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);

+    eeprom_delay (150);

+    //

+    // lower the eeprom clock

+    //

+    OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);

+    eeprom_delay (150);

+  }

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT16

+shift_bits_in (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT8   Tmp;

+  INT32   Index;

+  UINT16  retval;

+  UINT32  EEAddr;

+

+  EEAddr  = AdapterInfo->ioaddr + SCBeeprom;

+

+  retval  = 0;

+  for (Index = 15; Index >= 0; Index--) {

+    //

+    // raise the clock

+    //

+

+    //

+    // mask off the data_in bit

+    //

+    Tmp = InByte (AdapterInfo, EEAddr);

+    OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);

+    eeprom_delay (100);

+    Tmp     = InByte (AdapterInfo, EEAddr);

+    retval  = (UINT16) ((retval << 1) | ((Tmp & EE_DO) ? 1 : 0));

+    //

+    // lower the clock

+    //

+    OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);

+    eeprom_delay (100);

+  }

+

+  return retval;

+}

+

+

+/**

+  This routine sets the EEPROM lockout bit to gain exclusive access to the

+  eeprom. the access bit is the most significant bit in the General Control

+  Register 2 in the SCB space.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+  @retval TRUE                            if it got the access

+  @retval FALSE                           if it fails to get the exclusive access

+

+**/

+BOOLEAN

+E100bSetEepromLockOut (

+  IN NIC_DATA_INSTANCE  *AdapterInfo

+  )

+{

+  UINTN wait;

+  UINT8 tmp;

+

+  if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||

+      (AdapterInfo->RevID >= D102_REVID)) {

+

+    wait = 500;

+

+    while (wait--) {

+

+      tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);

+      tmp |= GCR2_EEPROM_ACCESS_SEMAPHORE;

+      OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);

+

+      DelayIt (AdapterInfo, 50);

+      tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);

+

+      if (tmp & GCR2_EEPROM_ACCESS_SEMAPHORE) {

+        return TRUE;

+      }

+    }

+

+    return FALSE;

+  }

+

+  return TRUE;

+}

+

+

+/**

+  This routine Resets the EEPROM lockout bit to giveup access to the

+  eeprom. the access bit is the most significant bit in the General Control

+  Register 2 in the SCB space.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+  @return None

+

+**/

+VOID

+E100bReSetEepromLockOut (

+  IN NIC_DATA_INSTANCE  *AdapterInfo

+  )

+{

+  UINT8 tmp;

+

+  if ((AdapterInfo->DeviceID == D102_DEVICE_ID) ||

+      (AdapterInfo->RevID >= D102_REVID)) {

+

+    tmp = InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2);

+    tmp &= ~(GCR2_EEPROM_ACCESS_SEMAPHORE);

+    OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2);

+

+    DelayIt (AdapterInfo, 50);

+  }

+}

+

+

+/**

+  Using the NIC data structure information, read the EEPROM to get a Word of data for the MAC address.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+  @param  Location                        Word offset into the MAC address to read.

+  @param  AddrLen                         Number of bits of address length.

+

+  @retval RetVal                          The word read from the EEPROM.

+

+**/

+UINT16

+E100bReadEeprom (

+  IN NIC_DATA_INSTANCE  *AdapterInfo,

+  IN INT32              Location,

+  IN UINT8              AddrLen

+  )

+{

+  UINT16  RetVal;

+  UINT8   Tmp;

+

+  UINT32  EEAddr;

+  UINT16  ReadCmd;

+

+  EEAddr  = AdapterInfo->ioaddr + SCBeeprom;

+  ReadCmd = (UINT16) (Location | (EE_READ_CMD << AddrLen));

+

+  RetVal  = 0;

+

+  //

+  // get exclusive access to the eeprom first!

+  //

+  E100bSetEepromLockOut (AdapterInfo);

+

+  //

+  // eeprom control reg bits: x,x,x,x,DO,DI,CS,SK

+  // to write the opcode+data value out one bit at a time in DI starting at msb

+  // and then out a 1 to sk, wait, out 0 to SK and wait

+  // repeat this for all the bits to be written

+  //

+

+  //

+  // 11110010b

+  //

+  Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);

+  OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);

+

+  //

+  // 3 for the read opcode 110b

+  //

+  shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + AddrLen));

+

+  //

+  // read the eeprom word one bit at a time

+  //

+  RetVal = shift_bits_in (AdapterInfo);

+

+  //

+  // Terminate the EEPROM access and leave eeprom in a clean state.

+  //

+  Tmp = InByte (AdapterInfo, EEAddr);

+  Tmp &= ~(EE_CS | EE_DI);

+  OutByte (AdapterInfo, Tmp, EEAddr);

+

+  //

+  // raise the clock and lower the eeprom shift clock

+  //

+  OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);

+  eeprom_delay (100);

+

+  OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);

+  eeprom_delay (100);

+

+  //

+  // giveup access to the eeprom

+  //

+  E100bReSetEepromLockOut (AdapterInfo);

+

+  return RetVal;

+}

+

+

+/**

+  Using the NIC data structure information, read the EEPROM to determine how many bits of address length

+  this EEPROM is in Words.

+

+  @param  AdapterInfo                     Pointer to the NIC data structure

+                                          information which the UNDI driver is

+                                          layering on..

+

+  @retval RetVal                          The word read from the EEPROM.

+

+**/

+UINT8

+E100bGetEepromAddrLen (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT8   Tmp;

+  UINT8   AddrLen;

+  UINT32  EEAddr;

+  //

+  // assume 64word eeprom (so,6 bits of address_length)

+  //

+  UINT16  ReadCmd;

+

+  EEAddr  = AdapterInfo->ioaddr + SCBeeprom;

+  ReadCmd = (EE_READ_CMD << 6);

+

+  //

+  // get exclusive access to the eeprom first!

+  //

+  E100bSetEepromLockOut (AdapterInfo);

+

+  //

+  // address we are trying to read is 0

+  // eeprom control reg bits: x,x,x,x,DO,,DI,,CS,SK

+  // to write the opcode+data value out one bit at a time in DI starting at msb

+  // and then out a 1 to sk, wait, out 0 to SK and wait

+  // repeat this for all the bits to be written

+  //

+  Tmp = (UINT8) (InByte (AdapterInfo, EEAddr) & 0xF2);

+

+  //

+  // enable eeprom access

+  //

+  OutByte (AdapterInfo, (UINT8) (Tmp | EE_CS), EEAddr);

+

+  //

+  // 3 for opcode, 6 for the default address len

+  //

+  shift_bits_out (AdapterInfo, ReadCmd, (UINT8) (3 + 6));

+

+  //

+  // (in case of a 64 word eeprom).

+  // read the "dummy zero" from EE_DO to say that the address we wrote

+  // (six 0s) is accepted, write more zeros (until 8) to get a "dummy zero"

+  //

+

+  //

+  // assume the smallest

+  //

+  AddrLen = 6;

+  Tmp     = InByte (AdapterInfo, EEAddr);

+  while ((AddrLen < 8) && ((Tmp & EE_DO) != 0)) {

+    OutByte (AdapterInfo, (UINT8) (Tmp &~EE_DI), EEAddr);

+    eeprom_delay (100);

+

+    //

+    // raise the eeprom clock

+    //

+    OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);

+    eeprom_delay (150);

+

+    //

+    // lower the eeprom clock

+    //

+    OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);

+    eeprom_delay (150);

+    Tmp = InByte (AdapterInfo, EEAddr);

+    AddrLen++;

+  }

+

+  //

+  // read the eeprom word, even though we don't need this

+  //

+  shift_bits_in (AdapterInfo);

+

+  //

+  // Terminate the EEPROM access.

+  //

+  Tmp = InByte (AdapterInfo, EEAddr);

+  Tmp &= ~(EE_CS | EE_DI);

+  OutByte (AdapterInfo, Tmp, EEAddr);

+

+  //

+  // raise the clock and lower the eeprom shift clock

+  //

+  OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr);

+  eeprom_delay (100);

+

+  OutByte (AdapterInfo, (UINT8) (Tmp &~EE_SHIFT_CLK), EEAddr);

+  eeprom_delay (100);

+

+  //

+  // giveup access to the eeprom!

+  //

+  E100bReSetEepromLockOut (AdapterInfo);

+

+  return AddrLen;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  DBaddr                          TODO: add argument description

+  @param  DBsize                          TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINTN

+E100bStatistics (

+  NIC_DATA_INSTANCE *AdapterInfo,

+  UINT64            DBaddr,

+  UINT16            DBsize

+  )

+{

+  PXE_DB_STATISTICS db;

+  //

+  // wait upto one second (each wait is 100 micro s)

+  //

+  UINT32            Wait;

+  Wait = 10000;

+  wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+

+  //

+  // Clear statistics done marker.

+  //

+  AdapterInfo->statistics->done_marker = 0;

+

+  //

+  // Issue statistics dump (or dump w/ reset) command.

+  //

+  OutByte (

+    AdapterInfo,

+    (UINT8) (DBsize ? CU_SHOWSTATS : CU_DUMPSTATS),

+    (UINT32) (AdapterInfo->ioaddr + SCBCmd)

+    );

+

+  //

+  // Wait for command to complete.

+  //

+  // zero the db here just to chew up a little more time.

+  //

+

+  ZeroMem ((VOID *) &db, sizeof db);

+

+  while (Wait != 0) {

+    //

+    // Wait a bit before checking.

+    //

+

+    DelayIt (AdapterInfo, 100);

+

+    //

+    // Look for done marker at end of statistics.

+    //

+

+    switch (AdapterInfo->statistics->done_marker) {

+    case 0xA005:

+    case 0xA007:

+      break;

+

+    default:

+      Wait--;

+      continue;

+    }

+

+    //

+    // if we did not "continue" from the above switch, we are done,

+    //

+    break;

+  }

+

+  //

+  // If this is a reset, we are out of here!

+  //

+  if (DBsize == 0) {

+    return PXE_STATCODE_SUCCESS;

+  }

+

+  //

+  // Convert NIC statistics counter format to EFI/UNDI

+  // specification statistics counter format.

+  //

+

+  //

+  //                54 3210 fedc ba98 7654 3210

+  // db.Supported = 01 0000 0100 1101 0001 0111;

+  //

+  db.Supported = 0x104D17;

+

+  //

+  // Statistics from the NIC

+  //

+

+  db.Data[0x01] = AdapterInfo->statistics->rx_good_frames;

+

+  db.Data[0x02] = AdapterInfo->statistics->rx_runt_errs;

+

+  db.Data[0x08] = AdapterInfo->statistics->rx_crc_errs +

+                  AdapterInfo->statistics->rx_align_errs;

+

+  db.Data[0x04] = db.Data[0x02] +

+                  db.Data[0x08] +

+                  AdapterInfo->statistics->rx_resource_errs +

+                  AdapterInfo->statistics->rx_overrun_errs;

+

+  db.Data[0x00] = db.Data[0x01] + db.Data[0x04];

+

+  db.Data[0x0B] = AdapterInfo->statistics->tx_good_frames;

+

+  db.Data[0x0E] = AdapterInfo->statistics->tx_coll16_errs +

+    AdapterInfo->statistics->tx_late_colls +

+    AdapterInfo->statistics->tx_underruns +

+    AdapterInfo->statistics->tx_one_colls +

+    AdapterInfo->statistics->tx_multi_colls;

+

+  db.Data[0x14] = AdapterInfo->statistics->tx_total_colls;

+

+  db.Data[0x0A] = db.Data[0x0B] +

+                  db.Data[0x0E] +

+                  AdapterInfo->statistics->tx_lost_carrier;

+

+  if (DBsize > sizeof db) {

+    DBsize = (UINT16) sizeof (db);

+  }

+

+  CopyMem ((VOID *) (UINTN) DBaddr, (VOID *) &db, (UINTN) DBsize);

+

+  return PXE_STATCODE_SUCCESS;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+  @param  OpFlags                         TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINTN

+E100bReset (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN INT32             OpFlags

+  )

+{

+

+  UINT16  save_filter;

+  //

+  // disable the interrupts

+  //

+  OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);

+

+  //

+  // wait for the tx queue to complete

+  //

+  CheckCBList (AdapterInfo);

+

+  XmitWaitForCompletion (AdapterInfo);

+

+  if (AdapterInfo->Receive_Started) {

+    StopRU (AdapterInfo);

+  }

+

+  InitializeChip (AdapterInfo);

+

+  //

+  // check the opflags and restart receive filters

+  //

+  if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) {

+

+    save_filter = AdapterInfo->Rx_Filter;

+    //

+    // if we give the filter same as Rx_Filter,

+    // this routine will not set mcast list (it thinks there is no change)

+    // to force it, we will reset that flag in the Rx_Filter

+    //

+    AdapterInfo->Rx_Filter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);

+    E100bSetfilter (AdapterInfo, save_filter, (UINT64) 0, (UINT32) 0);

+  }

+

+  if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) {

+    //

+    // disable the interrupts

+    //

+    AdapterInfo->int_mask = 0;

+  }

+  //

+  // else leave the interrupt in the pre-set state!!!

+  //

+  E100bSetInterruptState (AdapterInfo);

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINTN

+E100bShutdown (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  //

+  // disable the interrupts

+  //

+  OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);

+

+  //

+  // stop the receive unit

+  //

+  if (AdapterInfo->Receive_Started) {

+    StopRU (AdapterInfo);

+  }

+

+  //

+  // wait for the tx queue to complete

+  //

+  CheckCBList (AdapterInfo);

+  if (AdapterInfo->FreeCBCount != AdapterInfo->TxBufCnt) {

+    wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+  }

+

+  //

+  // we do not want to reset the phy, it takes a long time to renegotiate the

+  // link after that (3-4 seconds)

+  //

+  InitializeChip (AdapterInfo);

+  SelectiveReset (AdapterInfo);

+  return 0;

+}

+

+

+/**

+  This routine will write a value to the specified MII register

+  of an external MDI compliant device (e.g. PHY 100).  The command will

+  execute in polled mode.

+

+  @param  AdapterInfo                     pointer to the structure that contains

+                                          the NIC's context.

+  @param  RegAddress                      The MII register that we are writing to

+  @param  PhyAddress                      The MDI address of the Phy component.

+  @param  DataValue                       The value that we are writing to the MII

+                                          register.

+

+  @return nothing

+

+**/

+VOID

+MdiWrite (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT8             RegAddress,

+  IN UINT8             PhyAddress,

+  IN UINT16            DataValue

+  )

+{

+  UINT32  WriteCommand;

+

+  WriteCommand = ((UINT32) DataValue) |

+                 ((UINT32)(RegAddress << 16)) |

+                 ((UINT32)(PhyAddress << 21)) |

+                 ((UINT32)(MDI_WRITE << 26));

+

+  //

+  // Issue the write command to the MDI control register.

+  //

+  OutLong (AdapterInfo, WriteCommand, AdapterInfo->ioaddr + SCBCtrlMDI);

+

+  //

+  // wait 20usec before checking status

+  //

+  DelayIt (AdapterInfo, 20);

+

+  //

+  // poll for the mdi write to complete

+  while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &

+                    MDI_PHY_READY) == 0){

+    DelayIt (AdapterInfo, 20);

+  }

+}

+

+

+/**

+  This routine will read a value from the specified MII register

+  of an external MDI compliant device (e.g. PHY 100), and return

+  it to the calling routine.  The command will execute in polled mode.

+

+  @param  AdapterInfo                     pointer to the structure that contains

+                                          the NIC's context.

+  @param  RegAddress                      The MII register that we are reading from

+  @param  PhyAddress                      The MDI address of the Phy component.

+  @param  DataValue                       pointer to the value that we read from

+                                          the MII register.

+

+

+**/

+VOID

+MdiRead (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT8             RegAddress,

+  IN UINT8             PhyAddress,

+  IN OUT UINT16        *DataValue

+  )

+{

+  UINT32  ReadCommand;

+

+  ReadCommand = ((UINT32) (RegAddress << 16)) |

+                ((UINT32) (PhyAddress << 21)) |

+                ((UINT32) (MDI_READ << 26));

+

+  //

+  // Issue the read command to the MDI control register.

+  //

+  OutLong (AdapterInfo, ReadCommand, AdapterInfo->ioaddr + SCBCtrlMDI);

+

+  //

+  // wait 20usec before checking status

+  //

+  DelayIt (AdapterInfo, 20);

+

+  //

+  // poll for the mdi read to complete

+  //

+  while ((InLong (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI) &

+          MDI_PHY_READY) == 0) {

+    DelayIt (AdapterInfo, 20);

+

+  }

+

+  *DataValue = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCtrlMDI);

+}

+

+

+/**

+  This routine will reset the PHY that the adapter is currently

+  configured to use.

+

+  @param  AdapterInfo                     pointer to the structure that contains

+                                          the NIC's context.

+

+

+**/

+VOID

+PhyReset (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16  MdiControlReg;

+

+  MdiControlReg = (MDI_CR_AUTO_SELECT |

+                  MDI_CR_RESTART_AUTO_NEG |

+                  MDI_CR_RESET);

+

+  //

+  // Write the MDI control register with our new Phy configuration

+  //

+  MdiWrite (

+    AdapterInfo,

+    MDI_CONTROL_REG,

+    AdapterInfo->PhyAddress,

+    MdiControlReg

+    );

+

+  return ;

+}

+

+

+/**

+  This routine will detect what phy we are using, set the line

+  speed, FDX or HDX, and configure the phy if necessary.

+  The following combinations are supported:

+  - TX or T4 PHY alone at PHY address 1

+  - T4 or TX PHY at address 1 and MII PHY at address 0

+  - 82503 alone (10Base-T mode, no full duplex support)

+  - 82503 and MII PHY (TX or T4) at address 0

+  The sequence / priority of detection is as follows:

+  - PHY 1 with cable termination

+  - PHY 0 with cable termination

+  - PHY 1 (if found) without cable termination

+  - 503 interface

+  Additionally auto-negotiation capable (NWAY) and parallel

+  detection PHYs are supported. The flow-chart is described in

+  the 82557 software writer's manual.

+  NOTE:  1.  All PHY MDI registers are read in polled mode.

+  2.  The routines assume that the 82557 has been RESET and we have

+  obtained the virtual memory address of the CSR.

+  3.  PhyDetect will not RESET the PHY.

+  4.  If FORCEFDX is set, SPEED should also be set. The driver will

+  check the values for inconsistency with the detected PHY

+  technology.

+  5.  PHY 1 (the PHY on the adapter) may have an address in the range

+  1 through 31 inclusive. The driver will accept addresses in

+  this range.

+  6.  Driver ignores FORCEFDX and SPEED overrides if a 503 interface

+  is detected.

+

+  @param  AdapterInfo                     pointer to the structure that contains

+                                          the NIC's context.

+

+  @retval TRUE                            If a Phy was detected, and configured

+                                          correctly.

+  @retval FALSE                           If a valid phy could not be detected and

+                                          configured.

+

+**/

+BOOLEAN

+PhyDetect (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16  *eedata;

+  UINT16  MdiControlReg;

+  UINT16  MdiStatusReg;

+  BOOLEAN FoundPhy1;

+  UINT8   ReNegotiateTime;

+

+  eedata          = (UINT16 *) (&AdapterInfo->NVData[0]);

+

+  FoundPhy1       = FALSE;

+  ReNegotiateTime = 35;

+  //

+  // EEPROM word [6] contains the Primary PHY record in which the least 3 bits

+  // indicate the PHY address

+  // and word [7] contains the secondary PHY record

+  //

+  AdapterInfo->PhyRecord[0] = eedata[6];

+  AdapterInfo->PhyRecord[1] = eedata[7];

+  AdapterInfo->PhyAddress   = (UINT8) (AdapterInfo->PhyRecord[0] & 7);

+

+  //

+  // Check for a phy address over-ride of 32 which indicates force use of 82503

+  // not detecting the link in this case

+  //

+  if (AdapterInfo->PhyAddress == 32) {

+    //

+    // 503 interface over-ride

+    // Record the current speed and duplex.  We will be in half duplex

+    // mode unless the user used the force full duplex over-ride.

+    //

+    AdapterInfo->LinkSpeed = 10;

+    return (TRUE);

+  }

+

+  //

+  // If the Phy Address is between 1-31 then we must first look for phy 1,

+  // at that address.

+  //

+  if ((AdapterInfo->PhyAddress > 0) && (AdapterInfo->PhyAddress < 32)) {

+

+    //

+    // Read the MDI control and status registers at phy 1

+    // and check if we found a valid phy

+    //

+    MdiRead (

+      AdapterInfo,

+      MDI_CONTROL_REG,

+      AdapterInfo->PhyAddress,

+      &MdiControlReg

+      );

+

+    MdiRead (

+      AdapterInfo,

+      MDI_STATUS_REG,

+      AdapterInfo->PhyAddress,

+      &MdiStatusReg

+      );

+

+    if (!((MdiControlReg == 0xffff) ||

+          ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {

+

+      //

+      // we have a valid phy1

+      // Read the status register again because of sticky bits

+      //

+      FoundPhy1 = TRUE;

+      MdiRead (

+        AdapterInfo,

+        MDI_STATUS_REG,

+        AdapterInfo->PhyAddress,

+        &MdiStatusReg

+        );

+

+      //

+      // If there is a valid link then use this Phy.

+      //

+      if (MdiStatusReg & MDI_SR_LINK_STATUS) {

+        return (SetupPhy(AdapterInfo));

+      }

+    }

+  }

+

+  //

+  // Next try to detect a PHY at address 0x00 because there was no Phy 1,

+  // or Phy 1 didn't have link, or we had a phy 0 over-ride

+  //

+

+  //

+  // Read the MDI control and status registers at phy 0

+  //

+  MdiRead (AdapterInfo, MDI_CONTROL_REG, 0, &MdiControlReg);

+  MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);

+

+  //

+  // check if we found a valid phy 0

+  //

+  if (((MdiControlReg == 0xffff) ||

+       ((MdiStatusReg == 0) && (MdiControlReg == 0)))) {

+

+    //

+    // we don't have a valid phy at address 0

+    // if phy address was forced to 0, then error out because we

+    // didn't find a phy at that address

+    //

+    if (AdapterInfo->PhyAddress == 0x0000) {

+      return (FALSE);

+    } else {

+      //

+      // at this point phy1 does not have link and there is no phy 0 at all

+      // if we are forced to detect the cable, error out here!

+      //

+      if (AdapterInfo->CableDetect != 0) {

+        return FALSE;

+

+      }

+

+      if (FoundPhy1) {

+        //

+        // no phy 0, but there is a phy 1 (no link I guess), so use phy 1

+        //

+        return SetupPhy (AdapterInfo);

+      } else {

+        //

+        // didn't find phy 0 or phy 1, so assume a 503 interface

+        //

+        AdapterInfo->PhyAddress = 32;

+

+        //

+        // Record the current speed and duplex.  We'll be in half duplex

+        // mode unless the user used the force full duplex over-ride.

+        //

+        AdapterInfo->LinkSpeed = 10;

+        return (TRUE);

+      }

+    }

+  } else {

+    //

+    // We have a valid phy at address 0.  If phy 0 has a link then we use

+    // phy 0.  If Phy 0 doesn't have a link then we use Phy 1 (no link)

+    // if phy 1 is present, or phy 0 if phy 1 is not present

+    // If phy 1 was present, then we must isolate phy 1 before we enable

+    // phy 0 to see if Phy 0 has a link.

+    //

+    if (FoundPhy1) {

+      //

+      // isolate phy 1

+      //

+      MdiWrite (

+        AdapterInfo,

+        MDI_CONTROL_REG,

+        AdapterInfo->PhyAddress,

+        MDI_CR_ISOLATE

+        );

+

+      //

+      // wait 100 microseconds for the phy to isolate.

+      //

+      DelayIt (AdapterInfo, 100);

+    }

+

+    //

+    // Since this Phy is at address 0, we must enable it.  So clear

+    // the isolate bit, and set the auto-speed select bit

+    //

+    MdiWrite (

+      AdapterInfo,

+      MDI_CONTROL_REG,

+      0,

+      MDI_CR_AUTO_SELECT

+      );

+

+    //

+    // wait 100 microseconds for the phy to be enabled.

+    //

+    DelayIt (AdapterInfo, 100);

+

+    //

+    // restart the auto-negotion process

+    //

+    MdiWrite (

+      AdapterInfo,

+      MDI_CONTROL_REG,

+      0,

+      MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT

+      );

+

+    //

+    // wait no more than 3.5 seconds for auto-negotiation to complete

+    //

+    while (ReNegotiateTime) {

+      //

+      // Read the status register twice because of sticky bits

+      //

+      MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);

+      MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);

+

+      if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) {

+        break;

+      }

+

+      DelayIt (AdapterInfo, 100);

+      ReNegotiateTime--;

+    }

+

+    //

+    // Read the status register again because of sticky bits

+    //

+    MdiRead (AdapterInfo, MDI_STATUS_REG, 0, &MdiStatusReg);

+

+    //

+    // If the link was not set

+    //

+    if ((MdiStatusReg & MDI_SR_LINK_STATUS) == 0) {

+      //

+      // PHY1 does not have a link and phy 0 does not have a link

+      // do not proceed if we need to detect the link!

+      //

+      if (AdapterInfo->CableDetect != 0) {

+        return FALSE;

+      }

+

+      //

+      // the link wasn't set, so use phy 1 if phy 1 was present

+      //

+      if (FoundPhy1) {

+        //

+        // isolate phy 0

+        //

+        MdiWrite (AdapterInfo, MDI_CONTROL_REG, 0, MDI_CR_ISOLATE);

+

+        //

+        // wait 100 microseconds for the phy to isolate.

+        //

+        DelayIt (AdapterInfo, 100);

+

+        //

+        // Now re-enable PHY 1

+        //

+        MdiWrite (

+          AdapterInfo,

+          MDI_CONTROL_REG,

+          AdapterInfo->PhyAddress,

+          MDI_CR_AUTO_SELECT

+          );

+

+        //

+        // wait 100 microseconds for the phy to be enabled

+        //

+        DelayIt (AdapterInfo, 100);

+

+        //

+        // restart the auto-negotion process

+        //

+        MdiWrite (

+          AdapterInfo,

+          MDI_CONTROL_REG,

+          AdapterInfo->PhyAddress,

+          MDI_CR_RESTART_AUTO_NEG | MDI_CR_AUTO_SELECT

+          );

+

+        //

+        // Don't wait for it to complete (we didn't have link earlier)

+        //

+        return (SetupPhy (AdapterInfo));

+      }

+    }

+

+    //

+    // Definitely using Phy 0

+    //

+    AdapterInfo->PhyAddress = 0;

+    return (SetupPhy(AdapterInfo));

+  }

+}

+

+

+/**

+  This routine will setup phy 1 or phy 0 so that it is configured

+  to match a speed and duplex over-ride option.  If speed or

+  duplex mode is not explicitly specified in the registry, the

+  driver will skip the speed and duplex over-ride code, and

+  assume the adapter is automatically setting the line speed, and

+  the duplex mode.  At the end of this routine, any truly Phy

+  specific code will be executed (each Phy has its own quirks,

+  and some require that certain special bits are set).

+  NOTE:  The driver assumes that SPEED and FORCEFDX are specified at the

+  same time. If FORCEDPX is set without speed being set, the driver

+  will encouter a fatal error and log a message into the event viewer.

+

+  @param  AdapterInfo                     pointer to the structure that contains

+                                          the NIC's context.

+

+  @retval TRUE                            If the phy could be configured correctly

+  @retval FALSE                           If the phy couldn't be configured

+                                          correctly, because an unsupported

+                                          over-ride option was used

+

+**/

+BOOLEAN

+SetupPhy (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16  MdiControlReg;

+  UINT16  MdiStatusReg;

+  UINT16  MdiIdLowReg;

+  UINT16  MdiIdHighReg;

+  UINT16  MdiMiscReg;

+  UINT32  PhyId;

+  BOOLEAN ForcePhySetting;

+

+  ForcePhySetting = FALSE;

+

+  //

+  // If we are NOT forcing a setting for line speed or full duplex, then

+  // we won't force a link setting, and we'll jump down to the phy

+  // specific code.

+  //

+  if (((AdapterInfo->LinkSpeedReq) || (AdapterInfo->DuplexReq))) {

+    //

+    // Find out what kind of technology this Phy is capable of.

+    //

+    MdiRead (

+      AdapterInfo,

+      MDI_STATUS_REG,

+      AdapterInfo->PhyAddress,

+      &MdiStatusReg

+      );

+

+    //

+    // Read the MDI control register at our phy

+    //

+    MdiRead (

+      AdapterInfo,

+      MDI_CONTROL_REG,

+      AdapterInfo->PhyAddress,

+      &MdiControlReg

+      );

+

+    //

+    // Now check the validity of our forced option.  If the force option is

+    // valid, then force the setting.  If the force option is not valid,

+    // we'll set a flag indicating that we should error out.

+    //

+

+    //

+    // If speed is forced to 10mb

+    //

+    if (AdapterInfo->LinkSpeedReq == 10) {

+      //

+      // If half duplex is forced

+      //

+      if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {

+        if (MdiStatusReg & MDI_SR_10T_HALF_DPX) {

+

+          MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);

+          ForcePhySetting = TRUE;

+        }

+      } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {

+

+        //

+        // If full duplex is forced

+        //

+        if (MdiStatusReg & MDI_SR_10T_FULL_DPX) {

+

+          MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);

+          MdiControlReg |= MDI_CR_FULL_HALF;

+          ForcePhySetting = TRUE;

+        }

+      } else {

+        //

+        // If auto duplex (we actually set phy to 1/2)

+        //

+        if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX)) {

+

+          MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);

+          ForcePhySetting = TRUE;

+        }

+      }

+    }

+

+    //

+    // If speed is forced to 100mb

+    //

+    else if (AdapterInfo->LinkSpeedReq == 100) {

+      //

+      // If half duplex is forced

+      //

+      if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) != 0) {

+        if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {

+

+          MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);

+          MdiControlReg |= MDI_CR_10_100;

+          ForcePhySetting = TRUE;

+        }

+      } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) != 0) {

+        //

+        // If full duplex is forced

+        //

+        if (MdiStatusReg & MDI_SR_TX_FULL_DPX) {

+          MdiControlReg &= ~MDI_CR_AUTO_SELECT;

+          MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);

+          ForcePhySetting = TRUE;

+        }

+      } else {

+        //

+        // If auto duplex (we set phy to 1/2)

+        //

+        if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) {

+

+          MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);

+          MdiControlReg |= MDI_CR_10_100;

+          ForcePhySetting = TRUE;

+        }

+      }

+    }

+

+    if (!ForcePhySetting) {

+      return (FALSE);

+    }

+

+    //

+    // Write the MDI control register with our new Phy configuration

+    //

+    MdiWrite (

+      AdapterInfo,

+      MDI_CONTROL_REG,

+      AdapterInfo->PhyAddress,

+      MdiControlReg

+      );

+

+    //

+    // wait 100 milliseconds for auto-negotiation to complete

+    //

+    DelayIt (AdapterInfo, 100);

+  }

+

+  //

+  // Find out specifically what Phy this is.  We do this because for certain

+  // phys there are specific bits that must be set so that the phy and the

+  // 82557 work together properly.

+  //

+

+  MdiRead (

+    AdapterInfo,

+    PHY_ID_REG_1,

+    AdapterInfo->PhyAddress,

+    &MdiIdLowReg

+    );

+  MdiRead (

+    AdapterInfo,

+    PHY_ID_REG_2,

+    AdapterInfo->PhyAddress,

+    &MdiIdHighReg

+    );

+

+  PhyId = ((UINT32) MdiIdLowReg | ((UINT32) MdiIdHighReg << 16));

+

+  //

+  // And out the revsion field of the Phy ID so that we'll be able to detect

+  // future revs of the same Phy.

+  //

+  PhyId &= PHY_MODEL_REV_ID_MASK;

+

+  //

+  // Handle the National TX

+  //

+  if (PhyId == PHY_NSC_TX) {

+

+    MdiRead (

+      AdapterInfo,

+      NSC_CONG_CONTROL_REG,

+      AdapterInfo->PhyAddress,

+      &MdiMiscReg

+      );

+

+    MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);

+

+    MdiWrite (

+      AdapterInfo,

+      NSC_CONG_CONTROL_REG,

+      AdapterInfo->PhyAddress,

+      MdiMiscReg

+      );

+  }

+

+  FindPhySpeedAndDpx (AdapterInfo, PhyId);

+

+  //

+  // We put a hardware fix on to our adapters to work-around the PHY_100 errata

+  // described below.  The following code is only compiled in, if we wanted

+  // to attempt a software workaround to the PHY_100 A/B step problem.

+  //

+

+  return (TRUE);

+}

+

+

+/**

+  This routine will figure out what line speed and duplex mode

+  the PHY is currently using.

+

+  @param  AdapterInfo                     pointer to the structure that contains

+                                          the NIC's context.

+  @param  PhyId                           The ID of the PHY in question.

+

+  @return NOTHING

+

+**/

+VOID

+FindPhySpeedAndDpx (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT32            PhyId

+  )

+{

+  UINT16  MdiStatusReg;

+  UINT16  MdiMiscReg;

+  UINT16  MdiOwnAdReg;

+  UINT16  MdiLinkPartnerAdReg;

+

+  //

+  // If there was a speed and/or duplex override, then set our current

+  // value accordingly

+  //

+  AdapterInfo->LinkSpeed  = AdapterInfo->LinkSpeedReq;

+  AdapterInfo->Duplex = (UINT8) ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) ?

+                        FULL_DUPLEX : HALF_DUPLEX);

+

+  //

+  // If speed and duplex were forced, then we know our current settings, so

+  // we'll just return.  Otherwise, we'll need to figure out what NWAY set

+  // us to.

+  //

+  if (AdapterInfo->LinkSpeed && AdapterInfo->Duplex) {

+    return ;

+

+  }

+  //

+  // If we didn't have a valid link, then we'll assume that our current

+  // speed is 10mb half-duplex.

+  //

+

+  //

+  // Read the status register twice because of sticky bits

+  //

+  MdiRead (

+    AdapterInfo,

+    MDI_STATUS_REG,

+    AdapterInfo->PhyAddress,

+    &MdiStatusReg

+    );

+  MdiRead (

+    AdapterInfo,

+    MDI_STATUS_REG,

+    AdapterInfo->PhyAddress,

+    &MdiStatusReg

+    );

+

+  //

+  // If there wasn't a valid link then use default speed & duplex

+  //

+  if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) {

+

+    AdapterInfo->LinkSpeed  = 10;

+    AdapterInfo->Duplex     = HALF_DUPLEX;

+    return ;

+  }

+

+  //

+  // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits

+  // 1 and 0 of extended register 0, to get the current speed and duplex

+  // settings.

+  //

+  if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID)) {

+    //

+    // Read extended register 0

+    //

+    MdiRead (

+      AdapterInfo,

+      EXTENDED_REG_0,

+      AdapterInfo->PhyAddress,

+      &MdiMiscReg

+      );

+

+    //

+    // Get current speed setting

+    //

+    if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) {

+      AdapterInfo->LinkSpeed = 100;

+    } else {

+      AdapterInfo->LinkSpeed = 10;

+    }

+

+    //

+    // Get current duplex setting -- if bit is set then FDX is enabled

+    //

+    if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) {

+      AdapterInfo->Duplex = FULL_DUPLEX;

+    } else {

+      AdapterInfo->Duplex = HALF_DUPLEX;

+    }

+

+    return ;

+  }

+  //

+  // Read our link partner's advertisement register

+  //

+  MdiRead (

+    AdapterInfo,

+    AUTO_NEG_LINK_PARTNER_REG,

+    AdapterInfo->PhyAddress,

+    &MdiLinkPartnerAdReg

+    );

+

+  //

+  // See if Auto-Negotiation was complete (bit 5, reg 1)

+  //

+  MdiRead (

+    AdapterInfo,

+    MDI_STATUS_REG,

+    AdapterInfo->PhyAddress,

+    &MdiStatusReg

+    );

+

+  //

+  // If a True NWAY connection was made, then we can detect speed/duplex by

+  // ANDing our adapter's advertised abilities with our link partner's

+  // advertised ablilities, and then assuming that the highest common

+  // denominator was chosed by NWAY.

+  //

+  if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&

+      (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) {

+

+    //

+    // Read our advertisement register

+    //

+    MdiRead (

+      AdapterInfo,

+      AUTO_NEG_ADVERTISE_REG,

+      AdapterInfo->PhyAddress,

+      &MdiOwnAdReg

+      );

+

+    //

+    // AND the two advertisement registers together, and get rid of any

+    // extraneous bits.

+    //

+    MdiOwnAdReg = (UINT16) (MdiOwnAdReg & (MdiLinkPartnerAdReg & NWAY_LP_ABILITY));

+

+    //

+    // Get speed setting

+    //

+    if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE)) {

+      AdapterInfo->LinkSpeed = 100;

+    } else {

+      AdapterInfo->LinkSpeed = 10;

+    }

+

+    //

+    // Get duplex setting -- use priority resolution algorithm

+    //

+    if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) {

+      AdapterInfo->Duplex = HALF_DUPLEX;

+      return ;

+    } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) {

+      AdapterInfo->Duplex = FULL_DUPLEX;

+      return ;

+    } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) {

+      AdapterInfo->Duplex = HALF_DUPLEX;

+      return ;

+    } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) {

+      AdapterInfo->Duplex = FULL_DUPLEX;

+      return ;

+    } else {

+      AdapterInfo->Duplex = HALF_DUPLEX;

+      return ;

+    }

+  }

+

+  //

+  // If we are connected to a dumb (non-NWAY) repeater or hub, and the line

+  // speed was determined automatically by parallel detection, then we have

+  // no way of knowing exactly what speed the PHY is set to unless that PHY

+  // has a propietary register which indicates speed in this situation.  The

+  // NSC TX PHY does have such a register.  Also, since NWAY didn't establish

+  // the connection, the duplex setting should HALF duplex.

+  //

+  AdapterInfo->Duplex = HALF_DUPLEX;

+

+  if (PhyId == PHY_NSC_TX) {

+    //

+    // Read register 25 to get the SPEED_10 bit

+    //

+    MdiRead (

+      AdapterInfo,

+      NSC_SPEED_IND_REG,

+      AdapterInfo->PhyAddress,

+      &MdiMiscReg

+      );

+

+    //

+    // If bit 6 was set then we're at 10mb

+    //

+    if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) {

+      AdapterInfo->LinkSpeed = 10;

+    } else {

+      AdapterInfo->LinkSpeed = 100;

+    }

+  }

+

+  //

+  // If we don't know what line speed we are set at, then we'll default to

+  // 10mbs

+  //

+  else {

+    AdapterInfo->LinkSpeed = 10;

+  }

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+VOID

+XmitWaitForCompletion (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  TxCB  *TxPtr;

+

+  if (AdapterInfo->FreeCBCount == AdapterInfo->TxBufCnt) {

+    return ;

+  }

+

+  //

+  // used xmit cb list starts right after the free tail (ends before the

+  // free head ptr)

+  //

+  TxPtr = AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr;

+  while (TxPtr != AdapterInfo->FreeTxHeadPtr) {

+    CommandWaitForCompletion (TxPtr, AdapterInfo);

+    SetFreeCB (AdapterInfo, TxPtr);

+    TxPtr = TxPtr->NextTCBVirtualLinkPtr;

+  }

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  cmd_ptr                         TODO: add argument description

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+INT8

+CommandWaitForCompletion (

+  TxCB              *cmd_ptr,

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  INT16 wait;

+  wait = 5000;

+  while ((cmd_ptr->cb_header.status == 0) && (--wait > 0)) {

+    DelayIt (AdapterInfo, 10);

+  }

+

+  if (cmd_ptr->cb_header.status == 0) {

+    return -1;

+  }

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+INT8

+SoftwareReset (

+  NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT8   tco_stat;

+  UINT16  wait;

+

+  tco_stat = 0;

+

+  //

+  // Reset the chip: stop Tx and Rx processes and clear counters.

+  // This takes less than 10usec and will easily finish before the next

+  // action.

+  //

+

+  OutLong (AdapterInfo, PORT_RESET, AdapterInfo->ioaddr + SCBPort);

+  //

+  // wait for 5 milli seconds here!

+  //

+  DelayIt (AdapterInfo, 5000);

+  //

+  // TCO Errata work around for 559s only

+  // -----------------------------------------------------------------------------------

+  // TCO Workaround Code

+  //  haifa workaround

+  // -----------------------------------------------------------------------------------

+  //    1. Issue SW-RST ^^^ (already done above)

+  //    2. Issue a redundant Set CU Base CMD immediately

+  //       Do not set the General Pointer before the Set CU Base cycle

+  //       Do not check the SCB CMD before the Set CU Base cycle

+  //    3. Wait for the SCB-CMD to be cleared

+  //       this indicates the transition to post-driver

+  //    4. Poll the TCO-Req bit in the PMDR to be cleared

+  //       this indicates the tco activity has stopped for real

+  //    5. Proceed with the nominal Driver Init:

+  //       Actual Set CU & RU Base ...

+  //

+  // Check for ICH2 device ID.  If this is an ICH2,

+  // do the TCO workaround code.

+  //

+  if (AdapterInfo->VendorID == D102_DEVICE_ID ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_1 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_2 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_3 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_4 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_5 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_6 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_7 ||

+      AdapterInfo->VendorID == ICH3_DEVICE_ID_8 ||

+      AdapterInfo->RevID >= 8) {  // do the TCO fix

+    //

+    // donot load the scb pointer but just give load_cu cmd.

+    //

+    OutByte (AdapterInfo, CU_CMD_BASE, AdapterInfo->ioaddr + SCBCmd);

+    //

+    // wait for command to be accepted.

+    //

+    wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd);

+    //

+    // read PMDR register and check bit 1 in it to see if TCO is active

+    //

+

+    //

+    // wait for 5 milli seconds

+    //

+    wait = 5000;

+    while (wait) {

+      tco_stat = InByte (AdapterInfo, AdapterInfo->ioaddr + 0x1b);

+      if ((tco_stat & 2) == 0) {

+        //

+        // is the activity bit clear??

+        //

+        break;

+      }

+

+      wait--;

+      DelayIt (AdapterInfo, 1);

+    }

+

+    if ((tco_stat & 2) != 0) {

+      //

+      // not zero??

+      //

+      return -1;

+    }

+  }

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT8

+SelectiveReset (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16  wait;

+  UINT32  stat;

+

+  wait  = 10;

+  stat  = 0;

+  OutLong (AdapterInfo, POR_SELECTIVE_RESET, AdapterInfo->ioaddr + SCBPort);

+  //

+  // wait for this to complete

+  //

+

+  //

+  // wait for 2 milli seconds here!

+  //

+  DelayIt (AdapterInfo, 2000);

+  while (wait > 0) {

+    wait--;

+    stat = InLong (AdapterInfo, AdapterInfo->ioaddr + SCBPort);

+    if (stat == 0) {

+      break;

+    }

+

+    //

+    // wait for 1 milli second

+    //

+    DelayIt (AdapterInfo, 1000);

+  }

+

+  if (stat != 0) {

+    return PXE_STATCODE_DEVICE_FAILURE;

+  }

+

+  return 0;

+}

+

+

+/**

+  TODO: Add function description

+

+  @param  AdapterInfo                     TODO: add argument description

+

+  @return TODO: add return values

+

+**/

+UINT16

+InitializeChip (

+  IN NIC_DATA_INSTANCE *AdapterInfo

+  )

+{

+  UINT16  ret_val;

+  if (SoftwareReset (AdapterInfo) != 0) {

+    return PXE_STATCODE_DEVICE_FAILURE;

+  }

+

+  //

+  // disable interrupts

+  //

+  OutWord (AdapterInfo, INT_MASK, AdapterInfo->ioaddr + SCBCmd);

+

+  //

+  // Load the base registers with 0s (we will give the complete address as

+  // offset later when we issue any command

+  //

+  if ((ret_val = Load_Base_Regs (AdapterInfo)) != 0) {

+    return ret_val;

+  }

+

+  if ((ret_val = SetupCBlink (AdapterInfo)) != 0) {

+    return ret_val;

+  }

+

+  if ((ret_val = SetupReceiveQueues (AdapterInfo)) != 0) {

+    return ret_val;

+  }

+

+  //

+  // detect the PHY only if we need to detect the cable as requested by the

+  // initialize parameters

+  //

+  AdapterInfo->PhyAddress = 0xFF;

+

+  if (AdapterInfo->CableDetect != 0) {

+    if (!PhyDetect (AdapterInfo)) {

+      return PXE_STATCODE_DEVICE_FAILURE;

+    }

+  }

+

+  if ((ret_val = E100bSetupIAAddr (AdapterInfo)) != 0) {

+    return ret_val;

+  }

+

+  if ((ret_val = Configure (AdapterInfo)) != 0) {

+    return ret_val;

+  }

+

+  return 0;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/E100b.h b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/E100b.h
new file mode 100644
index 0000000..de63ff4
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/E100b.h
@@ -0,0 +1,671 @@
+/** @file

+  Definitions for network adapter card.

+

+Copyright (c) 2006 - 2007, 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.

+

+**/

+

+#ifndef _E100B_H_

+#define _E100B_H_

+

+// pci config offsets:

+

+#define RX_BUFFER_COUNT 32

+#define TX_BUFFER_COUNT 32

+

+#define PCI_VENDOR_ID_INTEL 0x8086

+#define PCI_DEVICE_ID_INTEL_82557 0x1229

+#define D100_VENDOR_ID   0x8086

+#define D100_DEVICE_ID   0x1229

+#define D102_DEVICE_ID   0x2449

+

+#define ICH3_DEVICE_ID_1   0x1031

+#define ICH3_DEVICE_ID_2   0x1032

+#define ICH3_DEVICE_ID_3   0x1033

+#define ICH3_DEVICE_ID_4   0x1034

+#define ICH3_DEVICE_ID_5   0x1035

+#define ICH3_DEVICE_ID_6   0x1036

+#define ICH3_DEVICE_ID_7   0x1037

+#define ICH3_DEVICE_ID_8   0x1038

+

+#define SPEEDO_DEVICE_ID   0x1227

+#define SPLASH1_DEVICE_ID   0x1226

+

+

+// bit fields for the command

+#define PCI_COMMAND_MASTER  0x04  // bit 2

+#define PCI_COMMAND_IO    0x01  // bit 0

+#define PCI_COMMAND  0x04

+#define PCI_LATENCY_TIMER  0x0D

+

+#define ETHER_MAC_ADDR_LEN 6

+#ifdef AVL_XXX

+#define ETHER_HEADER_LEN 14

+// media interface type

+// #define INTERFACE_TYPE "

+

+// Hardware type values

+#define HW_ETHER_TYPE    1

+#define HW_EXPERIMENTAL_ETHER_TYPE 2

+#define HW_IEEE_TYPE    6

+#define HW_ARCNET_TYPE     7

+

+#endif  // AVL_XXX

+

+#define MAX_ETHERNET_PKT_SIZE 1514  // including eth header

+#define RX_BUFFER_SIZE 1536  // including crc and padding

+#define TX_BUFFER_SIZE 64

+#define ETH_MTU 1500  // does not include ethernet header length

+

+#define SPEEDO3_TOTAL_SIZE 0x20

+

+#pragma pack(1)

+

+typedef struct eth {

+  UINT8 dest_addr[PXE_HWADDR_LEN_ETHER];

+  UINT8 src_addr[PXE_HWADDR_LEN_ETHER];

+  UINT16 type;

+} EtherHeader;

+

+#pragma pack(1)

+typedef struct CONFIG_HEADER {

+  UINT16 VendorID;

+  UINT16 DeviceID;

+  UINT16 Command;

+  UINT16 Status;

+  UINT16 RevID;

+  UINT16 ClassID;

+  UINT8  CacheLineSize;

+  UINT8  LatencyTimer;

+  UINT8  HeaderType;    // must be zero to impose this structure...

+  UINT8  BIST;  // built-in self test

+  UINT32 BaseAddressReg_0;  // memory mapped address

+  UINT32 BaseAddressReg_1;  //io mapped address, Base IO address

+  UINT32 BaseAddressReg_2;  // option rom address

+  UINT32 BaseAddressReg_3;

+  UINT32 BaseAddressReg_4;

+  UINT32 BaseAddressReg_5;

+  UINT32 CardBusCISPtr;

+  UINT16 SubVendorID;

+  UINT16 SubSystemID;

+  UINT32 ExpansionROMBaseAddr;

+  UINT8 CapabilitiesPtr;

+  UINT8 reserved1;

+  UINT16 Reserved2;

+  UINT32 Reserved3;

+  UINT8 int_line;

+  UINT8 int_pin;

+  UINT8 Min_gnt;

+  UINT8 Max_lat;

+} PCI_CONFIG_HEADER;

+#pragma pack()

+

+//-------------------------------------------------------------------------

+// Offsets to the various registers.

+//   All accesses need not be longword aligned.

+//-------------------------------------------------------------------------

+enum speedo_offsets {

+  SCBStatus = 0, SCBCmd = 2,     // Rx/Command Unit command and status.

+  SCBPointer = 4,                // General purpose pointer.

+  SCBPort = 8,                   // Misc. commands and operands.

+  SCBflash = 12, SCBeeprom = 14, // EEPROM and flash memory control.

+  SCBCtrlMDI = 16,               // MDI interface control.

+  SCBEarlyRx = 20,               // Early receive byte count.

+  SCBEarlyRxInt = 24, SCBFlowCtrlReg = 25, SCBPmdr = 27,

+  // offsets for general control registers (GCRs)

+  SCBGenCtrl = 28, SCBGenStatus = 29, SCBGenCtrl2 = 30, SCBRsvd = 31

+};

+

+#define GCR2_EEPROM_ACCESS_SEMAPHORE 0x80 // bit offset into the gcr2

+

+//-------------------------------------------------------------------------

+// Action commands - Commands that can be put in a command list entry.

+//-------------------------------------------------------------------------

+enum commands {

+  CmdNOp = 0, CmdIASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,

+  CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7,

+  CmdSuspend = 0x4000,    /* Suspend after completion. */

+  CmdIntr = 0x2000,      /* Interrupt after completion. */

+  CmdTxFlex = 0x0008      /* Use "Flexible mode" for CmdTx command. */

+};

+

+//-------------------------------------------------------------------------

+// port commands

+//-------------------------------------------------------------------------

+#define PORT_RESET 0

+#define PORT_SELF_TEST 1

+#define POR_SELECTIVE_RESET 2

+#define PORT_DUMP_POINTER 2

+

+//-------------------------------------------------------------------------

+// SCB Command Word bit definitions

+//-------------------------------------------------------------------------

+//- CUC fields

+#define   CU_START    0x0010

+#define   CU_RESUME    0x0020

+#define   CU_STATSADDR  0x0040

+#define   CU_SHOWSTATS  0x0050  /* Dump statistics counters. */

+#define   CU_CMD_BASE  0x0060  /* Base address to add to add CU commands. */

+#define   CU_DUMPSTATS  0x0070  /* Dump then reset stats counters. */

+

+//- RUC fields

+#define   RX_START  0x0001

+#define   RX_RESUME  0x0002

+#define   RX_ABORT  0x0004

+#define   RX_ADDR_LOAD  0x0006  /* load ru_base_reg */

+#define   RX_RESUMENR  0x0007

+

+// Interrupt fields (assuming byte addressing)

+#define INT_MASK  0x0100

+#define DRVR_INT  0x0200    /* Driver generated interrupt. */

+

+//- CB Status Word

+#define CMD_STATUS_COMPLETE 0x8000

+#define RX_STATUS_COMPLETE 0x8000

+#define CMD_STATUS_MASK 0xF000

+

+//-------------------------------------------------------------------------

+//- SCB Status bits:

+// Interrupts are ACKed by writing to the upper 6 interrupt bits

+//-------------------------------------------------------------------------

+#define SCB_STATUS_MASK        0xFC00 // bits 2-7 - STATUS/ACK Mask

+#define SCB_STATUS_CX_TNO      0x8000 // BIT_15  - CX or TNO Interrupt

+#define SCB_STATUS_FR          0x4000 // BIT_14 - FR Interrupt

+#define SCB_STATUS_CNA         0x2000 // BIT_13 - CNA Interrupt

+#define SCB_STATUS_RNR         0x1000 // BIT_12  - RNR Interrupt

+#define SCB_STATUS_MDI         0x0800 // BIT_11  - MDI R/W Done Interrupt

+#define SCB_STATUS_SWI         0x0400 // BIT_10  - SWI Interrupt

+

+// CU STATUS: bits 6 & 7

+#define SCB_STATUS_CU_MASK     0x00C0 // bits 6 & 7

+#define SCB_STATUS_CU_IDLE     0x0000 // 00

+#define SCB_STATUS_CU_SUSPEND  0x0040 // 01

+#define SCB_STATUS_CU_ACTIVE   0x0080 // 10

+

+// RU STATUS: bits 2-5

+#define SCB_RUS_IDLE         0x0000

+#define SCB_RUS_SUSPENDED    0x0004  // bit 2

+#define SCB_RUS_NO_RESOURCES   0x0008 // bit 3

+#define SCB_RUS_READY       0x0010 // bit 4

+

+//-------------------------------------------------------------------------

+// Bit Mask definitions

+//-------------------------------------------------------------------------

+#define BIT_0       0x0001

+#define BIT_1       0x0002

+#define BIT_2       0x0004

+#define BIT_3       0x0008

+#define BIT_4       0x0010

+#define BIT_5       0x0020

+#define BIT_6       0x0040

+#define BIT_7       0x0080

+#define BIT_8       0x0100

+#define BIT_9       0x0200

+#define BIT_10      0x0400

+#define BIT_11      0x0800

+#define BIT_12      0x1000

+#define BIT_13      0x2000

+#define BIT_14      0x4000

+#define BIT_15      0x8000

+#define BIT_24      0x01000000

+#define BIT_28      0x10000000

+

+

+//-------------------------------------------------------------------------

+// MDI Control register bit definitions

+//-------------------------------------------------------------------------

+#define MDI_DATA_MASK           BIT_0_15        // MDI Data port

+#define MDI_REG_ADDR            BIT_16_20       // which MDI register to read/write

+#define MDI_PHY_ADDR            BIT_21_25       // which PHY to read/write

+#define MDI_PHY_OPCODE          BIT_26_27       // which PHY to read/write

+#define MDI_PHY_READY           BIT_28          // PHY is ready for another MDI cycle

+#define MDI_PHY_INT_ENABLE      BIT_29          // Assert INT at MDI cycle completion

+

+#define BIT_0_2     0x0007

+#define BIT_0_3     0x000F

+#define BIT_0_4     0x001F

+#define BIT_0_5     0x003F

+#define BIT_0_6     0x007F

+#define BIT_0_7     0x00FF

+#define BIT_0_8     0x01FF

+#define BIT_0_13    0x3FFF

+#define BIT_0_15    0xFFFF

+#define BIT_1_2     0x0006

+#define BIT_1_3     0x000E

+#define BIT_2_5     0x003C

+#define BIT_3_4     0x0018

+#define BIT_4_5     0x0030

+#define BIT_4_6     0x0070

+#define BIT_4_7     0x00F0

+#define BIT_5_7     0x00E0

+#define BIT_5_9     0x03E0

+#define BIT_5_12    0x1FE0

+#define BIT_5_15    0xFFE0

+#define BIT_6_7     0x00c0

+#define BIT_7_11    0x0F80

+#define BIT_8_10    0x0700

+#define BIT_9_13    0x3E00

+#define BIT_12_15   0xF000

+

+#define BIT_16_20   0x001F0000

+#define BIT_21_25   0x03E00000

+#define BIT_26_27   0x0C000000

+

+//-------------------------------------------------------------------------

+// MDI Control register opcode definitions

+//-------------------------------------------------------------------------

+#define MDI_WRITE               1               // Phy Write

+#define MDI_READ                2               // Phy read

+

+//-------------------------------------------------------------------------

+// PHY 100 MDI Register/Bit Definitions

+//-------------------------------------------------------------------------

+// MDI register set

+#define MDI_CONTROL_REG             0x00        // MDI control register

+#define MDI_STATUS_REG              0x01        // MDI Status regiser

+#define PHY_ID_REG_1                0x02        // Phy indentification reg (word 1)

+#define PHY_ID_REG_2                0x03        // Phy indentification reg (word 2)

+#define AUTO_NEG_ADVERTISE_REG      0x04        // Auto-negotiation advertisement

+#define AUTO_NEG_LINK_PARTNER_REG   0x05        // Auto-negotiation link partner ability

+#define AUTO_NEG_EXPANSION_REG      0x06        // Auto-negotiation expansion

+#define AUTO_NEG_NEXT_PAGE_REG      0x07        // Auto-negotiation next page transmit

+#define EXTENDED_REG_0              0x10        // Extended reg 0 (Phy 100 modes)

+#define EXTENDED_REG_1              0x14        // Extended reg 1 (Phy 100 error indications)

+#define NSC_CONG_CONTROL_REG        0x17        // National (TX) congestion control

+#define NSC_SPEED_IND_REG           0x19        // National (TX) speed indication

+

+// MDI Control register bit definitions

+#define MDI_CR_COLL_TEST_ENABLE     BIT_7       // Collision test enable

+#define MDI_CR_FULL_HALF            BIT_8       // FDX =1, half duplex =0

+#define MDI_CR_RESTART_AUTO_NEG     BIT_9       // Restart auto negotiation

+#define MDI_CR_ISOLATE              BIT_10      // Isolate PHY from MII

+#define MDI_CR_POWER_DOWN           BIT_11      // Power down

+#define MDI_CR_AUTO_SELECT          BIT_12      // Auto speed select enable

+#define MDI_CR_10_100               BIT_13      // 0 = 10Mbs, 1 = 100Mbs

+#define MDI_CR_LOOPBACK             BIT_14      // 0 = normal, 1 = loopback

+#define MDI_CR_RESET                BIT_15      // 0 = normal, 1 = PHY reset

+

+// MDI Status register bit definitions

+#define MDI_SR_EXT_REG_CAPABLE      BIT_0       // Extended register capabilities

+#define MDI_SR_JABBER_DETECT        BIT_1       // Jabber detected

+#define MDI_SR_LINK_STATUS          BIT_2       // Link Status -- 1 = link

+#define MDI_SR_AUTO_SELECT_CAPABLE  BIT_3       // Auto speed select capable

+#define MDI_SR_REMOTE_FAULT_DETECT  BIT_4       // Remote fault detect

+#define MDI_SR_AUTO_NEG_COMPLETE    BIT_5       // Auto negotiation complete

+#define MDI_SR_10T_HALF_DPX         BIT_11      // 10BaseT Half Duplex capable

+#define MDI_SR_10T_FULL_DPX         BIT_12      // 10BaseT full duplex capable

+#define MDI_SR_TX_HALF_DPX          BIT_13      // TX Half Duplex capable

+#define MDI_SR_TX_FULL_DPX          BIT_14      // TX full duplex capable

+#define MDI_SR_T4_CAPABLE           BIT_15      // T4 capable

+

+// Auto-Negotiation advertisement register bit definitions

+#define NWAY_AD_SELCTOR_FIELD       BIT_0_4     // identifies supported protocol

+#define NWAY_AD_ABILITY             BIT_5_12    // technologies that are supported

+#define NWAY_AD_10T_HALF_DPX        BIT_5       // 10BaseT Half Duplex capable

+#define NWAY_AD_10T_FULL_DPX        BIT_6       // 10BaseT full duplex capable

+#define NWAY_AD_TX_HALF_DPX         BIT_7       // TX Half Duplex capable

+#define NWAY_AD_TX_FULL_DPX         BIT_8       // TX full duplex capable

+#define NWAY_AD_T4_CAPABLE          BIT_9       // T4 capable

+#define NWAY_AD_REMOTE_FAULT        BIT_13      // indicates local remote fault

+#define NWAY_AD_RESERVED            BIT_14      // reserved

+#define NWAY_AD_NEXT_PAGE           BIT_15      // Next page (not supported)

+

+// Auto-Negotiation link partner ability register bit definitions

+#define NWAY_LP_SELCTOR_FIELD       BIT_0_4     // identifies supported protocol

+#define NWAY_LP_ABILITY             BIT_5_9     // technologies that are supported

+#define NWAY_LP_REMOTE_FAULT        BIT_13      // indicates partner remote fault

+#define NWAY_LP_ACKNOWLEDGE         BIT_14      // acknowledge

+#define NWAY_LP_NEXT_PAGE           BIT_15      // Next page (not supported)

+

+// Auto-Negotiation expansion register bit definitions

+#define NWAY_EX_LP_NWAY             BIT_0       // link partner is NWAY

+#define NWAY_EX_PAGE_RECEIVED       BIT_1       // link code word received

+#define NWAY_EX_NEXT_PAGE_ABLE      BIT_2       // local is next page able

+#define NWAY_EX_LP_NEXT_PAGE_ABLE   BIT_3       // partner is next page able

+#define NWAY_EX_PARALLEL_DET_FLT    BIT_4       // parallel detection fault

+#define NWAY_EX_RESERVED            BIT_5_15    // reserved

+

+

+// PHY 100 Extended Register 0 bit definitions

+#define PHY_100_ER0_FDX_INDIC       BIT_0       // 1 = FDX, 0 = half duplex

+#define PHY_100_ER0_SPEED_INDIC     BIT_1       // 1 = 100mbs, 0= 10mbs

+#define PHY_100_ER0_WAKE_UP         BIT_2       // Wake up DAC

+#define PHY_100_ER0_RESERVED        BIT_3_4     // Reserved

+#define PHY_100_ER0_REV_CNTRL       BIT_5_7     // Revsion control (A step = 000)

+#define PHY_100_ER0_FORCE_FAIL      BIT_8       // Force Fail is enabled

+#define PHY_100_ER0_TEST            BIT_9_13    // Revsion control (A step = 000)

+#define PHY_100_ER0_LINKDIS         BIT_14      // Link integrity test is disabled

+#define PHY_100_ER0_JABDIS          BIT_15      // Jabber function is disabled

+

+

+// PHY 100 Extended Register 1 bit definitions

+#define PHY_100_ER1_RESERVED        BIT_0_8     // Reserved

+#define PHY_100_ER1_CH2_DET_ERR     BIT_9       // Channel 2 EOF detection error

+#define PHY_100_ER1_MANCH_CODE_ERR  BIT_10      // Manchester code error

+#define PHY_100_ER1_EOP_ERR         BIT_11      // EOP error

+#define PHY_100_ER1_BAD_CODE_ERR    BIT_12      // bad code error

+#define PHY_100_ER1_INV_CODE_ERR    BIT_13      // invalid code error

+#define PHY_100_ER1_DC_BAL_ERR      BIT_14      // DC balance error

+#define PHY_100_ER1_PAIR_SKEW_ERR   BIT_15      // Pair skew error

+

+// National Semiconductor TX phy congestion control register bit definitions

+#define NSC_TX_CONG_TXREADY         BIT_10      // Makes TxReady an input

+#define NSC_TX_CONG_ENABLE          BIT_8       // Enables congestion control

+#define NSC_TX_CONG_F_CONNECT       BIT_5       // Enables congestion control

+

+// National Semiconductor TX phy speed indication register bit definitions

+#define NSC_TX_SPD_INDC_SPEED       BIT_6       // 0 = 100mb, 1=10mb

+

+//-------------------------------------------------------------------------

+// Phy related constants

+//-------------------------------------------------------------------------

+#define PHY_503                 0

+#define PHY_100_A               0x000003E0

+#define PHY_100_C               0x035002A8

+#define PHY_TX_ID               0x015002A8

+#define PHY_NSC_TX              0x5c002000

+#define PHY_OTHER               0xFFFF

+

+#define PHY_MODEL_REV_ID_MASK   0xFFF0FFFF

+#define PARALLEL_DETECT         0

+#define N_WAY                   1

+

+#define RENEGOTIATE_TIME        35 // (3.5 Seconds)

+

+#define CONNECTOR_AUTO          0

+#define CONNECTOR_TPE           1

+#define CONNECTOR_MII           2

+

+//-------------------------------------------------------------------------

+

+/* The Speedo3 Rx and Tx frame/buffer descriptors. */

+#pragma pack(1)

+struct CB_Header {      /* A generic descriptor. */

+  UINT16 status;    /* Offset 0. */

+  UINT16 command;    /* Offset 2. */

+  UINT32 link;          /* struct descriptor *  */

+};

+

+/* transmit command block structure */

+#pragma pack(1)

+typedef struct s_TxCB {

+  struct CB_Header cb_header;

+  UINT32 PhysTBDArrayAddres;  /* address of an array that contains

+                physical TBD pointers */

+  UINT16 ByteCount;  /* immediate data count = 0 always */

+  UINT8 Threshold;

+  UINT8 TBDCount;

+  UINT8 ImmediateData[TX_BUFFER_SIZE];

+  /* following fields are not seen by the 82557 */

+  struct TBD {

+    UINT32 phys_buf_addr;

+    UINT32 buf_len;

+    } TBDArray[MAX_XMIT_FRAGMENTS];

+  UINT32 PhysArrayAddr;  /* in case the one in the header is lost */

+  UINT32 PhysTCBAddress;    /* for this TCB */

+  struct s_TxCB *NextTCBVirtualLinkPtr;

+  struct s_TxCB *PrevTCBVirtualLinkPtr;

+  UINT64 free_data_ptr;  // to be given to the upper layer when this xmit completes1

+}TxCB;

+

+/* The Speedo3 Rx and Tx buffer descriptors. */

+#pragma pack(1)

+typedef struct s_RxFD {          /* Receive frame descriptor. */

+  struct CB_Header cb_header;

+  UINT32 rx_buf_addr;      /* VOID * */

+  UINT16 ActualCount;

+  UINT16 RFDSize;

+  UINT8 RFDBuffer[RX_BUFFER_SIZE];

+  UINT8 forwarded;

+  UINT8 junk[3];

+}RxFD;

+

+/* Elements of the RxFD.status word. */

+#define RX_COMPLETE 0x8000

+#define RX_FRAME_OK 0x2000

+

+/* Elements of the dump_statistics block. This block must be lword aligned. */

+#pragma pack(1)

+struct speedo_stats {

+  UINT32 tx_good_frames;

+  UINT32 tx_coll16_errs;

+  UINT32 tx_late_colls;

+  UINT32 tx_underruns;

+  UINT32 tx_lost_carrier;

+  UINT32 tx_deferred;

+  UINT32 tx_one_colls;

+  UINT32 tx_multi_colls;

+  UINT32 tx_total_colls;

+  UINT32 rx_good_frames;

+  UINT32 rx_crc_errs;

+  UINT32 rx_align_errs;

+  UINT32 rx_resource_errs;

+  UINT32 rx_overrun_errs;

+  UINT32 rx_colls_errs;

+  UINT32 rx_runt_errs;

+  UINT32 done_marker;

+};

+#pragma pack()

+

+

+struct Krn_Mem{

+  RxFD rx_ring[RX_BUFFER_COUNT];

+  TxCB tx_ring[TX_BUFFER_COUNT];

+  struct speedo_stats statistics;

+};

+#define MEMORY_NEEDED  sizeof(struct Krn_Mem)

+

+/* The parameters for a CmdConfigure operation.

+   There are so many options that it would be difficult to document each bit.

+   We mostly use the default or recommended settings.

+*/

+

+/*

+ *--------------------------------------------------------------------------

+ * Configuration CB Parameter Bit Definitions

+ *--------------------------------------------------------------------------

+ */

+// - Byte 0  (Default Value = 16h)

+#define CFIG_BYTE_COUNT    0x16       // 22 Configuration Bytes

+

+//- Byte 1  (Default Value = 88h)

+#define CFIG_TXRX_FIFO_LIMIT  0x88

+

+//- Byte 2  (Default Value = 0)

+#define CFIG_ADAPTIVE_IFS    0

+

+//- Byte 3  (Default Value = 0, ALWAYS. This byte is RESERVED)

+#define CFIG_RESERVED        0

+

+//- Byte 4  (Default Value = 0. Default implies that Rx DMA cannot be

+//-          preempted).

+#define CFIG_RXDMA_BYTE_COUNT      0

+

+//- Byte 5  (Default Value = 80h. Default implies that Tx DMA cannot be

+//-          preempted. However, setting these counters is enabled.)

+#define CFIG_DMBC_ENABLE            0x80

+

+//- Byte 6  (Default Value = 33h. Late SCB enabled, No TNO interrupts,

+//-          CNA interrupts and do not save bad frames.)

+#define CFIG_LATE_SCB               1  // BIT 0

+#define CFIG_TNO_INTERRUPT          0x4  // BIT 2

+#define CFIG_CI_INTERRUPT           0x8  // BIT 3

+#define CFIG_SAVE_BAD_FRAMES        0x80  // BIT_7

+

+//- Byte 7  (Default Value = 7h. Discard short frames automatically and

+//-          attempt upto 3 retries on transmit.)

+#define CFIG_DISCARD_SHORTRX         0x00001

+#define CFIG_URUN_RETRY              BIT_1 OR BIT_2

+

+//- Byte 8  (Default Value = 1. Enable MII mode.)

+#define CFIG_503_MII              BIT_0

+

+//- Byte 9  (Default Value = 0, ALWAYS)

+

+//- Byte 10 (Default Value = 2Eh)

+#define CFIG_NSAI                   BIT_3

+#define CFIG_PREAMBLE_LENGTH         BIT_5      ;- Bit 5-4  = 1-0

+#define CFIG_NO_LOOPBACK             0

+#define CFIG_INTERNAL_LOOPBACK       BIT_6

+#define CFIG_EXT_LOOPBACK            BIT_7

+#define CFIG_EXT_PIN_LOOPBACK        BIT_6 OR BIT_7

+

+//- Byte 11 (Default Value = 0)

+#define CFIG_LINEAR_PRIORITY         0

+

+//- Byte 12 (Default Value = 60h)

+#define CFIG_LPRIORITY_MODE          0

+#define CFIG_IFS                     6          ;- 6 * 16 = 96

+

+//- Byte 13 (Default Value = 0, ALWAYS)

+

+//- Byte 14 (Default Value = 0F2h, ALWAYS)

+

+//- Byte 15 (Default Value = E8h)

+#define CFIG_PROMISCUOUS_MODE        BIT_0

+#define CFIG_BROADCAST_DISABLE       BIT_1

+#define CFIG_CRS_CDT                 BIT_7

+

+//- Byte 16 (Default Value = 0, ALWAYS)

+

+//- Byte 17 (Default Value = 40h, ALWAYS)

+

+//- Byte 18 (Default Value = F2h)

+#define CFIG_STRIPPING               BIT_0

+#define CFIG_PADDING                 BIT_1

+#define CFIG_RX_CRC_TRANSFER         BIT_2

+

+//- Byte 19 (Default Value = 80h)

+#define CFIG_FORCE_FDX               BIT_6

+#define CFIG_FDX_PIN_ENABLE          BIT_7

+

+//- Byte 20 (Default Value = 3Fh)

+#define CFIG_MULTI_IA                BIT_6

+

+//- Byte 21 (Default Value = 05)

+#define CFIG_MC_ALL                  BIT_3

+

+/*-----------------------------------------------------------------------*/

+#define D102_REVID 0x0b

+

+#define HALF_DUPLEX 1

+#define FULL_DUPLEX 2

+

+typedef struct s_data_instance {

+

+  UINT16 State;  // stopped, started or initialized

+  UINT16 Bus;

+  UINT8 Device;

+  UINT8 Function;

+  UINT16 VendorID;

+  UINT16 DeviceID;

+  UINT16 RevID;

+  UINT16 SubVendorID;

+  UINT16 SubSystemID;

+

+  UINT8 PermNodeAddress[PXE_MAC_LENGTH];

+  UINT8 CurrentNodeAddress[PXE_MAC_LENGTH];

+  UINT8 BroadcastNodeAddress[PXE_MAC_LENGTH];

+  UINT32 Config[MAX_PCI_CONFIG_LEN];

+  UINT32 NVData[MAX_EEPROM_LEN];

+

+  UINT32 ioaddr;

+  UINT32 flash_addr;

+

+  UINT16 LinkSpeed;     // actual link speed setting

+  UINT16 LinkSpeedReq;  // requested (forced) link speed

+  UINT8  DuplexReq;     // requested duplex

+  UINT8  Duplex;        // Duplex set

+  UINT8  CableDetect;   // 1 to detect and 0 not to detect the cable

+  UINT8  LoopBack;

+

+  UINT16 TxBufCnt;

+  UINT16 TxBufSize;

+  UINT16 RxBufCnt;

+  UINT16 RxBufSize;

+  UINT32 RxTotals;

+  UINT32 TxTotals;

+

+  UINT16 int_mask;

+  UINT16 Int_Status;

+  UINT16 PhyRecord[2];  // primary and secondary PHY record registers from eeprom

+  UINT8  PhyAddress;

+  UINT8  int_num;

+  UINT16 NVData_Len;

+  UINT32 MemoryLength;

+

+  RxFD *rx_ring;  // array of rx buffers

+  TxCB *tx_ring;  // array of tx buffers

+  struct speedo_stats *statistics;

+  TxCB *FreeTxHeadPtr;

+  TxCB *FreeTxTailPtr;

+  RxFD *RFDTailPtr;

+

+  UINT64 rx_phy_addr;  // physical addresses

+  UINT64 tx_phy_addr;

+  UINT64 stat_phy_addr;

+  UINT64 MemoryPtr;

+  UINT64 Mapped_MemoryPtr;

+

+  UINT64 xmit_done[TX_BUFFER_COUNT << 1]; // circular buffer

+  UINT16 xmit_done_head;  // index into the xmit_done array

+  UINT16 xmit_done_tail;  // where are we filling now (index into xmit_done)

+  UINT16 cur_rx_ind;  // current RX Q head index

+  UINT16 FreeCBCount;

+

+  BOOLEAN in_interrupt;

+  BOOLEAN in_transmit;

+  BOOLEAN Receive_Started;

+  UINT8 Rx_Filter;

+  UINT8 VersionFlag;  // UNDI30 or UNDI31??

+  UINT8 rsvd[3];

+

+  struct mc{

+    UINT16 reserved [3]; // padding for this structure to make it 8 byte aligned

+    UINT16 list_len;

+    UINT8 mc_list[MAX_MCAST_ADDRESS_CNT][PXE_MAC_LENGTH]; // 8*32 is the size

+  } mcast_list;

+

+  UINT64 Unique_ID;

+

+  EFI_PCI_IO_PROTOCOL   *Io_Function;

+  //

+  // Original PCI attributes

+  //

+  UINT64                OriginalPciAttributes;

+

+  VOID (*Delay_30)(UINTN);  // call back routine

+  VOID (*Virt2Phys_30)(UINT64 virtual_addr, UINT64 physical_ptr);  // call back routine

+  VOID (*Block_30)(UINT32 enable);  // call back routine

+  VOID (*Mem_Io_30)(UINT8 read_write, UINT8 len, UINT64 port, UINT64 buf_addr);

+  VOID (*Delay)(UINT64, UINTN);  // call back routine

+  VOID (*Virt2Phys)(UINT64 unq_id, UINT64 virtual_addr, UINT64 physical_ptr);  // call back routine

+  VOID (*Block)(UINT64 unq_id, UINT32 enable);  // call back routine

+  VOID (*Mem_Io)(UINT64 unq_id, UINT8 read_write, UINT8 len, UINT64 port,

+          UINT64 buf_addr);

+  VOID (*Map_Mem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,

+                   UINT32 Direction, UINT64 mapped_addr);

+  VOID (*UnMap_Mem)(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,

+            UINT32 Direction, UINT64 mapped_addr);

+  VOID (*Sync_Mem)(UINT64 unq_id, UINT64 virtual_addr,

+            UINT32 size, UINT32 Direction, UINT64 mapped_addr);

+} NIC_DATA_INSTANCE;

+

+#pragma pack(1)

+struct MC_CB_STRUCT{

+  UINT16 count;

+  UINT8 m_list[MAX_MCAST_ADDRESS_CNT][ETHER_MAC_ADDR_LEN];

+};

+#pragma pack()

+

+#define FOUR_GIGABYTE (UINT64)0x100000000ULL

+

+#endif

+

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Init.c b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Init.c
new file mode 100644
index 0000000..9410fe1
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Init.c
@@ -0,0 +1,1049 @@
+/** @file

+  Initialization functions for EFI UNDI32 driver.

+

+Copyright (c) 2006 - 2013, 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.

+

+**/

+

+#include "Undi32.h"

+//

+// Global Variables

+//

+

+PXE_SW_UNDI             *pxe_31 = NULL;  // 3.1 entry

+UNDI32_DEV              *UNDI32DeviceList[MAX_NIC_INTERFACES];

+UNDI_CONFIG_TABLE       *UndiDataPointer = NULL;

+

+//

+// UNDI Class Driver Global Variables

+//

+EFI_DRIVER_BINDING_PROTOCOL  gUndiDriverBinding = {

+  UndiDriverSupported,

+  UndiDriverStart,

+  UndiDriverStop,

+  0xa,

+  NULL,

+  NULL

+};

+

+

+/**

+  When address mapping changes to virtual this should make the appropriate

+  address conversions.

+

+  (Standard Event handler)

+

+  @return None

+

+**/

+VOID

+EFIAPI

+UndiNotifyVirtual (

+  EFI_EVENT Event,

+  VOID      *Context

+  )

+{

+  UINT16  Index;

+  VOID    *Pxe31Pointer;

+

+  if (pxe_31 != NULL) {

+    Pxe31Pointer = (VOID *) pxe_31;

+

+    EfiConvertPointer (

+      EFI_OPTIONAL_PTR,

+      (VOID **) &Pxe31Pointer

+      );

+

+    //

+    // UNDI32DeviceList is an array of pointers

+    //

+    for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) {

+      UNDI32DeviceList[Index]->NIIProtocol_31.Id = (UINT64) (UINTN) Pxe31Pointer;

+      EfiConvertPointer (

+        EFI_OPTIONAL_PTR,

+        (VOID **) &(UNDI32DeviceList[Index])

+        );

+    }

+

+    EfiConvertPointer (

+      EFI_OPTIONAL_PTR,

+      (VOID **) &(pxe_31->EntryPoint)

+      );

+    pxe_31 = Pxe31Pointer;

+  }

+

+  for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {

+    EfiConvertPointer (

+      EFI_OPTIONAL_PTR,

+      (VOID **) &api_table[Index].api_ptr

+      );

+  }

+}

+

+

+/**

+  When EFI is shuting down the boot services, we need to install a

+  configuration table for UNDI to work at runtime!

+

+  (Standard Event handler)

+

+  @return None

+

+**/

+VOID

+EFIAPI

+UndiNotifyExitBs (

+  EFI_EVENT Event,

+  VOID      *Context

+  )

+{

+  InstallConfigTable ();

+}

+

+

+/**

+  Test to see if this driver supports ControllerHandle. Any ControllerHandle

+  than contains a  DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,

+  and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 ||

+  ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 ||

+  ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported.

+

+  @param  This                 Protocol instance pointer.

+  @param  Controller           Handle of device to test.

+  @param  RemainingDevicePath  Not used.

+

+  @retval EFI_SUCCESS          This driver supports this device.

+  @retval other                This driver does not support this device.

+

+**/

+EFI_STATUS

+EFIAPI

+UndiDriverSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

+  )

+{

+  EFI_STATUS          Status;

+  EFI_PCI_IO_PROTOCOL *PciIo;

+  PCI_TYPE00          Pci;

+

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiDevicePathProtocolGuid,

+                  NULL,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint8,

+                        0,

+                        sizeof (PCI_CONFIG_HEADER),

+                        &Pci

+                        );

+

+  if (!EFI_ERROR (Status)) {

+    Status = EFI_UNSUPPORTED;

+

+    if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) {

+      switch (Pci.Hdr.DeviceId) {

+      case D100_DEVICE_ID:

+      case D102_DEVICE_ID:

+      case ICH3_DEVICE_ID_1:

+      case ICH3_DEVICE_ID_2:

+      case ICH3_DEVICE_ID_3:

+      case ICH3_DEVICE_ID_4:

+      case ICH3_DEVICE_ID_5:

+      case ICH3_DEVICE_ID_6:

+      case ICH3_DEVICE_ID_7:

+      case ICH3_DEVICE_ID_8:

+      case 0x1039:

+      case 0x103A:

+      case 0x103B:

+      case 0x103C:

+      case 0x103D:

+      case 0x103E:

+      case 0x1050:

+      case 0x1051:

+      case 0x1052:

+      case 0x1053:

+      case 0x1054:

+      case 0x1055:

+      case 0x1056:

+      case 0x1057:

+      case 0x1059:

+      case 0x1064:

+        Status = EFI_SUCCESS;

+      }

+    }

+  }

+

+  gBS->CloseProtocol (

+        Controller,

+        &gEfiPciIoProtocolGuid,

+        This->DriverBindingHandle,

+        Controller

+        );

+

+  return Status;

+}

+

+

+/**

+  Start this driver on Controller by opening PciIo and DevicePath protocol.

+  Initialize PXE structures, create a copy of the Controller Device Path with the

+  NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol

+  on the newly created Device Path.

+

+  @param  This                 Protocol instance pointer.

+  @param  Controller           Handle of device to work with.

+  @param  RemainingDevicePath  Not used, always produce all possible children.

+

+  @retval EFI_SUCCESS          This driver is added to Controller.

+  @retval other                This driver does not support this device.

+

+**/

+EFI_STATUS

+EFIAPI

+UndiDriverStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

+  )

+{

+  EFI_STATUS                Status;

+  EFI_DEVICE_PATH_PROTOCOL  *UndiDevicePath;

+  PCI_CONFIG_HEADER         *CfgHdr;

+  UNDI32_DEV                *UNDI32Device;

+  UINT16                    NewCommand;

+  UINT8                     *TmpPxePointer;

+  EFI_PCI_IO_PROTOCOL       *PciIoFncs;

+  UINTN                     Len;

+  UINT64                    Supports;

+  BOOLEAN                   PciAttributesSaved;

+

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIoFncs,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiDevicePathProtocolGuid,

+                  (VOID **) &UndiDevicePath,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+

+  if (EFI_ERROR (Status)) {

+    gBS->CloseProtocol (

+          Controller,

+          &gEfiPciIoProtocolGuid,

+          This->DriverBindingHandle,

+          Controller

+          );

+

+    return Status;

+  }

+

+  PciAttributesSaved = FALSE;

+

+  Status = gBS->AllocatePool (

+                  EfiRuntimeServicesData,

+                  sizeof (UNDI32_DEV),

+                  (VOID **) &UNDI32Device

+                  );

+

+  if (EFI_ERROR (Status)) {

+    goto UndiError;

+  }

+

+  ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV));

+

+  //

+  // Get original PCI attributes

+  //

+  Status = PciIoFncs->Attributes (

+                    PciIoFncs,

+                    EfiPciIoAttributeOperationGet,

+                    0,

+                    &UNDI32Device->NicInfo.OriginalPciAttributes

+                    );

+

+  if (EFI_ERROR (Status)) {

+    goto UndiErrorDeleteDevice;

+  }

+  PciAttributesSaved = TRUE;

+

+  //

+  // allocate and initialize both (old and new) the !pxe structures here,

+  // there should only be one copy of each of these structure for any number

+  // of NICs this undi supports. Also, these structures need to be on a

+  // paragraph boundary as per the spec. so, while allocating space for these,

+  // make sure that there is space for 2 !pxe structures (old and new) and a

+  // 32 bytes padding for alignment adjustment (in case)

+  //

+  TmpPxePointer = NULL;

+  if (pxe_31 == NULL) {

+    Status = gBS->AllocatePool (

+                    EfiRuntimeServicesData,

+                    (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),

+                    (VOID **) &TmpPxePointer

+                    );

+

+    if (EFI_ERROR (Status)) {

+      goto UndiErrorDeleteDevice;

+    }

+

+    ZeroMem (

+      TmpPxePointer,

+      sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32

+      );

+    //

+    // check for paragraph alignment here, assuming that the pointer is

+    // already 8 byte aligned.

+    //

+    if (((UINTN) TmpPxePointer & 0x0F) != 0) {

+      pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8));

+    } else {

+      pxe_31 = (PXE_SW_UNDI *) TmpPxePointer;

+    }

+

+    PxeStructInit (pxe_31);

+  }

+

+  UNDI32Device->NIIProtocol_31.Id = (UINT64) (UINTN) (pxe_31);

+

+  Status = PciIoFncs->Attributes (

+                        PciIoFncs,

+                        EfiPciIoAttributeOperationSupported,

+                        0,

+                        &Supports

+                        );

+  if (!EFI_ERROR (Status)) {

+    Supports &= EFI_PCI_DEVICE_ENABLE;

+    Status = PciIoFncs->Attributes (

+                          PciIoFncs,

+                          EfiPciIoAttributeOperationEnable,

+                          Supports,

+                          NULL

+                          );

+  }

+  //

+  // Read all the registers from device's PCI Configuration space

+  //

+  Status = PciIoFncs->Pci.Read (

+                            PciIoFncs,

+                            EfiPciIoWidthUint32,

+                            0,

+                            MAX_PCI_CONFIG_LEN,

+                            &UNDI32Device->NicInfo.Config

+                            );

+

+  CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]);

+

+  //

+  // make sure that this device is a PCI bus master

+  //

+

+  NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);

+  if (CfgHdr->Command != NewCommand) {

+    PciIoFncs->Pci.Write (

+                    PciIoFncs,

+                    EfiPciIoWidthUint16,

+                    PCI_COMMAND,

+                    1,

+                    &NewCommand

+                    );

+    CfgHdr->Command = NewCommand;

+  }

+

+  //

+  // make sure that the latency timer is at least 32

+  //

+  if (CfgHdr->LatencyTimer < 32) {

+    CfgHdr->LatencyTimer = 32;

+    PciIoFncs->Pci.Write (

+                    PciIoFncs,

+                    EfiPciIoWidthUint8,

+                    PCI_LATENCY_TIMER,

+                    1,

+                    &CfgHdr->LatencyTimer

+                    );

+  }

+  //

+  // the IfNum index for the current interface will be the total number

+  // of interfaces initialized so far

+  //

+  UNDI32Device->NIIProtocol_31.IfNum  = pxe_31->IFcnt | pxe_31->IFcntExt << 8;

+

+  PxeUpdate (&UNDI32Device->NicInfo, pxe_31);

+

+  UNDI32Device->NicInfo.Io_Function                    = PciIoFncs;

+  UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;

+  UNDI32Device->Undi32BaseDevPath                      = UndiDevicePath;

+

+  Status = AppendMac2DevPath (

+            &UNDI32Device->Undi32DevPath,

+            UNDI32Device->Undi32BaseDevPath,

+            &UNDI32Device->NicInfo

+            );

+

+  if (Status != 0) {

+    goto UndiErrorDeletePxe;

+  }

+

+  UNDI32Device->Signature                     = UNDI_DEV_SIGNATURE;

+

+  UNDI32Device->NIIProtocol_31.Revision       = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31;

+  UNDI32Device->NIIProtocol_31.Type           = EfiNetworkInterfaceUndi;

+  UNDI32Device->NIIProtocol_31.MajorVer       = PXE_ROMID_MAJORVER;

+  UNDI32Device->NIIProtocol_31.MinorVer       = PXE_ROMID_MINORVER_31;

+  UNDI32Device->NIIProtocol_31.ImageSize      = 0;

+  UNDI32Device->NIIProtocol_31.ImageAddr      = 0;

+  UNDI32Device->NIIProtocol_31.Ipv6Supported  = FALSE;

+

+  UNDI32Device->NIIProtocol_31.StringId[0]    = 'U';

+  UNDI32Device->NIIProtocol_31.StringId[1]    = 'N';

+  UNDI32Device->NIIProtocol_31.StringId[2]    = 'D';

+  UNDI32Device->NIIProtocol_31.StringId[3]    = 'I';

+

+  UNDI32Device->DeviceHandle                  = NULL;

+

+  //

+  // install both the 3.0 and 3.1 NII protocols.

+  //

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                  &UNDI32Device->DeviceHandle,

+                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,

+                  &UNDI32Device->NIIProtocol_31,

+                  &gEfiDevicePathProtocolGuid,

+                  UNDI32Device->Undi32DevPath,

+                  NULL

+                  );

+

+  if (EFI_ERROR (Status)) {

+    goto UndiErrorDeleteDevicePath;

+  }

+

+  //

+  // if the table exists, free it and alloc again, or alloc it directly

+  //

+  if (UndiDataPointer != NULL) {

+    Status = gBS->FreePool(UndiDataPointer);

+  }

+  if (EFI_ERROR (Status)) {

+    goto UndiErrorDeleteDevicePath;

+  }

+

+  Len = ((pxe_31->IFcnt|pxe_31->IFcntExt << 8)* sizeof (UndiDataPointer->NII_entry)) + sizeof (UndiDataPointer);

+  Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);

+

+  if (EFI_ERROR (Status)) {

+    goto UndiErrorAllocDataPointer;

+  }

+

+  //

+  // Open For Child Device

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIoFncs,

+                  This->DriverBindingHandle,

+                  UNDI32Device->DeviceHandle,

+                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER

+                  );

+

+  return EFI_SUCCESS;

+UndiErrorAllocDataPointer:

+  gBS->UninstallMultipleProtocolInterfaces (

+                  &UNDI32Device->DeviceHandle,

+                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,

+                  &UNDI32Device->NIIProtocol_31,

+                  &gEfiDevicePathProtocolGuid,

+                  UNDI32Device->Undi32DevPath,

+                  NULL

+                  );

+

+UndiErrorDeleteDevicePath:

+  UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;

+  gBS->FreePool (UNDI32Device->Undi32DevPath);

+

+UndiErrorDeletePxe:

+  PxeUpdate (NULL, pxe_31);

+  if (TmpPxePointer != NULL) {

+    gBS->FreePool (TmpPxePointer);

+

+  }

+

+UndiErrorDeleteDevice:

+  if (PciAttributesSaved) {

+    //

+    // Restore original PCI attributes

+    //

+    PciIoFncs->Attributes (

+                    PciIoFncs,

+                    EfiPciIoAttributeOperationSet,

+                    UNDI32Device->NicInfo.OriginalPciAttributes,

+                    NULL

+                    );

+  }

+

+  gBS->FreePool (UNDI32Device);

+

+UndiError:

+  gBS->CloseProtocol (

+        Controller,

+        &gEfiDevicePathProtocolGuid,

+        This->DriverBindingHandle,

+        Controller

+        );

+

+  gBS->CloseProtocol (

+        Controller,

+        &gEfiPciIoProtocolGuid,

+        This->DriverBindingHandle,

+        Controller

+        );

+

+  return Status;

+}

+

+

+/**

+  Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and

+  closing the DevicePath and PciIo protocols on Controller.

+

+  @param  This                 Protocol instance pointer.

+  @param  Controller           Handle of device to stop driver on.

+  @param  NumberOfChildren     How many children need to be stopped.

+  @param  ChildHandleBuffer    Not used.

+

+  @retval EFI_SUCCESS          This driver is removed Controller.

+  @retval other                This driver was not removed from this device.

+

+**/

+// TODO:    EFI_DEVICE_ERROR - add return value to function comment

+EFI_STATUS

+EFIAPI

+UndiDriverStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN  EFI_HANDLE                     Controller,

+  IN  UINTN                          NumberOfChildren,

+  IN  EFI_HANDLE                     *ChildHandleBuffer

+  )

+{

+  EFI_STATUS                                Status;

+  BOOLEAN                                   AllChildrenStopped;

+  UINTN                                     Index;

+  UNDI32_DEV                                *UNDI32Device;

+  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;

+

+  //

+  // Complete all outstanding transactions to Controller.

+  // Don't allow any new transaction to Controller to be started.

+  //

+  if (NumberOfChildren == 0) {

+

+    //

+    // Close the bus driver

+    //

+    Status = gBS->CloseProtocol (

+                    Controller,

+                    &gEfiDevicePathProtocolGuid,

+                    This->DriverBindingHandle,

+                    Controller

+                    );

+

+    Status = gBS->CloseProtocol (

+                    Controller,

+                    &gEfiPciIoProtocolGuid,

+                    This->DriverBindingHandle,

+                    Controller

+                    );

+

+    return Status;

+  }

+

+  AllChildrenStopped = TRUE;

+

+  for (Index = 0; Index < NumberOfChildren; Index++) {

+

+    Status = gBS->OpenProtocol (

+                    ChildHandleBuffer[Index],

+                    &gEfiNetworkInterfaceIdentifierProtocolGuid_31,

+                    (VOID **) &NIIProtocol,

+                    This->DriverBindingHandle,

+                    Controller,

+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                    );

+    if (!EFI_ERROR (Status)) {

+

+      UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);

+

+      Status = gBS->CloseProtocol (

+                      Controller,

+                      &gEfiPciIoProtocolGuid,

+                      This->DriverBindingHandle,

+                      ChildHandleBuffer[Index]

+                      );

+      if (!EFI_ERROR (Status)) {

+        Status = gBS->UninstallMultipleProtocolInterfaces (

+                        ChildHandleBuffer[Index],

+                        &gEfiDevicePathProtocolGuid,

+                        UNDI32Device->Undi32DevPath,

+                        &gEfiNetworkInterfaceIdentifierProtocolGuid_31,

+                        &UNDI32Device->NIIProtocol_31,

+                        NULL

+                        );

+        if (!EFI_ERROR (Status)) {

+          //

+          // Restore original PCI attributes

+          //

+          Status = UNDI32Device->NicInfo.Io_Function->Attributes (

+                                                        UNDI32Device->NicInfo.Io_Function,

+                                                        EfiPciIoAttributeOperationSet,

+                                                        UNDI32Device->NicInfo.OriginalPciAttributes,

+                                                        NULL

+                                                        );

+

+          ASSERT_EFI_ERROR (Status);

+

+          gBS->FreePool (UNDI32Device->Undi32DevPath);

+          gBS->FreePool (UNDI32Device);

+

+        }

+      }

+    }

+

+    if (EFI_ERROR (Status)) {

+      AllChildrenStopped = FALSE;

+    }

+  }

+

+  if (!AllChildrenStopped) {

+    return EFI_DEVICE_ERROR;

+  }

+

+  return EFI_SUCCESS;

+

+}

+

+

+/**

+  Use the EFI boot services to produce a pause. This is also the routine which

+  gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can

+  do it's own pause.

+

+  @param  UnqId                Runtime O/S routine might use this, this temp

+                               routine does not use it

+  @param  MicroSeconds         Determines the length of pause.

+

+  @return none

+

+**/

+VOID

+TmpDelay (

+  IN UINT64 UnqId,

+  IN UINTN  MicroSeconds

+  )

+{

+  gBS->Stall ((UINT32) MicroSeconds);

+}

+

+

+/**

+  Use the PCI IO abstraction to issue memory or I/O reads and writes.  This is also the routine which

+  gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions.

+

+  @param  UnqId                Runtime O/S routine may use this field, this temp

+                               routine does not.

+  @param  ReadWrite            Determine if it is an I/O or Memory Read/Write

+                               Operation.

+  @param  Len                  Determines the width of the data operation.

+  @param  Port                 What port to Read/Write from.

+  @param  BuffAddr             Address to read to or write from.

+

+  @return none

+

+**/

+VOID

+TmpMemIo (

+  IN UINT64 UnqId,

+  IN UINT8  ReadWrite,

+  IN UINT8  Len,

+  IN UINT64 Port,

+  IN UINT64 BuffAddr

+  )

+{

+  EFI_PCI_IO_PROTOCOL_WIDTH Width;

+  NIC_DATA_INSTANCE         *AdapterInfo;

+

+  Width       = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;

+  AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId;

+  switch (Len) {

+  case 2:

+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;

+    break;

+

+  case 4:

+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;

+    break;

+

+  case 8:

+    Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;

+    break;

+  }

+

+  switch (ReadWrite) {

+  case PXE_IO_READ:

+    AdapterInfo->Io_Function->Io.Read (

+                                  AdapterInfo->Io_Function,

+                                  Width,

+                                  1,

+                                  Port,

+                                  1,

+                                  (VOID *) (UINTN) (BuffAddr)

+                                  );

+    break;

+

+  case PXE_IO_WRITE:

+    AdapterInfo->Io_Function->Io.Write (

+                                  AdapterInfo->Io_Function,

+                                  Width,

+                                  1,

+                                  Port,

+                                  1,

+                                  (VOID *) (UINTN) (BuffAddr)

+                                  );

+    break;

+

+  case PXE_MEM_READ:

+    AdapterInfo->Io_Function->Mem.Read (

+                                    AdapterInfo->Io_Function,

+                                    Width,

+                                    0,

+                                    Port,

+                                    1,

+                                    (VOID *) (UINTN) (BuffAddr)

+                                    );

+    break;

+

+  case PXE_MEM_WRITE:

+    AdapterInfo->Io_Function->Mem.Write (

+                                    AdapterInfo->Io_Function,

+                                    Width,

+                                    0,

+                                    Port,

+                                    1,

+                                    (VOID *) (UINTN) (BuffAddr)

+                                    );

+    break;

+  }

+

+  return ;

+}

+

+

+/**

+  Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space

+  for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)

+  and an added MAC node.

+

+  @param  DevPtr               Pointer which will point to the newly created device

+                               path with the MAC node attached.

+  @param  BaseDevPtr           Pointer to the device path which the UNDI device

+                               driver is latching on to.

+  @param  AdapterInfo          Pointer to the NIC data structure information which

+                               the UNDI driver is layering on..

+

+  @retval EFI_SUCCESS          A MAC address was successfully appended to the Base

+                               Device Path.

+  @retval other                Not enough resources available to create new Device

+                               Path node.

+

+**/

+EFI_STATUS

+AppendMac2DevPath (

+  IN OUT  EFI_DEVICE_PATH_PROTOCOL **DevPtr,

+  IN      EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,

+  IN      NIC_DATA_INSTANCE        *AdapterInfo

+  )

+{

+  EFI_MAC_ADDRESS           MACAddress;

+  PCI_CONFIG_HEADER         *CfgHdr;

+  INT32                     Val;

+  INT32                     Index;

+  INT32                     Index2;

+  UINT8                     AddrLen;

+  MAC_ADDR_DEVICE_PATH      MacAddrNode;

+  EFI_DEVICE_PATH_PROTOCOL  *EndNode;

+  UINT8                     *DevicePtr;

+  UINT16                    TotalPathLen;

+  UINT16                    BasePathLen;

+  EFI_STATUS                Status;

+

+  //

+  // set the environment ready (similar to UNDI_Start call) so that we can

+  // execute the other UNDI_ calls to get the mac address

+  // we are using undi 3.1 style

+  //

+  AdapterInfo->Delay      = TmpDelay;

+  AdapterInfo->Virt2Phys  = (VOID *) 0;

+  AdapterInfo->Block      = (VOID *) 0;

+  AdapterInfo->Map_Mem    = (VOID *) 0;

+  AdapterInfo->UnMap_Mem  = (VOID *) 0;

+  AdapterInfo->Sync_Mem   = (VOID *) 0;

+  AdapterInfo->Mem_Io     = TmpMemIo;

+  //

+  // these tmp call-backs follow 3.1 undi style

+  // i.e. they have the unique_id parameter.

+  //

+  AdapterInfo->VersionFlag  = 0x31;

+  AdapterInfo->Unique_ID    = (UINT64) (UINTN) AdapterInfo;

+

+  //

+  // undi init portion

+  //

+  CfgHdr              = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);

+  AdapterInfo->ioaddr = 0;

+  AdapterInfo->RevID  = CfgHdr->RevID;

+

+  AddrLen             = E100bGetEepromAddrLen (AdapterInfo);

+

+  for (Index = 0, Index2 = 0; Index < 3; Index++) {

+    Val                       = E100bReadEeprom (AdapterInfo, Index, AddrLen);

+    MACAddress.Addr[Index2++] = (UINT8) Val;

+    MACAddress.Addr[Index2++] = (UINT8) (Val >> 8);

+  }

+

+  SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0);

+  //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) {

+  //  MACAddress.Addr[Index2] = 0;

+  //}

+  //

+  // stop undi

+  //

+  AdapterInfo->Delay  = (VOID *) 0;

+  AdapterInfo->Mem_Io = (VOID *) 0;

+

+  //

+  // fill the mac address node first

+  //

+  ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode);

+  CopyMem (

+    (CHAR8 *) &MacAddrNode.MacAddress,

+    (CHAR8 *) &MACAddress,

+    sizeof (EFI_MAC_ADDRESS)

+    );

+

+  MacAddrNode.Header.Type       = MESSAGING_DEVICE_PATH;

+  MacAddrNode.Header.SubType    = MSG_MAC_ADDR_DP;

+  MacAddrNode.Header.Length[0]  = (UINT8) sizeof (MacAddrNode);

+  MacAddrNode.Header.Length[1]  = 0;

+

+  //

+  // find the size of the base dev path.

+  //

+  EndNode = BaseDevPtr;

+

+  while (!IsDevicePathEnd (EndNode)) {

+    EndNode = NextDevicePathNode (EndNode);

+  }

+

+  BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));

+

+  //

+  // create space for full dev path

+  //

+  TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));

+

+  Status = gBS->AllocatePool (

+                  EfiRuntimeServicesData,

+                  TotalPathLen,

+                  (VOID **) &DevicePtr

+                  );

+

+  if (Status != EFI_SUCCESS) {

+    return Status;

+  }

+  //

+  // copy the base path, mac addr and end_dev_path nodes

+  //

+  *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;

+  CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen);

+  DevicePtr += BasePathLen;

+  CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode));

+  DevicePtr += sizeof (MacAddrNode);

+  CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Install a GUID/Pointer pair into the system's configuration table.

+

+  none

+

+  @retval EFI_SUCCESS          Install a GUID/Pointer pair into the system's

+                               configuration table.

+  @retval other                Did not successfully install the GUID/Pointer pair

+                               into the configuration table.

+

+**/

+// TODO:    VOID - add argument and description to function comment

+EFI_STATUS

+InstallConfigTable (

+  IN VOID

+  )

+{

+  EFI_STATUS              Status;

+  EFI_CONFIGURATION_TABLE *CfgPtr;

+  UNDI_CONFIG_TABLE       *TmpData;

+  UINT16                  Index;

+  UNDI_CONFIG_TABLE       *UndiData;

+

+  if (pxe_31 == NULL) {

+    return EFI_SUCCESS;

+  }

+

+  if(UndiDataPointer == NULL) {

+    return EFI_SUCCESS;

+  }

+

+  UndiData = (UNDI_CONFIG_TABLE *)UndiDataPointer;

+

+  UndiData->NumberOfInterfaces  = (pxe_31->IFcnt | pxe_31->IFcntExt << 8);

+  UndiData->nextlink            = NULL;

+

+  for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) {

+    UndiData->NII_entry[Index].NII_InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;

+    UndiData->NII_entry[Index].DevicePathPointer    = UNDI32DeviceList[Index]->Undi32DevPath;

+  }

+

+  //

+  // see if there is an entry in the config table already

+  //

+  CfgPtr = gST->ConfigurationTable;

+

+  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {

+    Status = CompareGuid (

+              &CfgPtr->VendorGuid,

+              &gEfiNetworkInterfaceIdentifierProtocolGuid_31

+              );

+    if (Status != EFI_SUCCESS) {

+      break;

+    }

+

+    CfgPtr++;

+  }

+

+  if (Index < gST->NumberOfTableEntries) {

+    TmpData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable;

+

+    //

+    // go to the last link

+    //

+    while (TmpData->nextlink != NULL) {

+      TmpData = TmpData->nextlink;

+    }

+

+    TmpData->nextlink = UndiData;

+

+    //

+    // 1st one in chain

+    //

+    UndiData = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable;

+  }

+

+  //

+  // create an entry in the configuration table for our GUID

+  //

+  Status = gBS->InstallConfigurationTable (

+                  &gEfiNetworkInterfaceIdentifierProtocolGuid_31,

+                  UndiData

+                  );

+  return Status;

+}

+

+/**

+

+**/

+EFI_STATUS

+EFIAPI

+InitializeUndi(

+  IN EFI_HANDLE           ImageHandle,

+  IN EFI_SYSTEM_TABLE     *SystemTable

+  )

+{

+  EFI_EVENT     Event;

+  EFI_STATUS    Status;

+

+  Status = EfiLibInstallDriverBindingComponentName2 (

+             ImageHandle,

+             SystemTable,

+             &gUndiDriverBinding,

+             ImageHandle,

+             &gUndiComponentName,

+             &gUndiComponentName2

+             );

+  ASSERT_EFI_ERROR (Status);

+

+  Status = gBS->CreateEventEx (

+                  EVT_NOTIFY_SIGNAL,

+                  TPL_NOTIFY,

+                  UndiNotifyExitBs,

+                  NULL,

+                  &gEfiEventExitBootServicesGuid,

+                  &Event

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  Status = gBS->CreateEventEx (

+                  EVT_NOTIFY_SIGNAL,

+                  TPL_NOTIFY,

+                  UndiNotifyVirtual,

+                  NULL,

+                  &gEfiEventVirtualAddressChangeGuid,

+                  &Event

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  return Status;

+}

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Undi32.h b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Undi32.h
new file mode 100644
index 0000000..2bc019e
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/Undi32.h
@@ -0,0 +1,353 @@
+/** @file

+  EFI internal structures for the EFI UNDI driver.

+

+Copyright (c) 2006 - 2012, 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.

+

+**/

+

+#ifndef _UNDI_32_H_

+#define _UNDI_32_H_

+

+#include <Uefi.h>

+

+#include <Guid/EventGroup.h>

+#include <Protocol/PciIo.h>

+#include <Protocol/NetworkInterfaceIdentifier.h>

+#include <Protocol/DevicePath.h>

+

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/UefiRuntimeLib.h>

+#include <Library/DebugLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiLib.h>

+#include <Library/BaseLib.h>

+#include <Library/DevicePathLib.h>

+

+#include <IndustryStandard/Pci.h>

+

+

+#include "E100b.h"

+

+extern EFI_DRIVER_BINDING_PROTOCOL  gUndiDriverBinding;

+extern EFI_COMPONENT_NAME_PROTOCOL  gUndiComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL gUndiComponentName2;

+

+#define MAX_NIC_INTERFACES 16

+

+#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31 0x00010001

+#define PXE_ROMID_MINORVER_31 0x10

+#define PXE_STATFLAGS_DB_WRITE_TRUNCATED  0x2000

+

+//

+// UNDI_CALL_TABLE.state can have the following values

+//

+#define DONT_CHECK -1

+#define ANY_STATE -1

+#define MUST_BE_STARTED 1

+#define MUST_BE_INITIALIZED 2

+

+#define UNDI_DEV_SIGNATURE   SIGNATURE_32('u','n','d','i')

+#define UNDI_DEV_FROM_THIS(a) CR(a, UNDI32_DEV, NIIProtocol_31, UNDI_DEV_SIGNATURE)

+#define UNDI_DEV_FROM_NIC(a) CR(a, UNDI32_DEV, NicInfo, UNDI_DEV_SIGNATURE)

+

+typedef struct {

+  UINTN                                     Signature;

+  EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NIIProtocol_31;

+  EFI_HANDLE                                DeviceHandle;

+  EFI_DEVICE_PATH_PROTOCOL                  *Undi32BaseDevPath;

+  EFI_DEVICE_PATH_PROTOCOL                  *Undi32DevPath;

+  NIC_DATA_INSTANCE                         NicInfo;

+} UNDI32_DEV;

+

+typedef struct {

+  UINT16 cpbsize;

+  UINT16 dbsize;

+  UINT16 opflags;

+  UINT16 state;

+  VOID (*api_ptr)();

+} UNDI_CALL_TABLE;

+

+typedef VOID (*ptr)(VOID);

+typedef VOID (*bsptr_30)(UINTN);

+typedef VOID (*virtphys_30)(UINT64, UINT64);

+typedef VOID (*block_30)(UINT32);

+typedef VOID (*mem_io_30)(UINT8, UINT8, UINT64, UINT64);

+

+typedef VOID (*bsptr)(UINT64, UINTN);

+typedef VOID (*virtphys)(UINT64, UINT64, UINT64);

+typedef VOID (*block)(UINT64, UINT32);

+typedef VOID (*mem_io)(UINT64, UINT8, UINT8, UINT64, UINT64);

+

+typedef VOID (*map_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);

+typedef VOID (*unmap_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);

+typedef VOID (*sync_mem)(UINT64, UINT64, UINT32, UINT32, UINT64);

+

+extern UNDI_CALL_TABLE  api_table[];

+extern PXE_SW_UNDI      *pxe_31;  // !pxe structure for 3.1 drivers

+extern UNDI32_DEV       *UNDI32DeviceList[MAX_NIC_INTERFACES];

+

+//

+// functions defined in e100b.c

+//

+UINT8 InByte (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Port);

+UINT16 InWord (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Port);

+UINT32 InLong (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Port);

+VOID  OutByte (NIC_DATA_INSTANCE *AdapterInfo, UINT8 Data, UINT32 Port);

+VOID  OutWord (NIC_DATA_INSTANCE *AdapterInfo, UINT16 Data, UINT32 Port);

+VOID  OutLong (NIC_DATA_INSTANCE *AdapterInfo, UINT32 Data, UINT32 Port);

+

+UINTN E100bInit (NIC_DATA_INSTANCE *AdapterInfo);

+UINTN E100bReset (NIC_DATA_INSTANCE *AdapterInfo, INT32 OpFlags);

+UINTN E100bShutdown (NIC_DATA_INSTANCE *AdapterInfo);

+UINTN E100bTransmit (NIC_DATA_INSTANCE *AdapterInfo, UINT64 cpb, UINT16 opflags);

+UINTN E100bReceive (NIC_DATA_INSTANCE *AdapterInfo, UINT64 cpb, UINT64 db);

+UINTN E100bSetfilter (NIC_DATA_INSTANCE *AdapterInfo, UINT16 New_filter,

+                      UINT64 cpb, UINT32 cpbsize);

+UINTN E100bStatistics(NIC_DATA_INSTANCE *AdapterInfo, UINT64 db, UINT16 dbsize);

+UINT8 E100bSetupIAAddr (NIC_DATA_INSTANCE *AdapterInfo);

+UINT8 E100bSetInterruptState (NIC_DATA_INSTANCE *AdapterInfo);

+

+UINT8 E100bGetEepromAddrLen (NIC_DATA_INSTANCE *AdapterInfo);

+UINT16 E100bReadEeprom (NIC_DATA_INSTANCE *AdapterInfo, INT32 Location, UINT8 address_len);

+INT16 E100bReadEepromAndStationAddress (NIC_DATA_INSTANCE *AdapterInfo);

+

+UINT16 next(UINT16);

+UINT8 SetupCBlink (NIC_DATA_INSTANCE *AdapterInfo);

+VOID SetFreeCB (NIC_DATA_INSTANCE *AdapterInfo,TxCB *);

+TxCB *GetFreeCB (NIC_DATA_INSTANCE *AdapterInfo);

+UINT16 CheckCBList (NIC_DATA_INSTANCE *AdapterInfo);

+

+UINT8 SelectiveReset (NIC_DATA_INSTANCE *AdapterInfo);

+UINT16 InitializeChip (NIC_DATA_INSTANCE *AdapterInfo);

+UINT8 SetupReceiveQueues (NIC_DATA_INSTANCE *AdapterInfo);

+VOID  Recycle_RFD (NIC_DATA_INSTANCE *AdapterInfo, UINT16);

+VOID XmitWaitForCompletion (NIC_DATA_INSTANCE *AdapterInfo);

+INT8 CommandWaitForCompletion (TxCB *cmd_ptr, NIC_DATA_INSTANCE *AdapterInfo);

+

+BOOLEAN PhyDetect (NIC_DATA_INSTANCE *AdapterInfo);

+VOID PhyReset (NIC_DATA_INSTANCE *AdapterInfo);

+VOID

+MdiWrite (

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT8 RegAddress,

+  IN UINT8 PhyAddress,

+  IN UINT16 DataValue

+  );

+

+VOID

+MdiRead(

+  IN NIC_DATA_INSTANCE *AdapterInfo,

+  IN UINT8 RegAddress,

+  IN UINT8 PhyAddress,

+  IN OUT UINT16 *DataValue

+  );

+

+BOOLEAN SetupPhy (NIC_DATA_INSTANCE *AdapterInfo);

+VOID FindPhySpeedAndDpx (NIC_DATA_INSTANCE *AdapterInfo, UINT32 PhyId);

+

+

+

+//

+// functions defined in init.c

+//

+EFI_STATUS

+InstallConfigTable (

+  IN VOID

+  );

+

+EFI_STATUS

+EFIAPI

+InitializeUNDIDriver (

+  IN EFI_HANDLE           ImageHandle,

+  IN EFI_SYSTEM_TABLE     *SystemTable

+  );

+

+VOID

+UNDI_notify_virtual (

+  EFI_EVENT event,

+  VOID      *context

+  );

+

+VOID

+EFIAPI

+UndiNotifyExitBs (

+  EFI_EVENT Event,

+  VOID      *Context

+  );

+

+EFI_STATUS

+EFIAPI

+UndiDriverSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

+  );

+

+EFI_STATUS

+EFIAPI

+UndiDriverStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN EFI_HANDLE                     Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

+  );

+

+EFI_STATUS

+EFIAPI

+UndiDriverStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,

+  IN  EFI_HANDLE                     Controller,

+  IN  UINTN                          NumberOfChildren,

+  IN  EFI_HANDLE                     *ChildHandleBuffer

+  );

+

+EFI_STATUS

+AppendMac2DevPath (

+  IN OUT  EFI_DEVICE_PATH_PROTOCOL **DevPtr,

+  IN      EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,

+  IN      NIC_DATA_INSTANCE        *AdapterInfo

+  );

+

+VOID

+TmpDelay (

+  IN UINT64 UnqId,

+  IN UINTN MicroSeconds

+  );

+

+VOID

+TmpMemIo (

+  IN UINT64 UnqId,

+  IN UINT8 ReadWrite,

+  IN UINT8 Len,

+  IN UINT64 Port,

+  IN UINT64 BufAddr

+  );

+

+//

+// functions defined in decode.c

+//

+VOID

+UNDI_GetState (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Start (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Stop (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_GetInitInfo (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_GetConfigInfo (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Initialize (

+  IN  PXE_CDB       *CdbPtr,

+  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Reset (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Shutdown (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Interrupt (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_RecFilter (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_StnAddr (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Statistics (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_ip2mac (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_NVData (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Status (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_FillHeader (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Transmit (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID

+UNDI_Receive (

+  IN  PXE_CDB           *CdbPtr,

+  IN  NIC_DATA_INSTANCE *AdapterInfo

+  );

+

+VOID UNDI_APIEntry_new(UINT64);

+VOID UNDI_APIEntry_Common(UINT64);

+

+PXE_IPV4 convert_mcip(PXE_MAC_ADDR *);

+INT32 validate_mcip (PXE_MAC_ADDR *MCastAddr);

+

+VOID PxeStructInit (PXE_SW_UNDI *PxePtr);

+VOID PxeUpdate (NIC_DATA_INSTANCE *NicPtr, PXE_SW_UNDI *PxePtr);

+

+#endif

diff --git a/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf
new file mode 100644
index 0000000..654c5fc
--- /dev/null
+++ b/uefi/linaro-edk2/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf
@@ -0,0 +1,72 @@
+## @file

+# Component description file for Undi module.

+#

+# This module provides support for Universal Network Driver Interface

+# Copyright (c) 2006 - 2012, 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.

+#

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = UndiRuntimeDxe

+  FILE_GUID                      = A1f436EA-A127-4EF8-957C-8048606FF670

+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER

+  VERSION_STRING                 = 1.0

+

+  ENTRY_POINT                    = InitializeUndi

+

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+

+[Sources]

+  Undi32.h

+  E100b.h

+  E100b.c

+  Decode.c

+  Init.c

+  ComponentName.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+

+

+[LibraryClasses]

+  UefiLib

+  UefiBootServicesTableLib

+  BaseMemoryLib

+  DebugLib

+  UefiRuntimeLib

+  UefiDriverEntryPoint

+  BaseLib

+

+[Protocols]

+  gEfiNetworkInterfaceIdentifierProtocolGuid_31

+  gEfiPciIoProtocolGuid

+  gEfiDevicePathProtocolGuid

+

+[Guids]

+  gEfiEventExitBootServicesGuid        ## PRODUCES ## Event

+  gEfiEventVirtualAddressChangeGuid    ## PRODUCES ## Event

+

+[Depex]

+  gEfiBdsArchProtocolGuid AND

+  gEfiCpuArchProtocolGuid AND

+  gEfiMetronomeArchProtocolGuid AND

+  gEfiMonotonicCounterArchProtocolGuid AND

+  gEfiRealTimeClockArchProtocolGuid AND

+  gEfiResetArchProtocolGuid AND

+  gEfiRuntimeArchProtocolGuid AND

+  gEfiSecurityArchProtocolGuid AND

+  gEfiTimerArchProtocolGuid AND

+  gEfiVariableWriteArchProtocolGuid AND

+  gEfiVariableArchProtocolGuid AND

+  gEfiWatchdogTimerArchProtocolGuid