From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.120, mailfrom: ray.ni@intel.com) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by groups.io with SMTP; Fri, 10 May 2019 18:52:19 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 10 May 2019 18:52:17 -0700 X-ExtLoop1: 1 Received: from fmsmsx107.amr.corp.intel.com ([10.18.124.205]) by orsmga002.jf.intel.com with ESMTP; 10 May 2019 18:52:14 -0700 Received: from fmsmsx155.amr.corp.intel.com (10.18.116.71) by fmsmsx107.amr.corp.intel.com (10.18.124.205) with Microsoft SMTP Server (TLS) id 14.3.408.0; Fri, 10 May 2019 18:52:14 -0700 Received: from shsmsx106.ccr.corp.intel.com (10.239.4.159) by FMSMSX155.amr.corp.intel.com (10.18.116.71) with Microsoft SMTP Server (TLS) id 14.3.408.0; Fri, 10 May 2019 18:52:09 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.33]) by SHSMSX106.ccr.corp.intel.com ([169.254.10.213]) with mapi id 14.03.0415.000; Sat, 11 May 2019 09:52:06 +0800 From: "Ni, Ray" To: "Kinney, Michael D" , "devel@edk2.groups.io" CC: Leif Lindholm , Ard Biesheuvel Subject: Re: [edk2-platforms: Patch 7/8] Drivers/OptionRomPkg: Import OptionRomPkg from edk2 Thread-Topic: [edk2-platforms: Patch 7/8] Drivers/OptionRomPkg: Import OptionRomPkg from edk2 Thread-Index: AQHVBuFr2FwE/moIfEiw9leQo+VC5KZlKZyQ Date: Sat, 11 May 2019 01:52:05 +0000 Deferred-Delivery: Sat, 11 May 2019 01:52:00 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C13A8E2@SHSMSX104.ccr.corp.intel.com> References: <20190510033435.24112-1-michael.d.kinney@intel.com> <20190510033435.24112-8-michael.d.kinney@intel.com> In-Reply-To: <20190510033435.24112-8-michael.d.kinney@intel.com> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiODFkMGNhZjEtMTM3OS00NGU5LThjYmYtYWM2M2FjN2I4MzYzIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiWUZhWkdBWDhLYjBxejZ2NmdvMHF6STNMWHhzRytjZjNNTEhScXhmbFlsZWpMSis2SWVPcWlHYklFREp3OE9KVSJ9 x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.0.600.7 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: ray.ni@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Ray Ni > -----Original Message----- > From: Kinney, Michael D > Sent: Friday, May 10, 2019 11:35 AM > To: devel@edk2.groups.io > Cc: Ni, Ray ; Leif Lindholm ; > Ard Biesheuvel > Subject: [edk2-platforms: Patch 7/8] Drivers/OptionRomPkg: Import > OptionRomPkg from edk2 >=20 > https://bugzilla.tianocore.org/show_bug.cgi?id=3D1793 >=20 > Import OptionRomPkg from edk2/master. >=20 > Cc: Ray Ni > Cc: Leif Lindholm > Cc: Ard Biesheuvel > Signed-off-by: Michael D Kinney > --- > .../Application/BltLibSample/BltLibSample.c | 279 ++ > .../Application/BltLibSample/BltLibSample.inf | 30 + > .../AtapiPassThruDxe/AtapiPassThru.c | 3410 ++++++++++++++++ > .../AtapiPassThruDxe/AtapiPassThru.h | 1618 ++++++++ > .../AtapiPassThruDxe/AtapiPassThruDxe.inf | 70 + > .../AtapiPassThruDxe/ComponentName.c | 169 + > .../DriverSupportedEfiVersion.c | 14 + > .../FtdiUsbSerialDxe/CompatibleDevices.txt | 5 + > .../Bus/Usb/FtdiUsbSerialDxe/ComponentName.c | 218 + > .../FtdiUsbSerialDxe/FtdiUsbSerialDriver.c | 2580 ++++++++++++ > .../FtdiUsbSerialDxe/FtdiUsbSerialDriver.h | 589 +++ > .../Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf | 55 + > .../Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt | 32 + > .../Bus/Usb/UsbNetworking/Ax88772/Ax88772.c | 1318 ++++++ > .../Bus/Usb/UsbNetworking/Ax88772/Ax88772.h | 969 +++++ > .../Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf | 61 + > .../Usb/UsbNetworking/Ax88772/ComponentName.c | 178 + > .../Usb/UsbNetworking/Ax88772/DriverBinding.c | 507 +++ > .../Usb/UsbNetworking/Ax88772/SimpleNetwork.c | 1503 +++++++ > .../Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c | 875 ++++ > .../Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h | 1026 +++++ > .../Usb/UsbNetworking/Ax88772b/Ax88772b.inf | 61 + > .../UsbNetworking/Ax88772b/ComponentName.c | 175 + > .../UsbNetworking/Ax88772b/DriverBinding.c | 696 ++++ > .../UsbNetworking/Ax88772b/SimpleNetwork.c | 1657 ++++++++ > .../CirrusLogic5430Dxe/CirrusLogic5430.c | 917 +++++ > .../CirrusLogic5430Dxe/CirrusLogic5430.h | 432 ++ > .../CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf | 84 + > .../CirrusLogic5430GraphicsOutput.c | 556 +++ > .../CirrusLogic5430Dxe/CirrusLogic5430I2c.c | 427 ++ > .../CirrusLogic5430Dxe/CirrusLogic5430I2c.h | 62 + > .../CirrusLogic5430UgaDraw.c | 412 ++ > .../CirrusLogic5430Dxe/ComponentName.c | 203 + > .../DriverSupportedEfiVersion.c | 14 + > .../OptionRomPkg/CirrusLogic5430Dxe/Edid.c | 525 +++ > Drivers/OptionRomPkg/Include/Library/BltLib.h | 253 ++ > .../FrameBufferBltLib/FrameBufferBltLib.c | 744 ++++ > .../FrameBufferBltLib/FrameBufferBltLib.inf | 29 + > .../Library/GopBltLib/GopBltLib.c | 449 +++ > .../Library/GopBltLib/GopBltLib.inf | 31 + > Drivers/OptionRomPkg/OptionRomPkg.dec | 41 + > Drivers/OptionRomPkg/OptionRomPkg.dsc | 113 + > Drivers/OptionRomPkg/ReadMe.txt | 17 + > .../UndiRuntimeDxe/ComponentName.c | 359 ++ > Drivers/OptionRomPkg/UndiRuntimeDxe/Decode.c | 1516 +++++++ > Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.c | 3541 > +++++++++++++++++ > Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.h | 665 ++++ > Drivers/OptionRomPkg/UndiRuntimeDxe/Init.c | 1051 +++++ > Drivers/OptionRomPkg/UndiRuntimeDxe/Undi32.h | 439 ++ > .../OptionRomPkg/UndiRuntimeDxe/UndiAipImpl.c | 145 + > .../UndiRuntimeDxe/UndiRuntimeDxe.inf | 72 + > 51 files changed, 31192 insertions(+) > create mode 100644 > Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.c > create mode 100644 > Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.inf > create mode 100644 > Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c > create mode 100644 > Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h > create mode 100644 > Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf > create mode 100644 > Drivers/OptionRomPkg/AtapiPassThruDxe/ComponentName.c > create mode 100644 > Drivers/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/CompatibleDevices.txt > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentName > .c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentNam > e.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding.c > create mode 100644 > Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwork. > c > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutput. > c > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c > create mode 100644 > Drivers/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c > create mode 100644 Drivers/OptionRomPkg/CirrusLogic5430Dxe/Edid.c > create mode 100644 Drivers/OptionRomPkg/Include/Library/BltLib.h > create mode 100644 > Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c > create mode 100644 > Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf > create mode 100644 Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.c > create mode 100644 Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.inf > create mode 100644 Drivers/OptionRomPkg/OptionRomPkg.dec > create mode 100644 Drivers/OptionRomPkg/OptionRomPkg.dsc > create mode 100644 Drivers/OptionRomPkg/ReadMe.txt > create mode 100644 > Drivers/OptionRomPkg/UndiRuntimeDxe/ComponentName.c > create mode 100644 Drivers/OptionRomPkg/UndiRuntimeDxe/Decode.c > create mode 100644 Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.c > create mode 100644 Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.h > create mode 100644 Drivers/OptionRomPkg/UndiRuntimeDxe/Init.c > create mode 100644 Drivers/OptionRomPkg/UndiRuntimeDxe/Undi32.h > create mode 100644 > Drivers/OptionRomPkg/UndiRuntimeDxe/UndiAipImpl.c > create mode 100644 > Drivers/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf >=20 > diff --git a/Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.c > b/Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.c > new file mode 100644 > index 0000000000..6f901383b6 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.c > @@ -0,0 +1,279 @@ > +/** @file > + Example program using BltLib > + > + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > + > +UINT64 > +ReadTimestamp ( > + VOID > + ) > +{ > +#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) > + return AsmReadTsc (); > +#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 =3D 0; > + Found =3D 0; > + Tsc1 =3D ReadTimestamp (); > + Tsc2 =3D ReadTimestamp (); > + do { > + Tsc2 =3D ReadTimestamp (); > + TscBits =3D Tsc2 ^ Tsc1; > + Bits =3D HighBitSet64 (TscBits); > + if (Bits > 0) { > + Bits =3D Bits - 1; > + } > + R32 =3D (UINT32)((R32 << Bits) | > + RShiftU64 (LShiftU64 (TscBits, (UINTN) (64 - Bits)), = (UINTN) (64 - > Bits))); > + Found =3D 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 =3D 0; Loop < 10000; Loop++) { > + W =3D Width - (Rand32 () % Width); > + H =3D Height - (Rand32 () % Height); > + if (W !=3D Width) { > + X =3D Rand32 () % (Width - W); > + } else { > + X =3D 0; > + } > + if (H !=3D Height) { > + Y =3D Rand32 () % (Height - H); > + } else { > + Y =3D 0; > + } > + *(UINT32*) (&Color) =3D 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) =3D 0; > + > + for (Y =3D 0; Y < Height; Y++) { > + for (X =3D 0; X < Width; X++) { > + Color.Red =3D (UINT8) ((X * 0x100) / Width); > + Color.Green =3D (UINT8) ((Y * 0x100) / Height); > + Color.Blue =3D (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 =3D=3D 0) { > + return 0; > + } > + > + for (SqRt =3D 0, Mask =3D (UINT32) (1 << (HighBitSet32 (Uint32) / 2)); > + Mask !=3D 0; > + Mask =3D Mask >> 1 > + ) { > + SqRtMask =3D SqRt | Mask; > + //DEBUG ((EFI_D_INFO, "Uint32=3D0x%x SqRtMask=3D0x%x\n", Uint32, > SqRtMask)); > + Squared =3D (UINT32) (SqRtMask * SqRtMask); > + if (Squared > Uint32) { > + continue; > + } else if (Squared < Uint32) { > + SqRt =3D 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) =3D 0; > + BltLibVideoFill (&Color, 0, 0, ScreenWidth, ScreenHeight); > + > + TriWidth =3D (UINTN) DivU64x32 ( > + MultU64x32 (11547005, (UINT32) ScreenHeight), > + 10000000 > + ); > + TriHeight =3D (UINTN) DivU64x32 ( > + MultU64x32 (8660254, (UINT32) ScreenWidth), > + 10000000 > + ); > + if (TriWidth > ScreenWidth) { > + DEBUG ((EFI_D_INFO, "TriWidth at %d was too big\n", TriWidth)); > + TriWidth =3D ScreenWidth; > + } else if (TriHeight > ScreenHeight) { > + DEBUG ((EFI_D_INFO, "TriHeight at %d was too big\n", TriHeight)); > + TriHeight =3D ScreenHeight; > + } > + > + DEBUG ((EFI_D_INFO, "Triangle Width: %d; Height: %d\n", TriWidth, > TriHeight)); > + > + X1 =3D (ScreenWidth - TriWidth) / 2; > + X3 =3D X1 + TriWidth - 1; > + X2 =3D (X1 + X3) / 2; > + Y2 =3D (ScreenHeight - TriHeight) / 2; > + Y1 =3D Y2 + TriHeight - 1; > + > + for (Y =3D Y2; Y <=3D Y1; Y++) { > + LineWidth =3D > + (UINTN) DivU64x32 ( > + MultU64x32 (11547005, (UINT32) (Y - Y2)), > + 20000000 > + ); > + for (X =3D X2 - LineWidth; X < (X2 + LineWidth); X++) { > + ColorDist =3D Uint32Dist(X - X1, Y1 - Y); > + Color.Red =3D GetTriColor (ColorDist, TriWidth); > + > + ColorDist =3D Uint32Dist((X < X2) ? X2 - X : X - X2, Y - Y2); > + Color.Green =3D GetTriColor (ColorDist, TriWidth); > + > + ColorDist =3D Uint32Dist(X3 - X, Y1 - Y); > + Color.Blue =3D 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 =3D gBS->HandleProtocol ( > + gST->ConsoleOutHandle, > + &gEfiGraphicsOutputProtocolGuid, > + (VOID **) &Gop > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D BltLibConfigure ( > + (VOID*)(UINTN) Gop->Mode->FrameBufferBase, > + Gop->Mode->Info > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + TestFills (); > + > + TestColor (); > + > + return EFI_SUCCESS; > +} > diff --git a/Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.i= nf > b/Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.inf > new file mode 100644 > index 0000000000..b544f960ab > --- /dev/null > +++ b/Drivers/OptionRomPkg/Application/BltLibSample/BltLibSample.inf > @@ -0,0 +1,30 @@ > +## @file > +# Test the BltLib interface > +# > +# Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D BltLibSample > + FILE_GUID =3D f7763316-8c04-41d8-a87d-45b73c13c43= c > + MODULE_TYPE =3D UEFI_APPLICATION > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D UefiMain > + > +[Sources] > + BltLibSample.c > + > +[Packages] > + MdePkg/MdePkg.dec > + OptionRomPkg/OptionRomPkg.dec > + > +[LibraryClasses] > + BltLib > + UefiApplicationEntryPoint > + UefiLib > + > diff --git a/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c > b/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c > new file mode 100644 > index 0000000000..20de2bc392 > --- /dev/null > +++ b/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c > @@ -0,0 +1,3410 @@ > +/** @file > + Copyright (c) 2006, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "AtapiPassThru.h" > + > + > +SCSI_COMMAND_SET gEndTable =3D { 0xff, (DATA_DIRECTION) 0xff }; > + > +/// > +/// This table contains all the supported ATAPI commands. > +/// > +SCSI_COMMAND_SET gSupportedATAPICommands[] =3D { > + { 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 =3D { > + 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 =3D { > + &gScsiPassThruMode, > + AtapiScsiPassThruFunction, > + AtapiScsiPassThruGetNextDevice, > + AtapiScsiPassThruBuildDevicePath, > + AtapiScsiPassThruGetTargetLun, > + AtapiScsiPassThruResetChannel, > + AtapiScsiPassThruResetTarget > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE > gExtScsiPassThruMode =3D { > + 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 =3D { > + &gExtScsiPassThruMode, > + AtapiExtScsiPassThruFunction, > + AtapiExtScsiPassThruGetNextTargetLun, > + AtapiExtScsiPassThruBuildDevicePath, > + AtapiExtScsiPassThruGetTargetLun, > + AtapiExtScsiPassThruResetChannel, > + AtapiExtScsiPassThruResetTarget, > + AtapiExtScsiPassThruGetNextTarget > +}; > + > +EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding =3D { > + 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 ControllerHa= ndle > + 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 =3D 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 t= hat > + // can be managed by this driver. Read the PCI Configuration Header > + // for this device. > + // > + Status =3D 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] !=3D PCI_CLASS_MASS_STORAGE || > Pci.Hdr.ClassCode[1] !=3D PCI_CLASS_MASS_STORAGE_IDE) { > + > + Status =3D 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 =3D NULL; > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + (VOID **) &PciIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + PciAttributesSaved =3D FALSE; > + // > + // Save original PCI attributes > + // > + Status =3D PciIo->Attributes ( > + PciIo, > + EfiPciIoAttributeOperationGet, > + 0, > + &OriginalPciAttributes > + ); > + > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + PciAttributesSaved =3D TRUE; > + > + Status =3D PciIo->Attributes ( > + PciIo, > + EfiPciIoAttributeOperationSupported, > + 0, > + &Supports > + ); > + if (!EFI_ERROR (Status)) { > + Supports &=3D (EFI_PCI_DEVICE_ENABLE | > + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | > + EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO); > + Status =3D PciIo->Attributes ( > + PciIo, > + EfiPciIoAttributeOperationEnable, > + Supports, > + NULL > + ); > + } > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + // > + // Create SCSI Pass Thru instance for the IDE channel. > + // > + Status =3D RegisterAtapiScsiPassThru (This, Controller, PciIo, > OriginalPciAttributes); > + > +Done: > + if (EFI_ERROR (Status)) { > + if (PciAttributesSaved =3D=3D 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 stopping any child handl= es > + 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 =3D gBS->OpenProtocol ( > + Controller, > + &gEfiScsiPassThruProtocolGuid, > + (VOID **) &ScsiPassThru, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + AtapiScsiPrivate =3D ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS > (ScsiPassThru); > + if (FeaturePcdGet (PcdSupportExtScsiPassThru)) { > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > + Controller, > + &gEfiScsiPassThruProtocolGuid, > + &AtapiScsiPrivate->ScsiPassThru, > + &gEfiExtScsiPassThruProtocolGuid, > + &AtapiScsiPrivate->ExtScsiPassThru, > + NULL > + ); > + } else { > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > + Controller, > + &gEfiScsiPassThruProtocolGuid, > + &AtapiScsiPrivate->ScsiPassThru, > + NULL > + ); > + } > + } else { > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiExtScsiPassThruProtocolGuid, > + (VOID **) &ExtScsiPassThru, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + AtapiScsiPrivate =3D ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS > (ExtScsiPassThru); > + Status =3D 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 fa= iled. > + > +--*/ > +{ > + EFI_STATUS Status; > + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; > + IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[ATAPI_MAX_CHANNEL]; > + > + AtapiScsiPrivate =3D AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DE= V)); > + if (AtapiScsiPrivate =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + AtapiScsiPrivate->Signature =3D ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE; > + AtapiScsiPrivate->Handle =3D Controller; > + > + // > + // will reset the IoPort inside each API function. > + // > + AtapiScsiPrivate->IoPort =3D NULL; > + AtapiScsiPrivate->PciIo =3D PciIo; > + AtapiScsiPrivate->OriginalPciAttributes =3D OriginalPciAttributes; > + > + // > + // Obtain IDE IO port registers' base addresses > + // > + Status =3D GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr); > + > + // > + // Initialize the LatestTargetId to MAX_TARGET_ID. > + // > + AtapiScsiPrivate->LatestTargetId =3D MAX_TARGET_ID; > + AtapiScsiPrivate->LatestLun =3D 0; > + > + Status =3D 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 signal= ed > + when the SCSI Request Packet completes. > + > +Returns: > + > + EFI_STATUS > + > +--*/ > +{ > + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; > + EFI_STATUS Status; > + > + AtapiScsiPrivate =3D ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + > + // > + // Target is not allowed beyond MAX_TARGET_ID > + // > + if ((Target > MAX_TARGET_ID) || (Lun !=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // check the data fields in Packet parameter. > + // > + Status =3D CheckSCSIRequestPacket (Packet); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // If Request Packet targets at the IDE channel itself, > + // do nothing. > + // > + if (Target =3D=3D This->Mode->AdapterId) { > + Packet->TransferLength =3D 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) =3D=3D 0) { > + Target =3D Target % 2; > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate->AtapiIoPortRegisters= [0]; > + } else { > + Target =3D Target % 2; > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate->AtapiIoPortRegisters= [1]; > + } > + > + // > + // the ATAPI SCSI interface does not support non-blocking I/O > + // ignore the Event parameter > + // > + // Performs blocking I/O. > + // > + Status =3D 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 de= vice > + present on a SCSI channel. An input value of > + 0xFFFFFFFF retrieves the Target ID of the firs= t > + SCSI device present on a SCSI channel. > + Lun - On input, a pointer to the LUN of a SCSI devic= e > + present on the SCSI channel. On output, a poin= ter > + 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 =3D ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + > + // > + // Check whether Target is valid. > + // > + if (Target =3D=3D NULL || Lun =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((*Target !=3D 0xFFFFFFFF) && > + ((*Target !=3D AtapiScsiPrivate->LatestTargetId) || > + (*Lun !=3D AtapiScsiPrivate->LatestLun))) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (*Target =3D=3D MAX_TARGET_ID) { > + return EFI_NOT_FOUND; > + } > + > + if (*Target =3D=3D 0xFFFFFFFF) { > + *Target =3D 0; > + } else { > + *Target =3D AtapiScsiPrivate->LatestTargetId + 1; > + } > + > + *Lun =3D 0; > + > + // > + // Update the LatestTargetId. > + // > + AtapiScsiPrivate->LatestTargetId =3D *Target; > + AtapiScsiPrivate->LatestLun =3D *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 Control= ler. > + > +Arguments: > + > + This - Protocol instance pointer. > + Target - The Target ID of the SCSI device for which > + a device path node is to be allocated and buil= t. > + 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 cal= ler > + is finished with DevicePath. > + Returns: > + EFI_SUCCESS - The device path node that describes the SCSI d= evice > + specified by Target and Lun was allocated and > + returned in DevicePath. > + EFI_NOT_FOUND - The SCSI devices specified by Target and Lun d= oes > + 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 =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // can not build device path for the SCSI Host Controller. > + // > + if ((Target > (MAX_TARGET_ID - 1)) || (Lun !=3D 0)) { > + return EFI_NOT_FOUND; > + } > + > + Node =3D AllocateZeroPool (sizeof (EFI_DEV_PATH)); > + if (Node =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Node->DevPath.Type =3D MESSAGING_DEVICE_PATH; > + Node->DevPath.SubType =3D MSG_ATAPI_DP; > + SetDevicePathNodeLength (&Node->DevPath, sizeof > (ATAPI_DEVICE_PATH)); > + > + Node->Atapi.PrimarySecondary =3D (UINT8) (Target / 2); > + Node->Atapi.SlaveMaster =3D (UINT8) (Target % 2); > + Node->Atapi.Lun =3D (UINT16) Lun; > + > + *DevicePath =3D (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 =3D=3D NULL || Target =3D=3D NULL || Lun =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check whether the DevicePath belongs to SCSI_DEVICE_PATH > + // > + if ((DevicePath->Type !=3D MESSAGING_DEVICE_PATH) || > + (DevicePath->SubType !=3D MSG_ATAPI_DP) || > + (DevicePathNodeLength(DevicePath) !=3D sizeof(ATAPI_DEVICE_PATH)))= { > + return EFI_UNSUPPORTED; > + } > + > + Node =3D (EFI_DEV_PATH *) DevicePath; > + > + *Target =3D Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster= ; > + *Lun =3D Node->Atapi.Lun; > + > + if (*Target > (MAX_TARGET_ID - 1) || *Lun !=3D 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 =3D ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + ResetFlag =3D FALSE; > + > + // > + // Reset both Primary channel and Secondary channel. > + // so, the IoPort pointer must point to the right I/O Register group > + // > + for (Index =3D 0; Index < 2; Index++) { > + // > + // Reset > + // > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate- > >AtapiIoPortRegisters[Index]; > + > + DeviceControlValue =3D 0; > + // > + // set SRST bit to initiate soft reset > + // > + DeviceControlValue |=3D SRST; > + // > + // disable Interrupt > + // > + DeviceControlValue |=3D BIT1; > + WritePortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Alt.DeviceControl, > + DeviceControlValue > + ); > + > + // > + // Wait 10us > + // > + gBS->Stall (10); > + > + // > + // Clear SRST bit > + // 0xfb:1111,1011 > + // > + DeviceControlValue &=3D 0xfb; > + > + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort- > >Alt.DeviceControl, DeviceControlValue); > + > + // > + // slave device needs at most 31s to clear BSY > + // > + if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) !=3D EFI_TIME= OUT) { > + ResetFlag =3D 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 =3D ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + > + if ((Target > MAX_TARGET_ID) || (Lun !=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + // > + // Directly return EFI_SUCCESS if want to reset the host controller > + // > + if (Target =3D=3D 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) =3D=3D 0) { > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate->AtapiIoPortRegisters= [0]; > + } else { > + AtapiScsiPrivate->IoPort =3D &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 =3D (UINT8) (((BIT7 | BIT5) | (Target << 4))); > + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, > DeviceSelect); > + > + Command =3D 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 signal= ed > + when the SCSI Request Packet completes. > + > +Returns: > + > + EFI_STATUS > + > +--*/ > +{ > + EFI_STATUS Status; > + ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate; > + UINT8 TargetId; > + > + AtapiScsiPrivate =3D ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + > + // > + // For ATAPI device, UINT8 is enough to represent the SCSI ID on chann= el. > + // > + TargetId =3D Target[0]; > + > + // > + // Target is not allowed beyond MAX_TARGET_ID > + // > + if ((TargetId > MAX_TARGET_ID) || (Lun !=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // check the data fields in Packet parameter. > + // > + Status =3D CheckExtSCSIRequestPacket (Packet); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // If Request Packet targets at the IDE channel itself, > + // do nothing. > + // > + if (TargetId =3D=3D (UINT8)This->Mode->AdapterId) { > + Packet->InTransferLength =3D Packet->OutTransferLength =3D 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) =3D=3D 0) { > + TargetId =3D (UINT8) (TargetId % 2); > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate->AtapiIoPortRegisters= [0]; > + } else { > + TargetId =3D (UINT8) (TargetId % 2); > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate->AtapiIoPortRegisters= [1]; > + } > + > + // > + // the ATAPI SCSI interface does not support non-blocking I/O > + // ignore the Event parameter > + // > + // Performs blocking I/O. > + // > + Status =3D SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Pac= ket); > + 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 de= vice > + present on a SCSI channel. An input value of > + 0xFFFFFFFF retrieves the Target ID of the firs= t > + SCSI device present on a SCSI channel. > + Lun - On input, a pointer to the LUN of a SCSI devic= e > + present on the SCSI channel. On output, a poin= ter > + 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 =3D ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + > + // > + // Check whether Target is valid. > + // > + if (*Target =3D=3D NULL || Lun =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF); > + > + TargetId =3D (*Target)[0]; > + > + // > + // For ATAPI device, we use UINT8 to represent the SCSI ID on channel. > + // > + if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) !=3D 0) { > + for (ByteIndex =3D 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) { > + if ((*Target)[ByteIndex] !=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + } > + } > + > + if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) !=3D 0) && > + ((TargetId !=3D AtapiScsiPrivate->LatestTargetId) || > + (*Lun !=3D AtapiScsiPrivate->LatestLun))) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (TargetId =3D=3D MAX_TARGET_ID) { > + return EFI_NOT_FOUND; > + } > + > + if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) =3D=3D 0) { > + SetMem (*Target, TARGET_MAX_BYTES,0); > + } else { > + (*Target)[0] =3D (UINT8) (AtapiScsiPrivate->LatestTargetId + 1); > + } > + > + *Lun =3D 0; > + > + // > + // Update the LatestTargetId. > + // > + AtapiScsiPrivate->LatestTargetId =3D (*Target)[0]; > + AtapiScsiPrivate->LatestLun =3D *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 Control= ler. > + > +Arguments: > + > + This - Protocol instance pointer. > + Target - The Target ID of the SCSI device for which > + a device path node is to be allocated and buil= t. > + 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 cal= ler > + is finished with DevicePath. > + Returns: > + EFI_SUCCESS - The device path node that describes the SCSI d= evice > + specified by Target and Lun was allocated and > + returned in DevicePath. > + EFI_NOT_FOUND - The SCSI devices specified by Target and Lun d= oes > + 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 =3D Target[0]; > + > + // > + // Validate parameters passed in. > + // > + > + if (DevicePath =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // can not build device path for the SCSI Host Controller. > + // > + if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun !=3D 0)) { > + return EFI_NOT_FOUND; > + } > + > + Node =3D AllocateZeroPool (sizeof (EFI_DEV_PATH)); > + if (Node =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Node->DevPath.Type =3D MESSAGING_DEVICE_PATH; > + Node->DevPath.SubType =3D MSG_ATAPI_DP; > + SetDevicePathNodeLength (&Node->DevPath, sizeof > (ATAPI_DEVICE_PATH)); > + > + Node->Atapi.PrimarySecondary =3D (UINT8) (TargetId / 2); > + Node->Atapi.SlaveMaster =3D (UINT8) (TargetId % 2); > + Node->Atapi.Lun =3D (UINT16) Lun; > + > + *DevicePath =3D (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 =3D=3D NULL || Target =3D=3D NULL || Lun =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check whether the DevicePath belongs to SCSI_DEVICE_PATH > + // > + if ((DevicePath->Type !=3D MESSAGING_DEVICE_PATH) || > + (DevicePath->SubType !=3D MSG_ATAPI_DP) || > + (DevicePathNodeLength(DevicePath) !=3D sizeof(ATAPI_DEVICE_PATH)))= { > + return EFI_UNSUPPORTED; > + } > + > + ZeroMem (*Target, TARGET_MAX_BYTES); > + > + Node =3D (EFI_DEV_PATH *) DevicePath; > + > + (*Target)[0] =3D (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node- > >Atapi.SlaveMaster); > + *Lun =3D Node->Atapi.Lun; > + > + if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun !=3D 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 =3D ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + ResetFlag =3D 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 =3D 0; Index < 2; Index++) { > + // > + // Reset > + // > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate- > >AtapiIoPortRegisters[Index]; > + > + DeviceControlValue =3D 0; > + // > + // set SRST bit to initiate soft reset > + // > + DeviceControlValue |=3D SRST; > + // > + // disable Interrupt > + // > + DeviceControlValue |=3D BIT1; > + WritePortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Alt.DeviceControl, > + DeviceControlValue > + ); > + > + // > + // Wait 10us > + // > + gBS->Stall (10); > + > + // > + // Clear SRST bit > + // 0xfb:1111,1011 > + // > + DeviceControlValue &=3D 0xfb; > + > + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort- > >Alt.DeviceControl, DeviceControlValue); > + > + // > + // slave device needs at most 31s to clear BSY > + // > + if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) !=3D EFI_TIME= OUT) { > + ResetFlag =3D 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 =3D ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + TargetId =3D Target[0]; > + > + if ((TargetId > MAX_TARGET_ID) || (Lun !=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + // > + // Directly return EFI_SUCCESS if want to reset the host controller > + // > + if (TargetId =3D=3D 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) =3D=3D 0) { > + AtapiScsiPrivate->IoPort =3D &AtapiScsiPrivate->AtapiIoPortRegisters= [0]; > + } else { > + AtapiScsiPrivate->IoPort =3D &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 =3D (UINT8) ((BIT7 | BIT5) | (TargetId << 4)); > + WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, > DeviceSelect); > + > + Command =3D 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 de= vice > + present on a SCSI channel. An input value of > + 0xFFFFFFFF retrieves the Target ID of the fir= st > + SCSI device present on a SCSI channel. > + Lun - On input, a pointer to the LUN of a SCSI devic= e > + present on the SCSI channel. On output, a poin= ter > + 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 =3D ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This); > + > + // > + // Check whether Target is valid. > + // > + if (*Target =3D=3D NULL ) { > + return EFI_INVALID_PARAMETER; > + } > + > + TargetId =3D (*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) !=3D 0) { > + for (ByteIndex =3D 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) { > + if ((*Target)[ByteIndex] !=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + } > + } > + > + if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) !=3D 0) > &&(TargetId !=3D AtapiScsiPrivate->LatestTargetId)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (TargetId =3D=3D MAX_TARGET_ID) { > + return EFI_NOT_FOUND; > + } > + > + if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) =3D=3D 0)) { > + SetMem (*Target, TARGET_MAX_BYTES, 0); > + } else { > + (*Target)[0] =3D (UINT8) (AtapiScsiPrivate->LatestTargetId + 1); > + } > + > + // > + // Update the LatestTargetId. > + // > + AtapiScsiPrivate->LatestTargetId =3D (*Target)[0]; > + AtapiScsiPrivate->LatestLun =3D 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 =3D PciIo->Pci.Read ( > + PciIo, > + EfiPciIoWidthUint8, > + 0, > + sizeof (PciData), > + &PciData > + ); > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) =3D=3D 0) = { > + IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =3D 0x1f0; > + IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =3D 0x3f6; > + } else { > + // > + // The BARs should be of IO type > + // > + if ((PciData.Device.Bar[0] & BIT0) =3D=3D 0 || > + (PciData.Device.Bar[1] & BIT0) =3D=3D 0) { > + return EFI_UNSUPPORTED; > + } > + > + IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =3D > + (UINT16) (PciData.Device.Bar[0] & 0x0000fff8); > + IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =3D > + (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2); > + } > + > + if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) =3D=3D 0= ) > { > + IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =3D 0x170; > + IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =3D 0x376; > + } else { > + // > + // The BARs should be of IO type > + // > + if ((PciData.Device.Bar[2] & BIT0) =3D=3D 0 || > + (PciData.Device.Bar[3] & BIT0) =3D=3D 0) { > + return EFI_UNSUPPORTED; > + } > + > + IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =3D > + (UINT16) (PciData.Device.Bar[2] & 0x0000fff8); > + IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =3D > + (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 ControlBloc= k. > + > +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 =3D 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) { > + > + RegisterPointer =3D &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChan= nel]; > + > + // > + // Initialize IDE IO port addresses, including Command Block registe= rs > + // and Control Block registers > + // > + CommandBlockBaseAddr =3D > IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr; > + ControlBlockBaseAddr =3D > IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr; > + > + RegisterPointer->Data =3D CommandBlockBaseAddr; > + (*(UINT16 *) &RegisterPointer->Reg1) =3D (UINT16) > (CommandBlockBaseAddr + 0x01); > + RegisterPointer->SectorCount =3D (UINT16) (CommandBlockBaseAddr + > 0x02); > + RegisterPointer->SectorNumber =3D (UINT16) (CommandBlockBaseAddr + > 0x03); > + RegisterPointer->CylinderLsb =3D (UINT16) (CommandBlockBaseAddr + > 0x04); > + RegisterPointer->CylinderMsb =3D (UINT16) (CommandBlockBaseAddr + > 0x05); > + RegisterPointer->Head =3D (UINT16) (CommandBlockBaseAddr + 0x06); > + (*(UINT16 *) &RegisterPointer->Reg) =3D (UINT16) > (CommandBlockBaseAddr + 0x07); > + > + (*(UINT16 *) &RegisterPointer->Alt) =3D ControlBlockBaseAddr; > + RegisterPointer->DriveAddress =3D (UINT16) (ControlBlockBaseAddr + 0= x01); > + } > + > +} > + > + > +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_PACKE= T > + > +Returns: > + > + EFI_STATUS > + > +--*/ > +{ > + if (Packet =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!ValidCdbLength (Packet->CdbLength)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Packet->Cdb =3D=3D 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_PACKE= T > + > +Returns: > + > + EFI_STATUS > + > +--*/ > +{ > + UINT8 Index; > + UINT8 *OpCode; > + UINT8 ArrayLen; > + > + OpCode =3D (UINT8 *) (Packet->Cdb); > + ArrayLen =3D (UINT8) (ARRAY_SIZE (gSupportedATAPICommands)); > + > + for (Index =3D 0; (Index < ArrayLen) && (CompareMem > (&gSupportedATAPICommands[Index], &gEndTable, sizeof > (SCSI_COMMAND_SET)) !=3D 0); Index++) { > + > + if (*OpCode =3D=3D gSupportedATAPICommands[Index].OpCode) { > + // > + // Check whether the requested Command is supported by this driver > + // > + if (Packet->DataDirection =3D=3D DataIn) { > + // > + // Check whether the requested data direction conforms to > + // what it should be. > + // > + if (gSupportedATAPICommands[Index].Direction =3D=3D DataOut) { > + return FALSE; > + } > + } > + > + if (Packet->DataDirection =3D=3D DataOut) { > + // > + // Check whether the requested data direction conforms to > + // what it should be. > + // > + if (gSupportedATAPICommands[Index].Direction =3D=3D 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 ID= E > + Channel, Target ID 0 indicates Master device;Targe= t > + ID 1 indicates Slave device. > + Packet: The SCSI Request Packet to send to the ATAPI devic= e > + 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 =3D DivU64x32 (Packet->Timeout, (UINT32) 10); > + > + // > + // Submit ATAPI Command Packet > + // > + PacketCommandStatus =3D AtapiPacketCommand ( > + AtapiScsiPrivate, > + Target, > + PacketCommand, > + Packet->DataBuffer, > + &(Packet->TransferLength), > + (DATA_DIRECTION) Packet->DataDirection, > + TimeoutInMicroSeconds > + ); > + if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData =3D=3D NULL= )) { > + Packet->SenseDataLength =3D 0; > + return PacketCommandStatus; > + } > + > + // > + // Return SenseData if PacketCommandStatus matches > + // the following return codes. > + // > + if ((PacketCommandStatus =3D=3D EFI_BAD_BUFFER_SIZE) || > + (PacketCommandStatus =3D=3D EFI_DEVICE_ERROR) || > + (PacketCommandStatus =3D=3D EFI_TIMEOUT)) { > + > + // > + // avoid submit request sense command continuously. > + // > + if (PacketCommand[0] =3D=3D OP_REQUEST_SENSE) { > + Packet->SenseDataLength =3D 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: > + > + Submit request sense command > + > +Arguments: > + > + AtapiScsiPrivate - The pointer 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] =3D OP_REQUEST_SENSE; > + Cdb[4] =3D (UINT8) (*SenseDataLength); > + > + Packet.Timeout =3D Timeout; > + Packet.DataBuffer =3D SenseData; > + Packet.SenseData =3D NULL; > + Packet.Cdb =3D Cdb; > + Packet.TransferLength =3D *SenseDataLength; > + Packet.CdbLength =3D 12; > + Packet.DataDirection =3D DataIn; > + > + Status =3D SubmitBlockingIoCommand (AtapiScsiPrivate, T= arget, > &Packet); > + *SenseDataLength =3D (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 =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!ValidCdbLength (Packet->CdbLength)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Packet->Cdb =3D=3D 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_PACKE= T > + > +Returns: > + > + EFI_STATUS > + > +--*/ > +{ > + UINT8 Index; > + UINT8 *OpCode; > + UINT8 ArrayLen; > + > + OpCode =3D (UINT8 *) (Packet->Cdb); > + ArrayLen =3D (UINT8) (ARRAY_SIZE (gSupportedATAPICommands)); > + > + for (Index =3D 0; (Index < ArrayLen) && (CompareMem > (&gSupportedATAPICommands[Index], &gEndTable, sizeof > (SCSI_COMMAND_SET)) !=3D 0); Index++) { > + > + if (*OpCode =3D=3D gSupportedATAPICommands[Index].OpCode) { > + // > + // Check whether the requested Command is supported by this driver > + // > + if (Packet->DataDirection =3D=3D DataIn) { > + // > + // Check whether the requested data direction conforms to > + // what it should be. > + // > + if (gSupportedATAPICommands[Index].Direction =3D=3D DataOut) { > + return FALSE; > + } > + } > + > + if (Packet->DataDirection =3D=3D DataOut) { > + // > + // Check whether the requested data direction conforms to > + // what it should be. > + // > + if (gSupportedATAPICommands[Index].Direction =3D=3D 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 ID= E > + Channel, Target ID 0 indicates Master device;Targe= t > + ID 1 indicates Slave device. > + Packet: The SCSI Request Packet to send to the ATAPI devic= e > + 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 =3D DivU64x32 (Packet->Timeout, (UINT32) 10); > + > + // > + // Submit ATAPI Command Packet > + // > + if (Packet->DataDirection =3D=3D DataIn) { > + PacketCommandStatus =3D AtapiPacketCommand ( > + AtapiScsiPrivate, > + Target, > + PacketCommand, > + Packet->InDataBuffer, > + &(Packet->InTransferLength), > + DataIn, > + TimeoutInMicroSeconds > + ); > + } else { > + > + PacketCommandStatus =3D AtapiPacketCommand ( > + AtapiScsiPrivate, > + Target, > + PacketCommand, > + Packet->OutDataBuffer, > + &(Packet->OutTransferLength), > + DataOut, > + TimeoutInMicroSeconds > + ); > + } > + > + if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData =3D=3D NULL= )) { > + Packet->SenseDataLength =3D 0; > + return PacketCommandStatus; > + } > + > + // > + // Return SenseData if PacketCommandStatus matches > + // the following return codes. > + // > + if ((PacketCommandStatus =3D=3D EFI_BAD_BUFFER_SIZE) || > + (PacketCommandStatus =3D=3D EFI_DEVICE_ERROR) || > + (PacketCommandStatus =3D=3D EFI_TIMEOUT)) { > + > + // > + // avoid submit request sense command continuously. > + // > + if (PacketCommand[0] =3D=3D OP_REQUEST_SENSE) { > + Packet->SenseDataLength =3D 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 ID= E > + Channel, Target ID 0 indicates Master device;Targe= t > + 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, the= n > + 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 =3D StatusWaitForBSYClear (AtapiScsiPrivate, > TimeoutInMicroSeconds); > + if (EFI_ERROR (Status)) { > + return EFI_DEVICE_ERROR; > + } > + > + > + // > + // Select device via Device/Head Register. > + // "Target =3D 0" indicates device 0; "Target =3D 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 =3D StatusDRQClear(AtapiScsiPrivate, TimeoutInMicroSeconds); > + > + if (EFI_ERROR (Status)) { > + if (Status =3D=3D EFI_ABORTED) { > + Status =3D EFI_DEVICE_ERROR; > + } > + *ByteCount =3D 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 =3D StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds); > + if (EFI_ERROR (Status)) { > + if (Status =3D=3D EFI_ABORTED) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + *ByteCount =3D 0; > + return Status; > + } > + > + // > + // Send out command packet > + // > + CommandIndex =3D (UINT16 *) PacketCommand; > + for (Count =3D 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, the= n > + 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 =3D EFI_SUCCESS; > + > + // > + // Non Data transfer request is also supported. > + // > + if (*ByteCount =3D=3D 0 || Buffer =3D=3D NULL) { > + *ByteCount =3D 0; > + if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, > TimeoutInMicroSeconds))) { > + return EFI_DEVICE_ERROR; > + } > + } > + > + ptrBuffer =3D Buffer; > + RequiredWordCount =3D *ByteCount / 2; > + > + // > + // ActuralWordCount means the word count of data really transfered. > + // > + ActualWordCount =3D 0; > + > + while (ActualWordCount < RequiredWordCount) { > + // > + // before each data transfer stream, the host should poll DRQ bit re= ady, > + // which indicates device's ready for data transfer . > + // > + Status =3D StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds); > + if (EFI_ERROR (Status)) { > + *ByteCount =3D ActualWordCount * 2; > + > + AtapiPassThruCheckErrorStatus (AtapiScsiPrivate); > + > + if (ActualWordCount =3D=3D 0) { > + return EFI_DEVICE_ERROR; > + } > + // > + // ActualWordCount > 0 > + // > + if (ActualWordCount < RequiredWordCount) { > + return EFI_BAD_BUFFER_SIZE; > + } > + } > + // > + // get current data transfer size from Cylinder Registers. > + // > + WordCount =3D ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate- > >IoPort->CylinderMsb) << 8; > + WordCount =3D WordCount | ReadPortB (AtapiScsiPrivate->PciIo, > AtapiScsiPrivate->IoPort->CylinderLsb); > + WordCount =3D WordCount & 0xffff; > + WordCount /=3D 2; > + > + // > + // perform a series data In/Out. > + // > + for (Index =3D 0; (Index < WordCount) && (ActualWordCount < > RequiredWordCount); Index++, ActualWordCount++) { > + > + if (Direction =3D=3D DataIn) { > + > + *ptrBuffer =3D ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPriv= ate- > >IoPort->Data); > + } else { > + > + WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->D= ata, > *ptrBuffer); > + } > + > + ptrBuffer++; > + > + } > + } > + // > + // After data transfer is completed, normally, DRQ bit should clear. > + // > + StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds); > + > + // > + // read status register to check whether error happens. > + // > + Status =3D AtapiPassThruCheckErrorStatus (AtapiScsiPrivate); > + > + *ByteCount =3D 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 =3D 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 =3D 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 i= s > + 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + > + StatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg.Status > + ); > + > + // > + // wait for BSY =3D=3D 0 and DRQ =3D=3D 0 > + // > + if ((StatusRegister & (DRQ | BSY)) =3D=3D 0) { > + break; > + } > + // > + // check whether the command is aborted by the device > + // > + if ((StatusRegister & (BSY | ERR)) =3D=3D ERR) { > + > + ErrRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg1.Error > + ); > + if ((ErrRegister & ABRT_ERR) =3D=3D ABRT_ERR) { > + > + return EFI_ABORTED; > + } > + } > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 rout= ine > should > + wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT w= hen > 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + > + AltStatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Alt.AltStatus > + ); > + > + // > + // wait for BSY =3D=3D 0 and DRQ =3D=3D 0 > + // > + if ((AltStatusRegister & (DRQ | BSY)) =3D=3D 0) { > + break; > + } > + > + if ((AltStatusRegister & (BSY | ERR)) =3D=3D ERR) { > + > + ErrRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg1.Error > + ); > + if ((ErrRegister & ABRT_ERR) =3D=3D ABRT_ERR) { > + > + return EFI_ABORTED; > + } > + } > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 i= s > + 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + // > + // read Status Register will clear interrupt > + // > + StatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg.Status > + ); > + > + // > + // BSY=3D=3D0,DRQ=3D=3D1 > + // > + if ((StatusRegister & (BSY | DRQ)) =3D=3D DRQ) { > + break; > + } > + > + if ((StatusRegister & (BSY | ERR)) =3D=3D ERR) { > + > + ErrRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg1.Error > + ); > + if ((ErrRegister & ABRT_ERR) =3D=3D ABRT_ERR) { > + return EFI_ABORTED; > + } > + } > + > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 i= s > + 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + // > + // read Status Register will clear interrupt > + // > + AltStatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Alt.AltStatus > + ); > + // > + // BSY=3D=3D0,DRQ=3D=3D1 > + // > + if ((AltStatusRegister & (BSY | DRQ)) =3D=3D DRQ) { > + break; > + } > + > + if ((AltStatusRegister & (BSY | ERR)) =3D=3D ERR) { > + > + ErrRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg1.Error > + ); > + if ((ErrRegister & ABRT_ERR) =3D=3D ABRT_ERR) { > + return EFI_ABORTED; > + } > + } > + > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 i= s > + 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + > + StatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg.Status > + ); > + if ((StatusRegister & BSY) =3D=3D 0x00) { > + break; > + } > + > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 i= s > + 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + > + AltStatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Alt.AltStatus > + ); > + if ((AltStatusRegister & BSY) =3D=3D 0x00) { > + break; > + } > + > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + StatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg.Status > + ); > + // > + // BSY =3D=3D 0 , DRDY =3D=3D 1 > + // > + if ((StatusRegister & (DRDY | BSY)) =3D=3D DRDY) { > + break; > + } > + > + if ((StatusRegister & (BSY | ERR)) =3D=3D ERR) { > + > + ErrRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg1.Error > + ); > + if ((ErrRegister & ABRT_ERR) =3D=3D ABRT_ERR) { > + return EFI_ABORTED; > + } > + } > + > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 =3D=3D 0) { > + Delay =3D 2; > + } else { > + Delay =3D DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1; > + } > + > + do { > + AltStatusRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Alt.AltStatus > + ); > + // > + // BSY =3D=3D 0 , DRDY =3D=3D 1 > + // > + if ((AltStatusRegister & (DRDY | BSY)) =3D=3D DRDY) { > + break; > + } > + > + if ((AltStatusRegister & (BSY | ERR)) =3D=3D ERR) { > + > + ErrRegister =3D ReadPortB ( > + AtapiScsiPrivate->PciIo, > + AtapiScsiPrivate->IoPort->Reg1.Error > + ); > + if ((ErrRegister & ABRT_ERR) =3D=3D ABRT_ERR) { > + return EFI_ABORTED; > + } > + } > + > + // > + // Stall for 30 us > + // > + gBS->Stall (30); > + // > + // Loop infinitely if not meeting expected condition > + // > + if (TimeoutInMicroSeconds =3D=3D 0) { > + Delay =3D 2; > + } > + > + Delay--; > + } while (Delay); > + > + if (Delay =3D=3D 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 =3D 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 =3D ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPri= vate- > >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 : Uncorrectabl= e > 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)) =3D=3D 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 =3D &AtapiScsiPrivate->ScsiPassThru; > + ExtScsiPassThru =3D &AtapiScsiPrivate->ExtScsiPassThru; > + > + if (FeaturePcdGet (PcdSupportScsiPassThru)) { > + ScsiPassThru =3D CopyMem (ScsiPassThru, &gScsiPassThruProtocolTempla= te, > sizeof (*ScsiPassThru)); > + if (FeaturePcdGet (PcdSupportExtScsiPassThru)) { > + ExtScsiPassThru =3D CopyMem (ExtScsiPassThru, > &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru)); > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + ControllerHandle, > + &gEfiScsiPassThruProtocolGuid, > + ScsiPassThru, > + &gEfiExtScsiPassThruProtocolGuid, > + ExtScsiPassThru, > + NULL > + ); > + } else { > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + ControllerHandle, > + &gEfiScsiPassThruProtocolGuid, > + ScsiPassThru, > + NULL > + ); > + } > + } else { > + if (FeaturePcdGet (PcdSupportExtScsiPassThru)) { > + ExtScsiPassThru =3D CopyMem (ExtScsiPassThru, > &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru)); > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + ControllerHandle, > + &gEfiExtScsiPassThruProtocolGuid, > + ExtScsiPassThru, > + NULL > + ); > + } else { > + // > + // This driver must support either ScsiPassThru or > + // ExtScsiPassThru protocols > + // > + ASSERT (FALSE); > + Status =3D EFI_UNSUPPORTED; > + } > + } > + > + return Status; > +} > + > +/** > + The user Entry Point for module AtapiPassThru. The user code starts wi= th > 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 =3D 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 =3D > PcdGet32 (PcdDriverSupportedEfiVersion); > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &ImageHandle, > + &gEfiDriverSupportedEfiVersionProtocolGuid, > + &gAtapiScsiPassThruDriverSupportedEfiVersion, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > diff --git a/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h > b/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h > new file mode 100644 > index 0000000000..9fca7b6ac2 > --- /dev/null > +++ b/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.h > @@ -0,0 +1,1618 @@ > +/** @file > + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + Module Name: AtapiPassThru.h > + > +**/ > + > +#ifndef _APT_H > +#define _APT_H > + > + > + > +#include > + > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#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 =3D 0, > + IdeSecondary =3D 1, > + IdeMaxChannel =3D 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 =3D 0, > + DataOut =3D 1, > + DataBi =3D 2, > + NoData =3D 3, > + End =3D 0xff > +} DATA_DIRECTION; > + > +typedef struct { > + UINT8 OpCode; > + DATA_DIRECTION Direction; > +} SCSI_COMMAND_SET; > + > +#define MAX_CHANNEL 2 > + > +#define ValidCdbLength(Len) ((Len) =3D=3D 6 || (Len) =3D=3D 10 || (Len) = =3D=3D 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 drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 fa= iled. > + > +--*/ > +; > + > +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 signal= ed > + 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 de= vice > + present on a SCSI channel. An input value of > + 0xFFFFFFFF retrieves the Target ID of the firs= t > + SCSI device present on a SCSI channel. > + Lun - On input, a pointer to the LUN of a SCSI devic= e > + present on the SCSI channel. On output, a poin= ter > + 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 Control= ler. > + > +Arguments: > + > + This - Protocol instance pointer. > + Target - The Target ID of the SCSI device for which > + a device path node is to be allocated and buil= t. > + 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 cal= ler > + is finished with DevicePath. > + Returns: > + EFI_SUCCESS - The device path node that describes the SCSI d= evice > + specified by Target and Lun was allocated and > + returned in DevicePath. > + EFI_NOT_FOUND - The SCSI devices specified by Target and Lun d= oes > + 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 signal= ed > + 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 de= vice > + present on a SCSI channel. An input value of > + 0xFFFFFFFF retrieves the Target ID of the firs= t > + SCSI device present on a SCSI channel. > + Lun - On input, a pointer to the LUN of a SCSI devic= e > + present on the SCSI channel. On output, a poin= ter > + 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 Control= ler. > + > +Arguments: > + > + This - Protocol instance pointer. > + Target - The Target ID of the SCSI device for which > + a device path node is to be allocated and buil= t. > + 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 cal= ler > + is finished with DevicePath. > + Returns: > + EFI_SUCCESS - The device path node that describes the SCSI d= evice > + specified by Target and Lun was allocated and > + returned in DevicePath. > + EFI_NOT_FOUND - The SCSI devices specified by Target and Lun d= oes > + 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 de= vice > + present on a SCSI channel. An input value of > + 0xFFFFFFFF retrieves the Target ID of the fir= st > + SCSI device present on a SCSI channel. > + Lun - On input, a pointer to the LUN of a SCSI devic= e > + present on the SCSI channel. On output, a poin= ter > + 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_PACKE= T > + > +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 ID= E > + Channel, Target ID 0 indicates Master device;Targe= t > + ID 1 indicates Slave device. > + Packet: The SCSI Request Packet to send to the ATAPI devic= e > + 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_PACKE= T > + > +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_PACKE= T > + > +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 ID= E > + Channel, Target ID 0 indicates Master device;Targe= t > + ID 1 indicates Slave device. > + Packet: The SCSI Request Packet to send to the ATAPI devic= e > + 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: > + > + Submit request sense command > + > +Arguments: > + > + AtapiScsiPrivate - The pointer 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 ID= E > + Channel, Target ID 0 indicates Master device;Targe= t > + 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, the= n > + 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 i= s > + 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 rout= ine > should > + wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT w= hen > 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 i= s > + 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 i= s > + 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 i= s > + 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 i= s > + 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, the= n > + 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 ControlBloc= k. > + > +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/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf > b/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf > new file mode 100644 > index 0000000000..750136275a > --- /dev/null > +++ b/Drivers/OptionRomPkg/AtapiPassThruDxe/AtapiPassThruDxe.inf > @@ -0,0 +1,70 @@ > +## @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 - 2018, Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D AtapiPassThruDxe > + FILE_GUID =3D E49061CE-99A7-41d3-AB3A-36E5CFBAD63= E > + MODULE_TYPE =3D UEFI_DRIVER > + VERSION_STRING =3D 1.0 > + > + ENTRY_POINT =3D InitializeAtapiPassThru > + > + PCI_VENDOR_ID =3D 0x8086 > + PCI_DEVICE_ID =3D 0x2921 > + PCI_CLASS_CODE =3D 0x010100 > + PCI_REVISION =3D 0x0003 > + > +# > +# The following information is for reference only and not required by th= e > build tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 EBC > +# > +# DRIVER_BINDING =3D gAtapiScsiPassThruDriverBinding > +# COMPONENT_NAME =3D 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/Drivers/OptionRomPkg/AtapiPassThruDxe/ComponentName.c > b/Drivers/OptionRomPkg/AtapiPassThruDxe/ComponentName.c > new file mode 100644 > index 0000000000..007cb5f195 > --- /dev/null > +++ b/Drivers/OptionRomPkg/AtapiPassThruDxe/ComponentName.c > @@ -0,0 +1,169 @@ > +/** @file > + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + Module Name: ComponentName.c > + > +**/ > +#include "AtapiPassThru.h" > + > +// > +// EFI Component Name Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME_PROTOCOL gAtapiScsiPassThruComponentName =3D > { > + AtapiScsiPassThruComponentNameGetDriverName, > + AtapiScsiPassThruComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME2_PROTOCOL gAtapiScsiPassThruComponentName2 > =3D { > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) > AtapiScsiPassThruComponentNameGetDriverName, > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) > AtapiScsiPassThruComponentNameGetControllerName, > + "en" > +}; > + > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mAtapiScsiPassThruDriverNameTable[] =3D { > + { "eng;en", (CHAR16 *) L"ATAPI SCSI Pass Thru Driver" }, > + { NULL , NULL } > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 =3D=3D &gAtapiScsiPassThruComponentName) > + ); > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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/Drivers/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c > b/Drivers/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c > new file mode 100644 > index 0000000000..84a9badad2 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/AtapiPassThruDxe/DriverSupportedEfiVersion.c > @@ -0,0 +1,14 @@ > +/** @file > + Copyright (c) 2007, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + Module Name: DriverSupportEfiVersion.c > + > +**/ > +#include "AtapiPassThru.h" > + > +EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL > gAtapiScsiPassThruDriverSupportedEfiVersion =3D { > + sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of > Protocol structure. > + 0 // Version number = to be filled at start up. > +}; > + > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/CompatibleDevices.txt > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/CompatibleDevices.txt > new file mode 100644 > index 0000000000..1ec1cce0d1 > --- /dev/null > +++ > b/Drivers/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/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c > new file mode 100644 > index 0000000000..d15abf5090 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ComponentName.c > @@ -0,0 +1,218 @@ > +/** @file > + UEFI Component Name(2) protocol implementation for USB Serial driver. > + > +Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "FtdiUsbSerialDriver.h" > + > +// > +// EFI Component Name Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME_PROTOCOL gUsbSerialComponentName =3D { > + (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 =3D { > + UsbSerialComponentNameGetDriverName, > + UsbSerialComponentNameGetControllerName, > + "en" > +}; > + > +// > +// Driver name string table > +// > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mUsbSerialDriverNameTable[] =3D { > + { "eng;en", L"FTDI-232 USB Serial Driver" }, > + { NULL , NULL } > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + @param DriverName A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 =3D=3D &gUsbSerialComponentName2) > + ); > +} > + > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + @param ChildHandle The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + @param Language A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + @param ControllerName A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 !=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Check Controller's handle > + // > + Status =3D 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 !=3D EFI_ALREADY_STARTED) { > + return EFI_UNSUPPORTED; > + } > + // > + // Get the device context > + // > + Status =3D gBS->OpenProtocol ( > + ControllerHandle, > + &gEfiSerialIoProtocolGuid, > + (VOID **) &SerialIo, > + gUsbSerialDriverBinding.DriverBindingHandle, > + ControllerHandle, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + UsbSerDev =3D USB_SER_DEV_FROM_THIS (SerialIo); > + > + return LookupUnicodeString2 ( > + Language, > + This->SupportedLanguages, > + UsbSerDev->ControllerNameTable, > + ControllerName, > + (BOOLEAN)(This =3D=3D &gUsbSerialComponentName2) > + ); > +} > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c > new file mode 100644 > index 0000000000..ac09fae014 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.c > @@ -0,0 +1,2580 @@ > +/** @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 > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +// > + > +// 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[] =3D { > + {VID_FTDI, DID_FTDI_FT232}, > + {0,0} > +}; > + > +// > +// USB Serial Driver Global Variables > +// > +EFI_DRIVER_BINDING_PROTOCOL gUsbSerialDriverBinding =3D { > + UsbSerialDriverBindingSupported, > + UsbSerialDriverBindingStart, > + UsbSerialDriverBindingStop, > + 0xa, > + NULL, > + NULL > +}; > + > +// > +// Table with the nearest power of 2 for the numbers 0-15 > +// > +UINT8 gRoundedPowersOf2[16] =3D { 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) =3D=3D MESSAGING_DEVICE_PATH) &= & > + (DevicePathSubType (FlowControl) =3D=3D 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 =3D 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 tr= ansfer > + @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 =3D=3D EfiUsbNoData) || (*TransLen =3D=3D 0)) { > + return EFI_SUCCESS; > + } > + > + // > + // Select the endpoint then issue the transfer > + // > + if (DataDir =3D=3D EfiUsbDataIn) { > + Endpoint =3D &UsbBot->InEndpointDescriptor; > + } else { > + Endpoint =3D &UsbBot->OutEndpointDescriptor; > + } > + > + Result =3D 0; > + Status =3D 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 =3D EFI_NOT_READY; > + } else { > + UsbBot->Shutdown =3D 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 th= e > status > + for > + @param StatusBuffer[in] Buffer holding the status values > + > + @retval EFI_SUCCESS The status values were read and set corre= ctly > + > +**/ > +EFI_STATUS > +EFIAPI > +SetStatusInternal ( > + IN USB_SER_DEV *UsbSerialDevice, > + IN UINT8 *StatusBuffer > + ) > +{ > + UINT8 Msr; > + > + Msr =3D (StatusBuffer[0] & MSR_MASK); > + > + // > + // set the Status values to disabled > + // > + UsbSerialDevice->StatusValues.CtsState =3D FALSE; > + UsbSerialDevice->StatusValues.DsrState =3D FALSE; > + UsbSerialDevice->StatusValues.RiState =3D FALSE; > + UsbSerialDevice->StatusValues.SdState =3D FALSE; > + > + // > + // Check the values from the status buffer and set the appropriate sta= tus > + // values to enabled > + // > + if ((Msr & CTS_MASK) =3D=3D CTS_MASK) { > + UsbSerialDevice->StatusValues.CtsState =3D TRUE; > + } > + if ((Msr & DSR_MASK) =3D=3D DSR_MASK) { > + UsbSerialDevice->StatusValues.DsrState =3D TRUE; > + } > + if ((Msr & RI_MASK) =3D=3D RI_MASK) { > + UsbSerialDevice->StatusValues.RiState =3D TRUE; > + } > + if ((Msr & SD_MASK) =3D=3D SD_MASK) { > + UsbSerialDevice->StatusValues.SdState =3D 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. O= n output, > + the amount of data returned in Buff= er. > + 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 =3D 512; > + ReadBuffer =3D &(UsbSerialDevice->ReadBuffer[0]); > + > + if (UsbSerialDevice->Shutdown) { > + return EFI_DEVICE_ERROR; > + } > + > + Tpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + > + Status =3D UsbSerialDataTransfer ( > + UsbSerialDevice, > + EfiUsbDataIn, > + ReadBuffer, > + &ReadBufferSize, > + FTDI_TIMEOUT*2 //Padded because timers won't be exactly al= igned > + ); > + if (EFI_ERROR (Status)) { > + gBS->RestoreTPL (Tpl); > + if (Status =3D=3D EFI_TIMEOUT) { > + return EFI_TIMEOUT; > + } else { > + return EFI_DEVICE_ERROR; > + } > + } > + > + // > + // Store the status bytes in the status buffer > + // > + for (Index =3D 0; Index < 2; Index++) {//only the first 2 bytes are st= atus bytes > + StatusBuffer[Index] =3D ReadBuffer[Index]; > + } > + // > + // update the statusvalue field of the usbserialdevice > + // > + Status =3D SetStatusInternal (UsbSerialDevice, StatusBuffer); > + if (Status !=3D EFI_SUCCESS) { > + } > + > + // > + // Store the read data in the read buffer, start at 2 to ignore status= bytes > + // > + for (Index =3D 2; Index < ReadBufferSize; Index++) { > + if (((UsbSerialDevice->DataBufferTail + 1) % SW_FIFO_DEPTH) =3D=3D > UsbSerialDevice->DataBufferHead) { > + break; > + } > + if (ReadBuffer[Index] =3D=3D 0x00) { > + // > + // This is null, do not add > + // > + } else { > + UsbSerialDevice->DataBuffer[UsbSerialDevice->DataBufferTail] =3D > ReadBuffer[Index]; > + UsbSerialDevice->DataBufferTail =3D (UsbSerialDevice->DataBufferTa= il + 1) % > SW_FIFO_DEPTH; > + } > + } > + > + // > + // Read characters out of the buffer to satisfy caller's request. > + // > + for (Index =3D 0; Index < *BufferSize; Index++) { > + if (UsbSerialDevice->DataBufferHead =3D=3D UsbSerialDevice->DataBuff= erTail) > { > + break; > + } > + // > + // Still have characters in the buffer to return > + // > + ((UINT8 *)Buffer)[Index] =3D UsbSerialDevice- > >DataBuffer[UsbSerialDevice->DataBufferHead]; > + UsbSerialDevice->DataBufferHead =3D (UsbSerialDevice->DataBufferHead= + > 1) % SW_FIFO_DEPTH; > + } > + // > + // Return actual number of bytes returned. > + // > + *BufferSize =3D 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 need= s > its > + initial status values set > + > + @retval EFI_SUCCESS The status bytes were read successfully a= nd 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 =3D EFI_UNSUPPORTED; > + BufferSize =3D sizeof (StatusBuffer); > + > + if (UsbSerialDevice->Shutdown) { > + return EFI_DEVICE_ERROR; > + } > + > + Tpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + > + Status =3D UsbSerialDataTransfer ( > + UsbSerialDevice, > + EfiUsbDataIn, > + StatusBuffer, > + &BufferSize, > + 40 //Slightly more than 2x the FTDI polling frequency to= make sure > that data will be returned > + ); > + > + Status =3D 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 =3D (USB_SER_DEV*)Context; > + > + if (UsbSerialDevice->DataBufferHead =3D=3D UsbSerialDevice->DataBuffer= Tail) { > + // > + // Data buffer is empty, try to read from device > + // > + BufferSize =3D 0; > + ReadDataFromUsb (UsbSerialDevice, &BufferSize, NULL); > + if (UsbSerialDevice->DataBufferHead =3D=3D UsbSerialDevice->DataBuff= erTail) > { > + // > + // Data buffer still has no data, set the > EFI_SERIAL_INPUT_BUFFER_EMPTY > + // flag > + // > + UsbSerialDevice->ControlBits |=3D EFI_SERIAL_INPUT_BUFFER_EMPTY; > + } else { > + // > + // Read has returned some data, clear the > EFI_SERIAL_INPUT_BUFFER_EMPTY > + // flag > + // > + UsbSerialDevice->ControlBits &=3D ~(EFI_SERIAL_INPUT_BUFFER_EMPTY)= ; > + } > + } else { > + // > + // Data buffer has data, no read attempt required > + // > + UsbSerialDevice->ControlBits &=3D ~(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 devi= ce > + @param EncodedBaudRate[out] The baud rate encoded in the forma= t > + 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 >=3D FTDI_SPECIAL_CASE_300_MIN) && (BaudRate <=3D > FTDI_SPECIAL_CASE_300_MAX)) { > + *EncodedBaudRate =3D 0; > + return EFI_SUCCESS; > + } > + if ((BaudRate >=3D FTDI_SPECIAL_CASE_200_MIN) && (BaudRate <=3D > FTDI_SPECIAL_CASE_200_MAX)) { > + *EncodedBaudRate =3D 1; > + return EFI_SUCCESS; > + } > + > + // > + // Compute divisor > + // > + Divisor =3D (FTDI_UART_FREQUENCY << 4) / (UINT32)BaudRate; > + > + // > + // Round the last 4 bits to the nearest power of 2 > + // > + Divisor =3D (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 =3D FTDI_MIN_DIVISOR; > + } else if (Divisor > FTDI_MAX_DIVISOR) { > + Divisor =3D 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 =3D 46601941 > + // (3MHz * 1600) / 97 =3D 49484536 > + // > + AdjustedFrequency =3D (((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 =3D (UINT16)(Divisor >> 4); > + if ((Divisor & 0x8) !=3D 0) { > + Result |=3D 0x4000; > + } else if ((Divisor & 0x4) !=3D 0) { > + Result |=3D 0x8000; > + } else if ((Divisor & 0x2) !=3D 0) { > + Result |=3D 0xC000; > + } > + > + *EncodedBaudRate =3D 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 =3D UsbIo->UsbGetDeviceDescriptor ( > + UsbIo, > + &DeviceDescriptor > + ); > + if (EFI_ERROR (Status)) { > + return FALSE; > + } > + > + Found =3D FALSE; > + Index =3D 0; > + while (gUSBDeviceList[Index].VendorId !=3D 0 && > + gUSBDeviceList[Index].DeviceId !=3D 0 && > + !Found ) { > + if (DeviceDescriptor.IdProduct =3D=3D gUSBDeviceList[Index].DeviceId= && > + DeviceDescriptor.IdVendor =3D=3D gUSBDeviceList[Index].VendorId= ){ > + // > + // Checks to see if a string descriptor can be pulled from the d= evice in > + // the selected language. If not False is returned indicating th= at this > + // is not a Usb Serial Device that can be managegd by this drive= r > + // > + StrMfg =3D NULL; > + Status =3D UsbIo->UsbGetStringDescriptor ( > + UsbIo, > + USB_US_LANG_ID, // LANGID selector, should mak= e this > + // more robust to verify lang = support > + // for device > + DeviceDescriptor.StrManufacturer, > + &StrMfg > + ); > + if (StrMfg !=3D 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 th= e 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 o= n 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 corre= ctly > and > + the data values were unable to be s= et > + > +**/ > +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 se= tting of > + // 1.5 check to see if this happens when the values of last settings a= re used > + // > + if ((DataBits =3D=3D 0) && (StopBits =3D=3D OneFiveStopBits)) { > + if ((LastSettings->DataBits =3D=3D 6) || (LastSettings->DataBits =3D= =3D 7) || > (LastSettings->DataBits =3D=3D 8)) { > + return EFI_INVALID_PARAMETER; > + } > + } else if ((StopBits =3D=3D DefaultStopBits) && ((DataBits =3D=3D 6) |= | (DataBits =3D=3D 7) > || (DataBits =3D=3D 8))) { > + if (LastSettings->StopBits =3D=3D OneFiveStopBits) { > + return EFI_INVALID_PARAMETER; > + } > + } else if ((DataBits =3D=3D 0) && (StopBits =3D=3D DefaultStopBits)) { > + if (LastSettings->StopBits =3D=3D OneFiveStopBits) { > + if ((LastSettings->DataBits =3D=3D 6) || (LastSettings->DataBits = =3D=3D 7) || > (LastSettings->DataBits =3D=3D 8)) { > + return EFI_INVALID_PARAMETER; > + } > + } > + } > + > + // > + // set the DevReq.Value for the usb control transfer to the correct va= lue > + // based on the seleceted number of data bits if there is an invalid n= umber > of > + // data bits requested return EFI_INVALID_PARAMETER > + // > + if (((DataBits < 5 ) || (DataBits > 8)) && (DataBits !=3D 0)) { > + return EFI_INVALID_PARAMETER; > + } > + if (DataBits =3D=3D 0) { > + // > + // use the value of LastDataBits > + // > + DevReq.Value =3D SET_DATA_BITS (LastSettings->DataBits); > + } else { > + // > + // use the value of DataBits > + // > + DevReq.Value =3D SET_DATA_BITS (DataBits); > + } > + > + // > + // Set Parity > + // > + if (Parity =3D=3D DefaultParity) { > + Parity =3D LastSettings->Parity; > + } > + > + if (Parity =3D=3D NoParity) { > + DevReq.Value |=3D SET_PARITY_NONE; > + } else if (Parity =3D=3D EvenParity) { > + DevReq.Value |=3D SET_PARITY_EVEN; > + } else if (Parity =3D=3D OddParity){ > + DevReq.Value |=3D SET_PARITY_ODD; > + } else if (Parity =3D=3D MarkParity) { > + DevReq.Value |=3D SET_PARITY_MARK; > + } else if (Parity =3D=3D SpaceParity) { > + DevReq.Value |=3D SET_PARITY_SPACE; > + } > + > + // > + // Set Stop Bits > + // > + if (StopBits =3D=3D DefaultStopBits) { > + StopBits =3D LastSettings->StopBits; > + } > + > + if (StopBits =3D=3D OneStopBit) { > + DevReq.Value |=3D SET_STOP_BITS_1; > + } else if (StopBits =3D=3D OneFiveStopBits) { > + DevReq.Value |=3D SET_STOP_BITS_15; > + } else if (StopBits =3D=3D TwoStopBits) { > + DevReq.Value |=3D 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 =3D FTDI_COMMAND_SET_DATA; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; // indicates that there is no data phase in = this > request > + > + Status =3D UsbIo->UsbControlTransfer ( > + UsbIo, > + &DevReq, > + EfiUsbDataOut, > + WDR_SHORT_TIMEOUT, > + &ConfigurationValue, > + 1, > + &ReturnValue > + ); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + return Status; > + > +StatusError: > + if ((Status !=3D EFI_INVALID_PARAMETER) || (Status !=3D EFI_DEVICE_ERR= OR)) > { > + 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 Las= tBaudRate > + will be used instead > + @param LastBaudRate[in] The baud rate value that was previo= usly > 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 corre= ctly > 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 =3D 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 =3D=3D 0) { > + Status =3D EncodeBaudRateForFtdi (LastBaudRate, &EncodedBaudRate); > + if (EFI_ERROR (Status)) { > + gBS->RestoreTPL (Tpl); > + // > + // EncodeBaudRateForFtdi returns EFI_INVALID_PARAMETER when not > + // succesfull > + // > + return Status; > + } > + DevReq.Value =3D EncodedBaudRate; > + } else { > + Status =3D EncodeBaudRateForFtdi (BaudRate, &EncodedBaudRate); > + if (EFI_ERROR (Status)) { > + gBS->RestoreTPL (Tpl); > + // > + // EncodeBaudRateForFtdi returns EFI_INVALID_PARAMETER when not > + // successfull > + // > + return Status; > + } > + DevReq.Value =3D EncodedBaudRate; > + } > + > + // > + // set the remaining parameters of DevReq and perform the usb control > transfer > + // to set the device > + // > + DevReq.Request =3D FTDI_COMMAND_SET_BAUDRATE; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; // indicates that there is no data phase in = this > request > + > + Status =3D 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 !=3D EFI_INVALID_PARAMETER) || (Status !=3D EFI_DEVICE_ERR= OR)) > { > + return EFI_DEVICE_ERROR; > + } else { > + return Status; > + } > +} > + > +/** > + Sets the baud rate, receive FIFO depth, transmit/receice time out, par= ity, > + data bits, and stop bits on a serial device. > + > + @param UsbSerialDevice[in] Pointer to the current instance of the US= B > Serial > + Device. > + @param BaudRate[in] The requested baud rate. A BaudRate value= of > 0 > + will use the device's default interface s= peed. > + @param ReveiveFifoDepth[in] The requested depth of the FIFO on the > receive > + side of the serial interface. A ReceiveFi= foDepth > + value of 0 will use the device's default = FIFO > + depth. > + @param Timeout[in] The requested time out for a single chara= cter in > + microseconds.This timeout applies to both= the > + transmit and receive side of the interfac= e.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 ser= ial > + device. A DataBits value of 0 will use th= e > + device's default data bit setting. > + @param StopBits[in] The number of stop bits to use on this se= rial > + device. A StopBits value of DefaultStopBi= ts will > + use the device's default number of stop b= its. > + > + @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 =3D EFI_UNSUPPORTED; > + Tpl =3D gBS->RaiseTPL(TPL_NOTIFY); > + Uart =3D NULL; > + > + // > + // check for invalid combinations of parameters > + // > + if (((DataBits >=3D 6) && (DataBits <=3D 8)) && (StopBits =3D=3D OneFi= veStopBits)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // set data bits, parity and stop bits > + // > + Status =3D SetDataInternal ( > + UsbSerialDevice->UsbIo, > + DataBits, > + Parity, > + StopBits, > + &(UsbSerialDevice->LastSettings) > + ); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + // > + // set baudrate > + // > + Status =3D 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 =3D=3D 0) { > + UsbSerialDevice->LastSettings.BaudRate =3D UsbSerialDevice- > >LastSettings.BaudRate; > + UsbSerialDevice->SerialIo.Mode->BaudRate =3D UsbSerialDevice- > >LastSettings.BaudRate; > + } else { > + UsbSerialDevice->LastSettings.BaudRate =3D BaudRate; > + UsbSerialDevice->SerialIo.Mode->BaudRate =3D BaudRate; > + } > + > + UsbSerialDevice->LastSettings.Timeout =3D FTDI_TIMEOUT; > + UsbSerialDevice->LastSettings.ReceiveFifoDepth =3D > FTDI_MAX_RECEIVE_FIFO_DEPTH; > + > + if (Parity =3D=3D DefaultParity) { > + UsbSerialDevice->LastSettings.Parity =3D UsbSerialDevice- > >LastSettings.Parity; > + UsbSerialDevice->SerialIo.Mode->Parity =3D UsbSerialDevice- > >LastSettings.Parity; > + } else { > + UsbSerialDevice->LastSettings.Parity =3D Parity; > + UsbSerialDevice->SerialIo.Mode->Parity =3D Parity; > + } > + if (DataBits =3D=3D 0) { > + UsbSerialDevice->LastSettings.DataBits =3D UsbSerialDevice- > >LastSettings.DataBits; > + UsbSerialDevice->SerialIo.Mode->DataBits =3D UsbSerialDevice- > >LastSettings.DataBits; > + } else { > + UsbSerialDevice->LastSettings.DataBits =3D DataBits; > + UsbSerialDevice->SerialIo.Mode->DataBits =3D DataBits; > + } > + if (StopBits =3D=3D DefaultStopBits) { > + UsbSerialDevice->LastSettings.StopBits =3D UsbSerialDevice- > >LastSettings.StopBits; > + UsbSerialDevice->SerialIo.Mode->StopBits =3D UsbSerialDevice- > >LastSettings.StopBits; > + } else { > + UsbSerialDevice->LastSettings.StopBits =3D StopBits; > + UsbSerialDevice->SerialIo.Mode->StopBits =3D StopBits; > + } > + > + // > + // See if the device path node has changed > + // > + if (UsbSerialDevice->UartDevicePath.BaudRate =3D=3D BaudRate && > + UsbSerialDevice->UartDevicePath.DataBits =3D=3D DataBits && > + UsbSerialDevice->UartDevicePath.StopBits =3D=3D StopBits && > + UsbSerialDevice->UartDevicePath.Parity =3D=3D Parity > + ) { > + gBS->RestoreTPL (Tpl); > + return EFI_SUCCESS; > + } > + > + // > + // Update the device path > + // > + UsbSerialDevice->UartDevicePath.BaudRate =3D BaudRate; > + UsbSerialDevice->UartDevicePath.DataBits =3D DataBits; > + UsbSerialDevice->UartDevicePath.StopBits =3D (UINT8) StopBits; > + UsbSerialDevice->UartDevicePath.Parity =3D (UINT8) Parity; > + > + Status =3D EFI_SUCCESS; > + if (UsbSerialDevice->ControllerHandle !=3D NULL) { > + RemainingDevicePath =3D UsbSerialDevice->DevicePath; > + while (!IsDevicePathEnd (RemainingDevicePath)) { > + Uart =3D (UART_DEVICE_PATH *) NextDevicePathNode > (RemainingDevicePath); > + if (Uart->Header.Type =3D=3D MESSAGING_DEVICE_PATH && > + Uart->Header.SubType =3D=3D MSG_UART_DP && > + sizeof (UART_DEVICE_PATH) =3D=3D DevicePathNodeLength > ((EFI_DEVICE_PATH *) Uart)) { > + Uart->BaudRate =3D BaudRate; > + Uart->DataBits =3D DataBits; > + Uart->StopBits =3D (UINT8)StopBits; > + Uart->Parity =3D (UINT8) Parity; > + break; > + } > + RemainingDevicePath =3D NextDevicePathNode (RemainingDevicePath)= ; > + } > + } > + > + gBS->RestoreTPL (Tpl); > + return Status; > + > +StatusError: > + gBS->RestoreTPL (Tpl); > + if ((Status !=3D EFI_INVALID_PARAMETER) || (Status !=3D EFI_DEVICE_ERR= OR)) > { > + 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 o= f > 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 corre= ctly > + > +**/ > +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 =3D NO_FLOW_CTRL; > + } > + if (FlowControlEnable) { > + DevReq.Value =3D XON_XOFF_CTRL; > + } > + // > + // set the remaining DevReq parameters and perform the usb control > transfer to > + // set the flow control on the device > + // > + DevReq.Request =3D FTDI_COMMAND_SET_FLOW_CTRL; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; // indicates that this transfer has no data= phase > + Status =3D UsbIo->UsbControlTransfer ( > + UsbIo, > + &DevReq, > + EfiUsbDataOut, > + WDR_TIMEOUT, > + &ConfigurationValue, > + 1, > + &ReturnValue > + ); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + > + return Status; > + > +StatusError: > + if ((Status !=3D EFI_INVALID_PARAMETER) || > + (Status !=3D EFI_DEVICE_ERROR) || > + (Status !=3D 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 o= f the > + Dtr for the Usb Serial Device > + > + @retval EFI_SUCCESS The Dtr value was set on the Usb Se= rial > + 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 corre= ctly > + > +**/ > +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 =3D SET_DTR_LOW; > + } > + if (DtrEnable) { > + DevReq.Value =3D SET_DTR_HIGH; > + } > + // > + // set the remaining attributes of DevReq and perform the usb control > transfer > + // to set the device > + // > + DevReq.Request =3D FTDI_COMMAND_MODEM_CTRL; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; // indicates that there is no data phase in= this > transfer > + > + Status =3D UsbIo->UsbControlTransfer ( > + UsbIo, > + &DevReq, > + EfiUsbDataOut, > + WDR_TIMEOUT, > + &ConfigurationValue, > + 1, > + &ReturnValue > + ); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + return Status; > + > +StatusError: > + if ((Status !=3D EFI_INVALID_PARAMETER) || > + (Status !=3D EFI_DEVICE_ERROR) || > + (Status !=3D 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 o= f the > + Rts for the Usb Serial Device > + > + @retval EFI_SUCCESS The Rts value was set on the Usb Se= rial > + 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 corre= ctly > + > +**/ > +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 =3D SET_RTS_LOW; > + } > + if (RtsEnable) { > + DevReq.Value =3D SET_RTS_HIGH; > + } > + > + // > + // set the remaining parameters of DevReq and perform the usb control > transfer > + // to set the values on the device > + // > + DevReq.Request =3D FTDI_COMMAND_MODEM_CTRL; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; // indicates that there is no data phase in = this > request > + > + Status =3D UsbIo->UsbControlTransfer ( > + UsbIo, > + &DevReq, > + EfiUsbDataOut, > + WDR_TIMEOUT, > + &ConfigurationValue, > + 1, > + &ReturnValue > + ); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + > + return Status; > + > +StatusError: > + if ((Status !=3D EFI_INVALID_PARAMETER) || > + (Status !=3D EFI_DEVICE_ERROR) || > + (Status !=3D EFI_UNSUPPORTED) ) { > + return EFI_DEVICE_ERROR; > + } else { > + return Status; > + } > +} > + > +/** > + Internal function that checks for valid control values and sets the co= ntrol > + bits on the Usb Serial Device. > + > + @param UsbSerialDevice[in] Handle to the Usb Serial Device who= se > + control bits are being set > + @param Control[in] The control value passed to the fun= ction > + that contains the values of the con= trol > + bits that are being set > + > + @retval EFI_SUCCESS The control bits were set on the Us= b 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 corre= ctly > + > +**/ > +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 =3D FALSE; > + Control->SoftwareLoopBack =3D FALSE; > + > + // > + // set hardware flow control > + // > + Status =3D SetFlowControlInternal ( > + UsbSerialDevice->UsbIo, > + Control->HardwareFlowControl > + ); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + > + // > + // set Dtr state > + // > + Status =3D SetDtrInternal (UsbSerialDevice->UsbIo, Control->DtrState); > + if (EFI_ERROR (Status)) { > + goto StatusError; > + } > + > + // > + // set Rts state > + // > + Status =3D SetRtsInternal (UsbSerialDevice->UsbIo, Control->RtsState); > + if (EFI_ERROR (Status)){ > + goto StatusError; > + } > + > + // > + // update the remaining control values for UsbSerialDevice->ControlVal= ues > + // > + UsbSerialDevice->ControlValues.DtrState =3D Control->DtrSta= te; > + UsbSerialDevice->ControlValues.RtsState =3D Control->RtsSta= te; > + UsbSerialDevice->ControlValues.HardwareFlowControl =3D Control- > >HardwareFlowControl; > + UsbSerialDevice->ControlValues.HardwareLoopBack =3D FALSE; > + UsbSerialDevice->ControlValues.SoftwareLoopBack =3D FALSE; > + > + Status =3D EFI_SUCCESS; > + // > + // Update the device path to have the correct flow control values > + // > + if (UsbSerialDevice->ControllerHandle !=3D NULL) { > + RemainingDevicePath =3D UsbSerialDevice->DevicePath; > + while (!IsDevicePathEnd (RemainingDevicePath)) { > + FlowControl =3D (UART_FLOW_CONTROL_DEVICE_PATH *) > NextDevicePathNode (RemainingDevicePath); > + if (FlowControl->Header.Type =3D=3D MESSAGING_DEVICE_PATH && > + FlowControl->Header.SubType =3D=3D MSG_VENDOR_DP && > + sizeof (UART_FLOW_CONTROL_DEVICE_PATH) =3D=3D > DevicePathNodeLength ((EFI_DEVICE_PATH *) FlowControl)){ > + if (UsbSerialDevice->ControlValues.HardwareFlowControl =3D=3D TR= UE) { > + FlowControl->FlowControlMap =3D UART_FLOW_CONTROL_HARDWARE; > + } else if (UsbSerialDevice->ControlValues.HardwareFlowControl = =3D=3D > FALSE) { > + FlowControl->FlowControlMap =3D 0; > + } > + break; > + } > + RemainingDevicePath =3D NextDevicePathNode (RemainingDevicePath); > + } > + } > + > + return Status; > + > +StatusError: > + if ((Status !=3D EFI_INVALID_PARAMETER) || > + (Status !=3D EFI_DEVICE_ERROR) || > + (Status !=3D EFI_UNSUPPORTED) ) { > + return EFI_DEVICE_ERROR; > + } else { > + return Status; > + } > +} > + > +/** > + Internal function that calculates the Control value used by GetControl= Bits() > + based on the status and control values of the Usb Serial Device. > + > + @param UsbSerialDevice[in] Handle to the Usb Serial Devie whos= e > status > + and control values are being used t= o set > + Control > + @param Control[out] On output the formated value of Con= trol > + that has been calculated based on t= he > + control and status values of the Us= b Serial > + Device > + > + @retval EFI_SUCCESS The value of Control was successful= ly > + calculated > + > +**/ > +EFI_STATUS > +EFIAPI > +GetControlBitsInternal ( > + IN USB_SER_DEV *UsbSerialDevice, > + OUT UINT32 *Control > + ) > +{ > + *Control =3D 0; > + > + // > + // Check the values of UsbSerialDevice->Status Values and modify contr= ol > + // accordingly these values correspond to the modem status register > + // > + if (UsbSerialDevice->StatusValues.CtsState) { > + *Control |=3D EFI_SERIAL_CLEAR_TO_SEND; > + } > + if (UsbSerialDevice->StatusValues.DsrState) { > + *Control |=3D EFI_SERIAL_DATA_SET_READY; > + } > + if (UsbSerialDevice->StatusValues.RiState) { > + *Control |=3D EFI_SERIAL_RING_INDICATE; > + } > + if (UsbSerialDevice->StatusValues.SdState) { > + *Control |=3D EFI_SERIAL_CARRIER_DETECT; > + } > + > + // > + // check the values of UsbSerialDevice->ControlValues and modify contr= ol > + // accordingly these values correspond to the values of the Modem > Control > + // Register > + // > + if (UsbSerialDevice->ControlValues.DtrState) { > + *Control |=3D EFI_SERIAL_DATA_TERMINAL_READY; > + } > + if (UsbSerialDevice->ControlValues.RtsState) { > + *Control |=3D EFI_SERIAL_REQUEST_TO_SEND; > + } > + if (UsbSerialDevice->ControlValues.HardwareLoopBack) { > + *Control |=3D EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE; > + } > + if (UsbSerialDevice->ControlValues.HardwareFlowControl) { > + *Control |=3D 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 =3D=3D UsbSerialDevice->DataBuffer= Tail) { > + *Control |=3D EFI_SERIAL_OUTPUT_BUFFER_EMPTY; > + *Control |=3D EFI_SERIAL_INPUT_BUFFER_EMPTY; > + } > + // > + // check for software loopback enable in UsbSerialDevice->ControlValue= s > + // > + if (UsbSerialDevice->ControlValues.SoftwareLoopBack) { > + *Control |=3D EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Resets the USB Serial Device > + > + This function is the internal method for resetting the device and is c= alled > 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 =3D FTDI_COMMAND_RESET_PORT; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Value =3D RESET_PORT_PURGE_RX; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; //indicates that there is not data phase in = this > request > + > + Status =3D UsbSerialDevice->UsbIo->UsbControlTransfer ( > + UsbSerialDevice->UsbIo, > + &DevReq, > + EfiUsbDataIn, > + WDR_TIMEOUT, > + &ConfigurationValue, > + 1, > + &ReturnValue > + ); > + if (EFI_ERROR (Status)) { > + return EFI_DEVICE_ERROR; > + } > + > + DevReq.Request =3D FTDI_COMMAND_RESET_PORT; > + DevReq.RequestType =3D USB_REQ_TYPE_VENDOR; > + DevReq.Value =3D RESET_PORT_PURGE_TX; > + DevReq.Index =3D FTDI_PORT_IDENTIFIER; > + DevReq.Length =3D 0; //indicates that there is no data phase in t= his > request > + > + Status =3D 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 EF= I > 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 =3D 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 =3D 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 =3D 0; Index < HandleCount; Index++) { > + Status =3D gBS->DisconnectController ( > + HandleBuffer[Index], > + gImageHandle, > + NULL > + ); > + } > + > + // > + // Free the handle array > + // > + FreePool (HandleBuffer); > + > + // > + // Uninstall protocols installed by the driver in its entrypoint > + // > + Status =3D 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 proto= col. > + @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 !=3D NULL) { > + if (!IsDevicePathEnd (RemainingDevicePath)) { > + Status =3D EFI_UNSUPPORTED; > + UartNode =3D (UART_DEVICE_PATH *) NextDevicePathNode > (RemainingDevicePath); > + if (UartNode->Header.Type !=3D MESSAGING_DEVICE_PATH || > + UartNode->Header.SubType !=3D MSG_UART_DP || > + sizeof (UART_DEVICE_PATH) !=3D DevicePathNodeLength > ((EFI_DEVICE_PATH *) UartNode)) { > + goto Error; > + } > + FlowControlNode =3D (UART_FLOW_CONTROL_DEVICE_PATH *) > NextDevicePathNode (UartNode); > + if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & > ~UART_FLOW_CONTROL_HARDWARE) !=3D 0) { > + goto Error; > + } > + } > + } > + > + // > + // Check if USB I/O Protocol is attached on the controller handle. > + // > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + (VOID **) &UsbIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (Status =3D=3D EFI_ALREADY_STARTED) { > + if (RemainingDevicePath =3D=3D NULL || IsDevicePathEnd > (RemainingDevicePath)) { > + return EFI_SUCCESS; > + } > + Status =3D gBS->OpenProtocolInformation ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + &OpenInfoBuffer, > + &EntryCount > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + for (Index =3D 0; Index < EntryCount; Index++) { > + if ((OpenInfoBuffer[Index].Attributes & > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) !=3D 0) { > + Status =3D gBS->OpenProtocol ( > + OpenInfoBuffer[Index].ControllerHandle, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &DevicePath, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (!EFI_ERROR (Status)) { > + HasFlowControl =3D ContainsFlowControl (RemainingDevicePath); > + if (HasFlowControl ^ ContainsFlowControl (DevicePath)) { > + Status =3D EFI_UNSUPPORTED; > + } > + } > + break; > + } > + } > + FreePool (OpenInfoBuffer); > + return Status; > + } > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &ParentDevicePath, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (Status =3D=3D 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 =3D EFI_SUCCESS; > + > + if (!IsUsbSerial (UsbIo)) { > + Status =3D 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 insta= nce. > + @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 Control; > + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; > + > + UsbSerialDevice =3D AllocateZeroPool (sizeof (USB_SER_DEV)); > + ASSERT (UsbSerialDevice !=3D NULL); > + > + // > + // Get the Parent Device path > + // > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &ParentDevicePath, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status) && Status !=3D EFI_ALREADY_STARTED) { > + goto ErrorExit1; > + } > + > + // > + // Open USB I/O Protocol > + // > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + (VOID **) &UsbIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status) && Status !=3D EFI_ALREADY_STARTED) { > + goto ErrorExit1; > + } > + > + if (Status =3D=3D EFI_ALREADY_STARTED) { > + if (RemainingDevicePath =3D=3D NULL || IsDevicePathEnd > (RemainingDevicePath)) { > + FreePool (UsbSerialDevice); > + return EFI_SUCCESS; > + } > + > + // > + // Check to see if a child handle exists > + // > + Status =3D gBS->OpenProtocolInformation ( > + Controller, > + &gEfiSerialIoProtocolGuid, > + &OpenInfoBuffer, > + &EntryCount > + ); > + if (EFI_ERROR (Status)) { > + goto ErrorExit1; > + } > + > + Status =3D EFI_ALREADY_STARTED; > + for (Index =3D 0; Index < EntryCount; Index++) { > + if ((OpenInfoBuffer[Index].Attributes & > EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) !=3D 0) { > + Status =3D 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 =3D (UART_DEVICE_PATH *) RemainingDevicePath; > + Status =3D 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 =3D (UART_FLOW_CONTROL_DEVICE_PATH *) > NextDevicePathNode (Uart); > + if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)= ) { > + Status =3D SerialIo->GetControl ( > + SerialIo, > + &Control > + ); > + if (!EFI_ERROR (Status)) { > + if (ReadUnaligned32 (&FlowControl->FlowControlMap) =3D=3D > UART_FLOW_CONTROL_HARDWARE) { > + Control |=3D EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; > + } else { > + Control &=3D ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE; > + } > + // > + // Clear bits that are not allowed to be passed to SetCont= rol > + // > + Control &=3D (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 =3D SerialIo->SetControl (SerialIo, Control); > + } > + } > + } > + break; > + } > + } > + FreePool (OpenInfoBuffer); > + return Status; > + } > + > + if (RemainingDevicePath !=3D NULL) { > + if (IsDevicePathEnd (RemainingDevicePath)) { > + return EFI_SUCCESS; > + } > + } > + > + UsbSerialDevice->UsbIo =3D UsbIo; > + > + // > + // Get interface & endpoint descriptor > + // > + UsbIo->UsbGetInterfaceDescriptor ( > + UsbIo, > + &UsbSerialDevice->InterfaceDescriptor > + ); > + > + EndpointNumber =3D UsbSerialDevice->InterfaceDescriptor.NumEndpoints; > + > + // > + // Traverse endpoints to find the IN and OUT endpoints that will send = and > + // receive data. > + // > + FoundIn =3D FALSE; > + FoundOut =3D FALSE; > + for (Index =3D 0; Index < EndpointNumber; Index++) { > + > + Status =3D UsbIo->UsbGetEndpointDescriptor ( > + UsbIo, > + Index, > + &EndpointDescriptor > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + if (EndpointDescriptor.EndpointAddress =3D=3D > FTDI_ENDPOINT_ADDRESS_OUT) { > + // > + // Set the Out endpoint device > + // > + CopyMem ( > + &UsbSerialDevice->OutEndpointDescriptor, > + &EndpointDescriptor, > + sizeof(EndpointDescriptor) > + ); > + FoundOut =3D TRUE; > + } > + > + if (EndpointDescriptor.EndpointAddress =3D=3D > FTDI_ENDPOINT_ADDRESS_IN) { > + // > + // Set the In endpoint device > + // > + CopyMem ( > + &UsbSerialDevice->InEndpointDescriptor, > + &EndpointDescriptor, > + sizeof(EndpointDescriptor) > + ); > + FoundIn =3D TRUE; > + } > + } > + > + if (!FoundIn || !FoundOut) { > + // > + // No interrupt endpoint found, then return unsupported. > + // > + Status =3D EFI_UNSUPPORTED; > + goto ErrorExit; > + } > + // > + // set the initial values of UsbSerialDevice->LastSettings to the defa= ult > + // values > + // > + UsbSerialDevice->LastSettings.BaudRate =3D 115200; > + UsbSerialDevice->LastSettings.DataBits =3D 8; > + UsbSerialDevice->LastSettings.Parity =3D NoParity; > + UsbSerialDevice->LastSettings.ReceiveFifoDepth =3D > FTDI_MAX_RECEIVE_FIFO_DEPTH; > + UsbSerialDevice->LastSettings.StopBits =3D OneStopBit; > + UsbSerialDevice->LastSettings.Timeout =3D FTDI_TIMEOUT; > + > + // > + // set the initial values of UsbSerialDevice->ControlValues > + // > + UsbSerialDevice->ControlValues.DtrState =3D FALSE; > + UsbSerialDevice->ControlValues.RtsState =3D FALSE; > + UsbSerialDevice->ControlValues.HardwareFlowControl =3D FALSE; > + UsbSerialDevice->ControlValues.HardwareLoopBack =3D FALSE; > + UsbSerialDevice->ControlValues.SoftwareLoopBack =3D FALSE; > + > + // > + // set the values of UsbSerialDevice->UartDevicePath > + // > + UsbSerialDevice->UartDevicePath.Header.Type =3D > MESSAGING_DEVICE_PATH; > + UsbSerialDevice->UartDevicePath.Header.SubType =3D MSG_UART_DP; > + UsbSerialDevice->UartDevicePath.Header.Length[0] =3D (UINT8) (sizeof > (UART_DEVICE_PATH)); > + UsbSerialDevice->UartDevicePath.Header.Length[1] =3D (UINT8) ((sizeof > (UART_DEVICE_PATH)) >> 8); > + > + // > + // set the values of UsbSerialDevice->FlowControlDevicePath > + UsbSerialDevice->FlowControlDevicePath.Header.Type =3D > MESSAGING_DEVICE_PATH; > + UsbSerialDevice->FlowControlDevicePath.Header.SubType =3D > MSG_VENDOR_DP; > + UsbSerialDevice->FlowControlDevicePath.Header.Length[0] =3D (UINT8) > (sizeof (UART_FLOW_CONTROL_DEVICE_PATH)); > + UsbSerialDevice->FlowControlDevicePath.Header.Length[1] =3D (UINT8) > ((sizeof (UART_FLOW_CONTROL_DEVICE_PATH)) >> 8); > + UsbSerialDevice->FlowControlDevicePath.FlowControlMap =3D 0; > + > + Status =3D 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 =3D SetControlBitsInternal ( > + UsbSerialDevice, > + &(UsbSerialDevice->ControlValues) > + ); > + > + ASSERT_EFI_ERROR (Status); > + > + // > + // Publish Serial GUID and protocol > + // > + > + UsbSerialDevice->Signature =3D USB_SER_DEV_SIGNATURE; > + UsbSerialDevice->SerialIo.Reset =3D SerialReset; > + UsbSerialDevice->SerialIo.SetControl =3D SetControlBits; > + UsbSerialDevice->SerialIo.SetAttributes =3D SetAttributes; > + UsbSerialDevice->SerialIo.GetControl =3D GetControlBits; > + UsbSerialDevice->SerialIo.Read =3D ReadSerialIo; > + UsbSerialDevice->SerialIo.Write =3D WriteSerialIo; > + > + // > + // Set the static Serial IO modes that will display when running > + // "sermode" within the UEFI shell. > + // > + > + UsbSerialDevice->SerialIo.Mode->Timeout =3D 0; > + UsbSerialDevice->SerialIo.Mode->BaudRate =3D 115200; > + UsbSerialDevice->SerialIo.Mode->DataBits =3D 8; > + UsbSerialDevice->SerialIo.Mode->Parity =3D 1; > + UsbSerialDevice->SerialIo.Mode->StopBits =3D 1; > + > + UsbSerialDevice->ParentDevicePath =3D ParentDevicePath; > + UsbSerialDevice->ControllerHandle =3D NULL; > + FlowControl =3D NULL; > + > + // > + // Allocate space for the receive buffer > + // > + UsbSerialDevice->DataBuffer =3D AllocateZeroPool (SW_FIFO_DEPTH); > + > + // > + // Initialize data buffer pointers. > + // Head=3D=3DTail =3D true means buffer is empty. > + // > + UsbSerialDevice->DataBufferHead =3D 0; > + UsbSerialDevice->DataBufferTail =3D 0; > + > + UsbSerialDevice->ControllerNameTable =3D 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 =3D 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 chang= e the > settings > + // of the device to match those on the device path > + // > + if (RemainingDevicePath !=3D NULL) { > + CopyMem ( > + &UsbSerialDevice->UartDevicePath, > + RemainingDevicePath, > + sizeof (UART_DEVICE_PATH) > + ); > + FlowControl =3D (UART_FLOW_CONTROL_DEVICE_PATH *) > NextDevicePathNode (RemainingDevicePath); > + if (IsUartFlowControlNode (FlowControl)) { > + UsbSerialDevice->FlowControlDevicePath.FlowControlMap =3D > ReadUnaligned32 (&FlowControl->FlowControlMap); > + } else { > + FlowControl =3D NULL; > + } > + } > + > + // > + // Build the device path by appending the UART node to the parent devi= ce > path > + // > + UsbSerialDevice->DevicePath =3D AppendDevicePathNode ( > + ParentDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) &UsbSeria= lDevice- > >UartDevicePath > + ); > + // > + // Continue building the device path by appending the flow control nod= e > + // > + TempDevicePath =3D UsbSerialDevice->DevicePath; > + UsbSerialDevice->DevicePath =3D AppendDevicePathNode ( > + TempDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) &UsbSeria= lDevice- > >FlowControlDevicePath > + ); > + FreePool (TempDevicePath); > + > + if (UsbSerialDevice->DevicePath =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto ErrorExit; > + } > + > + // > + // Install protocol interfaces for the device > + // > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &UsbSerialDevice->ControllerHandle, > + &gEfiDevicePathProtocolGuid, > + UsbSerialDevice->DevicePath, > + &gEfiSerialIoProtocolGuid, > + &UsbSerialDevice->SerialIo, > + NULL > + ); > + if (EFI_ERROR (Status)){ > + goto ErrorExit; > + } > + > + // > + // Open for child device > + // > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + (VOID **) &UsbIo, > + This->DriverBindingHandle, > + UsbSerialDevice->ControllerHandle, > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER > + ); > + > + UsbSerialDevice->Shutdown =3D FALSE; > + > + return EFI_SUCCESS; > + > +ErrorExit: > + // > + // Error handler > + // > + > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > + Controller, > + &gEfiSerialIoProtocolGuid, > + &UsbSerialDevice->SerialIo, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + goto ErrorExit1; > + } > + > + FreePool (UsbSerialDevice->DataBuffer); > + FreePool (UsbSerialDevice); > + > + UsbSerialDevice =3D 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 proto= col. > + @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 attache= d 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 =3D EFI_SUCCESS; > + UsbSerialDevice =3D NULL; > + > + if (NumberOfChildren =3D=3D 0) { > + // > + // Close the driver > + // > + Status =3D gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + Status =3D gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + return Status; > + } > + > + AllChildrenStopped =3D TRUE; > + > + for (Index =3D 0; Index < NumberOfChildren ;Index++) { > + Status =3D gBS->OpenProtocol ( > + ChildHandleBuffer[Index], > + &gEfiSerialIoProtocolGuid, > + (VOID **) &SerialIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (Status =3D=3D EFI_SUCCESS) {//!EFI_ERROR (Status)) { > + UsbSerialDevice =3D USB_SER_DEV_FROM_THIS (SerialIo); > + Status =3D gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + This->DriverBindingHandle, > + ChildHandleBuffer[Index] > + ); > + Status =3D 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 !=3D NULL) { > + gBS->FreePool (UsbSerialDevice->DevicePath); > + } > + gBS->SetTimer ( > + UsbSerialDevice->PollingLoop, > + TimerCancel, > + 0 > + ); > + gBS->CloseEvent (UsbSerialDevice->PollingLoop); > + UsbSerialDevice->Shutdown =3D TRUE; > + FreeUnicodeStringTable (UsbSerialDevice->ControllerNameTable); > + FreePool (UsbSerialDevice->DataBuffer); > + FreePool (UsbSerialDevice); > + } > + } > + if (EFI_ERROR (Status)) { > + AllChildrenStopped =3D 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 =3D USB_SER_DEV_FROM_THIS (This); > + Status =3D 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 seri= al > device. > + @retval EFI_UNSUPPORTED The serial device does not support this > operation. > + @retval EFI_DEVICE_ERROR The serial device is not functioning corr= ectly. > + > +**/ > +EFI_STATUS > +EFIAPI > +SetControlBits ( > + IN EFI_SERIAL_IO_PROTOCOL *This, > + IN UINT32 Control > + ) > +{ > + EFI_STATUS Status; > + USB_SER_DEV *UsbSerialDevice; > + CONTROL_BITS ControlBits; > + > + UsbSerialDevice =3D 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))) !=3D 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 =3D FALSE; > + ControlBits.SoftwareLoopBack =3D FALSE; > + // > + // check for hardware flow control > + // > + if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) =3D=3D > EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) { > + ControlBits.HardwareFlowControl =3D TRUE; > + } else { > + ControlBits.HardwareFlowControl =3D FALSE; > + } > + // > + // check for DTR enabled > + // > + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) =3D=3D > EFI_SERIAL_DATA_TERMINAL_READY) { > + ControlBits.DtrState =3D TRUE; > + } else { > + ControlBits.DtrState =3D FALSE; > + } > + // > + // check for RTS enabled > + // > + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) =3D=3D > EFI_SERIAL_REQUEST_TO_SEND) { > + ControlBits.RtsState =3D TRUE; > + } else { > + ControlBits.RtsState =3D FALSE; > + } > + > + // > + // set the control values with a call to SetControlBitsInternal() > + // > + Status =3D 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 seria= l > + 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 s= peed. > + @param ReveiveFifoDepth[in] The requested depth of the FIFO on the > receive > + side of the serial interface. A ReceiveFi= foDepth > + value of 0 will use the device's default = FIFO > + depth. > + @param Timeout[in] The requested time out for a single chara= cter in > + microseconds.This timeout applies to both= the > + transmit and receive side of the interfac= e. 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 ser= ial > + 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 se= rial > + device. A StopBits value of DefaultStopBi= ts will > + use the device's default number of stop b= its. > + > + @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 =3D USB_SER_DEV_FROM_THIS (This); > + > + Status =3D 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 ser= ial > + 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 =3D USB_SER_DEV_FROM_THIS (This); > + > + *Control =3D 0; > + > + Status =3D 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. O= n output, > + the amount of data returned in Buff= er. > + @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 =3D=3D 0) { > + return EFI_SUCCESS; > + } > + > + if (Buffer =3D=3D NULL) { > + return EFI_DEVICE_ERROR; > + } > + > + Status =3D EFI_SUCCESS; > + UsbSerialDevice =3D USB_SER_DEV_FROM_THIS (This); > + > + // > + // Clear out any data that we already have in our internal buffer > + // > + for (Index =3D 0; Index < *BufferSize; Index++) { > + if (UsbSerialDevice->DataBufferHead =3D=3D UsbSerialDevice->DataBuff= erTail) > { > + break; > + } > + > + // > + // Still have characters in the buffer to return > + // > + ((UINT8 *)Buffer)[Index] =3D UsbSerialDevice->DataBuffer[UsbSerialDe= vice- > >DataBufferHead]; > + UsbSerialDevice->DataBufferHead =3D (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 !=3D *BufferSize) { > + RemainingCallerBufferSize =3D *BufferSize - Index; > + Status =3D ReadDataFromUsb ( > + UsbSerialDevice, > + &RemainingCallerBufferSize, > + (VOID *)(((CHAR8 *)Buffer) + Index) > + ); > + if (!EFI_ERROR (Status)) { > + *BufferSize =3D RemainingCallerBufferSize + Index; > + } else { > + *BufferSize =3D Index; > + } > + } > + > + if (UsbSerialDevice->DataBufferHead =3D=3D UsbSerialDevice->DataBuffer= Tail) { > + // > + // Data buffer has no data, set the EFI_SERIAL_INPUT_BUFFER_EMPTY > flag > + // > + UsbSerialDevice->ControlBits |=3D EFI_SERIAL_INPUT_BUFFER_EMPTY; > + } else { > + // > + // There is some leftover data, clear EFI_SERIAL_INPUT_BUFFER_EMPTY > flag > + // > + UsbSerialDevice->ControlBits &=3D ~(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. O= n 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 =3D USB_SER_DEV_FROM_THIS (This); > + > + if (UsbSerialDevice->Shutdown) { > + return EFI_DEVICE_ERROR; > + } > + > + Tpl =3D gBS->RaiseTPL (TPL_NOTIFY); > + > + Status =3D UsbSerialDataTransfer ( > + UsbSerialDevice, > + EfiUsbDataOut, > + Buffer, > + BufferSize, > + FTDI_TIMEOUT > + ); > + > + gBS->RestoreTPL (Tpl); > + if (EFI_ERROR (Status)) { > + if (Status =3D=3D EFI_TIMEOUT){ > + return Status; > + } else { > + return EFI_DEVICE_ERROR; > + } > + } > + > + return EFI_SUCCESS; > +} > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h > new file mode 100644 > index 0000000000..6048923d6f > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDriver.h > @@ -0,0 +1,589 @@ > +/** @file > + Header file for USB Serial Driver's Data Structures. > + > +Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved. > +Portions Copyright 2012 Ashley DeSimone > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _FTDI_USB_SERIAL_DRIVER_H_ > +#define _FTDI_USB_SERIAL_DRIVER_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +// > +// 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 ind= ex > 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 ev= ent > + // trigger, sets the event char to 0= x0d 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 fro= m > +// 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 = =3D > 46601941 > +#define FTDI_MAX_FREQUENCY 49484536 // (3MHz * 1600) / 97 = =3D > 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 =3D (1 | (1 << 8)), SET_DTR_LOW =3D (0 | (1 << 8) > +// SET_RTS_HIGH =3D (2 | (2 << 8)), SET_RTS_LOW =3D (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)) !=3D= 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 proto= col. > + @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 insta= nce. > + @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 proto= col. > + @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 T= ext > In Ex > + Protocol is not installed on Contro= ller. > + @retval EFI_DEVICE_ERROR The device could not be stopped due= to > a > + device error. > + @retval Others Fail to uninstall protocols attache= d 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. O= n 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. O= n output, > + the amount of data returned in Buff= er. > + @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 ser= ial > + 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 seri= al > device. > + @retval EFI_UNSUPPORTED The serial device does not support this > operation. > + @retval EFI_DEVICE_ERROR The serial device is not functioning corr= ectly. > + > +**/ > +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 seria= l > 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 s= peed. > + @param ReveiveFifoDepth[in] The requested depth of the FIFO on the > receive > + side of the serial interface. A ReceiveFi= foDepth > + value of 0 will use the device's default = FIFO > + depth. > + @param Timeout[in] The requested time out for a single chara= cter in > + microseconds.This timeout applies to both= the > + transmit and receive side of the interfac= e.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 th= e > + device's default parity value. > + @param DataBits[in] The number of data bits to use on the ser= ial > + device. A DataBits value of 0 will use th= e > + device's default data bit setting. > + @param StopBits[in] The number of stop bits to use on this se= rial > + device. A StopBits value of DefaultStopBi= ts will > + use the device's default number of stop b= its. > + > + @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 drive= r. > + > + 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 na= me 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 inst= ance. > + @param Language[in] A pointer to a Null-terminated ASCI= I string > + array indicating the language. This= is the > + language of the driver name that th= e caller > + is requesting, and it must match on= e of the > + languages specified in SupportedLan= guages. > + The number of languages supported b= y 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 lan= guage > + specified by Language. > + > + @retval EFI_SUCCESS The Unicode string for the Driver s= pecified > + 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 n= ot > + support the language specified by L= anguage. > + > +**/ > +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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 inst= ance. > + @param ControllerHandle[in] The handle of a controller that the > driver > + specified by This is managing. Thi= s 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 op= tional > + parameter that may be NULL. It will= be NULL > + for device drivers. It will also be= NULL > + for a bus drivers that wish to retr= ieve the > + name of the bus controller. It will= not be > + NULL for a bus driver that wishes t= o > + retrieve the name of a child contro= ller. > + @param Language[in] A pointer to a Null-terminated ASCI= I string > + array indicating the language. Thi= s is the > + language of the driver name that th= e caller > + is requesting, and it must match on= e of the > + languages specified in SupportedLan= guages. > + The number of languages supported b= y 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 ControllerH= andle > + and ChildHandle in the language spe= cified > + by Language from the point of view = of the > + driver specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user rea= dable > + name in the language specified by L= anguage > + for the driver specified by This wa= s > + 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 n= ot > 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 s= pecified > + by ControllerHandle and ChildHandle= . > + @retval EFI_UNSUPPORTED The driver specified by This does n= ot > + support the language specified by L= anguage. > + > +**/ > +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/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf > new file mode 100644 > index 0000000000..67c1d36470 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/FtdiUsbSerialDxe.inf > @@ -0,0 +1,55 @@ > +## @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 - 2018, Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D FtdiUsbSerialDxe > + FILE_GUID =3D A8154B55-2021-4D40-AE81-2E23A02dCC4= 6 > + MODULE_TYPE =3D UEFI_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D FtdiUsbSerialEntryPoint > + UNLOAD_IMAGE =3D FtdiUsbSerialUnload > + > +# > +# VALID_ARCHITECTURES =3D IA32 X64 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/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt > b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt > new file mode 100644 > index 0000000000..d8ca227a41 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Bus/Usb/FtdiUsbSerialDxe/ReadMe.txt > @@ -0,0 +1,32 @@ > + > +=3D=3D=3D FTDI USB SERIAL OVERVIEW =3D=3D=3D > + > +This is a bus driver that enables the EfiSerialIoProtocol interface > +for FTDI8U232AM based USB-to-Serial adapters. > + > +=3D=3D=3D STATUS =3D=3D=3D > + > +Serial Input: Functional on real hardware. > +Serial Output: Functional on real hardware. > + > +Operating Modes: Currently the user is able to change all operating mode= s > +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 transm= itted > incorrectly. > + > +=3D=3D=3D COMPATIBILITY =3D=3D=3D > + > +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 confirme= d > to work with this > +driver. > \ No newline at end of file > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c > new file mode 100644 > index 0000000000..c9329f506d > --- /dev/null > +++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.c > @@ -0,0 +1,1318 @@ > +/** @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 availa= ble. > + > + Copyright (c) 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Ax88772.h" > + > + > +/** > + Compute the CRC > + > + @param [in] pMacAddress Address of a six byte buffer to containin= g 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 =3D -1; > + pEnd =3D &pMacAddress[ PXE_HWADDR_LEN_ETHER ]; > + while ( pEnd > pMacAddress ) { > + Data =3D *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 =3D 0; 8 > BitNumber; BitNumber++ ) { > + Carry =3D (( Crc >> 31 ) & 1 ) ^ ( Data & 1 ); > + Crc <<=3D 1; > + if ( 0 !=3D Carry ) { > + Crc ^=3D 0x04c11db7; > + } > + Data >>=3D 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 =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MAC_ADDRESS_READ; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D PXE_HWADDR_LEN_ETHER; > + > + // > + // Read the PHY register > + // > + Status =3D 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 containin= g 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MAC_ADDRESS_WRITE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D PXE_HWADDR_LEN_ETHER; > + > + // > + // Read the PHY register > + // > + Status =3D 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] =3D 0; > + pNicDevice->MulticastHash[1] =3D 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 containin= g 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 =3D Ax88772Crc ( pMacAddress ); > + > + // > + // Set the bit corresponding to the destination address > + // > + BitNumber =3D Crc >> 26; > + if ( 32 > BitNumber ) { > + Mask =3D 1 << BitNumber; > + pNicDevice->MulticastHash[0] |=3D Mask; > + } > + else { > + Mask =3D 1 << ( BitNumber - 32 ); > + pNicDevice->MulticastHash[1] |=3D 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 =3D 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 =3D BMCR_AUTONEGOTIATION_ENABLE > + | BMCR_RESTART_AUTONEGOTIATION; > + if ( pNicDevice->b100Mbps ) { > + Control |=3D BMCR_100MBPS; > + } > + if ( pNicDevice->bFullDuplex ) { > + Control |=3D BMCR_FULL_DUPLEX; > + } > + Status =3D 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 w= as > polled > + @param [out] pbComplete Address of boolean to receive complate > status. > + @param [out] pbLinkUp Address of boolean to receive link status= , > TRUE=3Dup. > + @param [out] pbHiSpeed Address of boolean to receive link speed, > TRUE=3D100Mbps. > + @param [out] pbFullDuplex Address of boolean to receive link duplex= , > TRUE=3Dfull. > + > + @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 =3D FALSE; > + > + // > + // Get the link status > + // > + Status =3D Ax88772PhyRead ( pNicDevice, > + PHY_BMSR, > + &PhyData ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Determine if the autonegotiation is complete. > + // > + *pbLinkUp =3D (BOOLEAN)( 0 !=3D ( PhyData & BMSR_LINKST )); > + *pbComplete =3D *pbLinkUp; > + if ( 0 !=3D *pbComplete ) { > + // > + // Get the partners capabilities. > + // > + Status =3D Ax88772PhyRead ( pNicDevice, > + PHY_ANLPAR, > + &PhyData ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Autonegotiation is complete > + // Determine the link speed. > + // > + *pbHiSpeed =3D (BOOLEAN)( 0 !=3D ( PhyData & ( AN_TX_FDX | > AN_TX_HDX ))); > + > + // > + // Determine the link duplex. > + // > + Mask =3D ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX; > + *pbFullDuplex =3D (BOOLEAN)( 0 !=3D ( 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_SOFTWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Read the PHY register address. > + // > + SetupMsg.RequestType =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_REG_READ; > + SetupMsg.Value =3D pNicDevice->PhyId; > + SetupMsg.Index =3D RegisterAddress; > + SetupMsg.Length =3D sizeof ( *pPhyData ); > + Status =3D 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_HARDWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 re= gister > 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_SOFTWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Write the PHY register > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_REG_WRITE; > + SetupMsg.Value =3D pNicDevice->PhyId; > + SetupMsg.Index =3D RegisterAddress; > + SetupMsg.Length =3D sizeof ( PhyData ); > + Status =3D 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_HARDWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RX_CONTROL_WRITE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 =3D TRUE; > + > + // > + // Delay for a bit > + // > + gBS->Stall ( RESET_MSEC ); > + > + // > + // Select the internal PHY > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_SELECT; > + SetupMsg.Value =3D SPHY_PSEL; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Delay for a bit > + // > + gBS->Stall ( PHY_RESET_MSEC ); > + > + // > + // Clear the internal PHY reset > + // > + SetupMsg.Request =3D CMD_RESET; > + SetupMsg.Value =3D SRR_IPRL | SRR_PRL; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Reset the PHY > + // > + Status =3D Ax88772PhyWrite ( pNicDevice, > + PHY_BMCR, > + BMCR_RESET ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Set the gaps > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_GAPS_WRITE; > + SetupMsg.Value =3D 0x0c15; > + SetupMsg.Index =3D 0x0e; > + SetupMsg.Length =3D 0; > + Status =3D 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; > + EFI_STATUS Status; > + > + for ( offset =3D 0; offset < BufLength; ){ > + pLength =3D (UINT16*) (pNicDevice->pBulkInBuff + offset); > + pLengthBar =3D (UINT16*) (pNicDevice->pBulkInBuff + offset +2); > + > + *pLength &=3D 0x7ff; > + *pLengthBar &=3D 0x7ff; > + *pLengthBar |=3D 0xf800; > + > + if ((*pLength ^ *pLengthBar ) !=3D 0xFFFF) { > + DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength =3D %d\n", > BufLength)); > + return; > + } > + > + pRxPacket =3D pNicDevice->pRxFree; > + if ( NULL =3D=3D pRxPacket ) { > + Status =3D gBS->AllocatePool ( EfiRuntimeServicesData, > + sizeof( RX_TX_PACKET ), > + (VOID **) &pRxPacket ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Add this packet to the free packet list > + // > + pNicDevice->pRxFree =3D pRxPacket; > + pRxPacket->pNext =3D NULL; > + } > + else { > + // > + // Use the discard packet buffer > + // > + //pRxPacket =3D &Packet; > + } > + } > + > + > + pData =3D pNicDevice->pBulkInBuff + offset + 4; > + pRxPacket->Length =3D *pLength; > + pRxPacket->LengthBar =3D *(UINT16*) (pNicDevice->pBulkInBuff + offse= t > +2); > + CopyMem (&pRxPacket->Data[0], pData, *pLength); > + //DEBUG((DEBUG_INFO, "Packet [%d]\n", *pLength)); > + > + pNicDevice->pRxFree =3D pRxPacket->pNext; > + pRxPacket->pNext =3D NULL; > + > + if ( NULL =3D=3D pNicDevice->pRxTail ) { > + pNicDevice->pRxHead =3D pRxPacket; > + } > + else { > + pNicDevice->pRxTail->pNext =3D pRxPacket; > + } > + pNicDevice->pRxTail =3D pRxPacket; > + offset +=3D (*pLength + 4); > + > + } > +} > + > + > + > +/** > + Receive a frame from the network. > + > + This routine polls the USB receive interface for a packet. If a packe= t > + 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 =3D 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 =3D gBS->RaiseTPL ( TPL_AX88772 ); > + DEBUG (( DEBUG_TPL | DEBUG_INFO, > + "%d: TPL\r\n", > + TPL_AX88772 )); > + > + // > + // Get the link status > + // > + if ( bUpdateLink ) { > + bLinkUp =3D pNicDevice->bLinkUp; > + bSpeed100 =3D pNicDevice->b100Mbps; > + bFullDuplex =3D pNicDevice->bFullDuplex; > + Status =3D 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 =3D 0; > + DEBUG (( DEBUG_LINK | DEBUG_INFO, > + "Reset to establish proper link setup: %d Mbps, %s d= uplex\r\n", > + pNicDevice->b100Mbps ? 100 : 10, > + pNicDevice->bFullDuplex ? L"Full" : L"Half" )); > + Status =3D 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 =3D FALSE; > + > + // > + // Locate a packet for use > + // > + pRxPacket =3D pNicDevice->pRxFree; > + LengthInBytes =3D MAX_BULKIN_SIZE; > + if ( NULL =3D=3D pRxPacket ) { > + Status =3D gBS->AllocatePool ( EfiRuntimeServicesData, > + sizeof ( *pRxPacket ), > + (VOID **) &pRxPacket ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Add this packet to the free packet list > + // > + pNicDevice->pRxFree =3D pRxPacket; > + pRxPacket->pNext =3D NULL; > + } > + else { > + // > + // Use the discard packet buffer > + // > + pRxPacket =3D &Packet; > + } > + } > + > + // > + // Attempt to receive a packet > + // > + SetMem (&pNicDevice->pBulkInBuff[0], MAX_BULKIN_SIZE, 0); > + pUsbIo =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbBulkTransfer ( pUsbIo, > + USB_ENDPOINT_DIR_IN | BULK_IN_END= POINT, > + &pNicDevice->pBulkInBuff[0], > + &LengthInBytes, > + 2, > + &TransferStatus ); > + if ( LengthInBytes > 0 ) { > + FillPkt2Queue(pNicDevice, LengthInBytes); > + } > + pRxPacket =3D pNicDevice->pRxHead; > + if (( !EFI_ERROR ( Status )) > + && ( 0 < pRxPacket->Length ) > + && ( pRxPacket->Length <=3D sizeof ( pRxPacket->Data )) > + && ( LengthInBytes > 0)) { > + > + // > + // Determine if the packet should be received > + // > + bRxPacket =3D TRUE; > + LengthInBytes =3D pRxPacket->Length; > + pNicDevice->bLinkIdle =3D FALSE; > + if ( pNicDevice->pRxFree =3D=3D pRxPacket ) { > + // > + // Display the received packet > + // > + if ( 0 !=3D ( pRxPacket->Data[0] & 1 )) { > + if (( 0xff =3D=3D pRxPacket->Data[0]) > + && ( 0xff =3D=3D pRxPacket->Data[1]) > + && ( 0xff =3D=3D pRxPacket->Data[2]) > + && ( 0xff =3D=3D pRxPacket->Data[3]) > + && ( 0xff =3D=3D pRxPacket->Data[4]) > + && ( 0xff =3D=3D 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] =3D 0; > + MulticastHash[1] =3D 0; > + > + // > + // Enable the receiver if something is to be received > + // > + Status =3D EFI_SUCCESS; > + RxControl =3D RXC_SO | RXC_MFB_16384; > + if ( 0 !=3D RxFilter ) { > + // > + // Enable the receiver > + // > + SetupMsg.RequestType =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MEDIUM_STATUS_READ; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D sizeof ( MediumStatus ); > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + &MediumStatus ); > + if ( !EFI_ERROR ( Status )) { > + if ( 0 =3D=3D ( MediumStatus & MS_RE )) { > + MediumStatus |=3D MS_RE | MS_ONE; > + if ( pNicDevice->bFullDuplex ) { > + MediumStatus |=3D MS_TFC | MS_RFC; > + } > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MEDIUM_STATUS_WRITE; > + SetupMsg.Value =3D MediumStatus; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 !=3D ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) { > + RxControl |=3D RXC_AM; > + MulticastHash[0] =3D pNicDevice->MulticastHash[0]; > + MulticastHash[1] =3D pNicDevice->MulticastHash[1]; > + } > + > + // > + // Enable all multicast if requested > + // > + if ( 0 !=3D ( RxFilter & > EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) { > + RxControl |=3D RXC_AMALL; > + MulticastHash[0] =3D -1; > + MulticastHash[1] =3D -1; > + } > + > + // > + // Enable broadcast if requested > + // > + if ( 0 !=3D ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) { > + RxControl |=3D RXC_AB; > + } > + > + // > + // Enable promiscuous mode if requested > + // > + if ( 0 !=3D ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) { > + RxControl |=3D RXC_PRO; > + MulticastHash[0] =3D -1; > + MulticastHash[1] =3D -1; > + } > + } > + > + // > + // Update the MAC address > + // > + if ( !EFI_ERROR ( Status )) { > + Status =3D Ax88772MacAddressSet ( pNicDevice, &pNicDevice- > >SimpleNetworkData.CurrentAddress.Addr[0]); > + } > + > + // > + // Update the receiver control > + // > + if ( !EFI_ERROR ( Status )) { > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RX_CONTROL_WRITE; > + SetupMsg.Value =3D RxControl; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MULTICAST_HASH_WRITE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D sizeof ( pNicDevice ->MulticastHash ); > + Status =3D 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 =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_SROM_READ; > + SetupMsg.Value =3D (UINT16) Address; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D sizeof ( *pData ); > + Status =3D 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 =3D EfiUsbNoData; > + if ( 0 !=3D pRequest->Length ) { > + Direction =3D ( 0 !=3D ( pRequest->RequestType & USB_ENDPOINT_DIR_IN= )) > + ? EfiUsbDataIn : EfiUsbDataOut; > + } > + > + // > + // Issue the command > + // > + pUsbIo =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbControlTransfer ( pUsbIo, > + pRequest, > + Direction, > + USB_BUS_TIMEOUT, > + pBuffer, > + pRequest->Length, > + &CmdStatus ); > + > + // > + // Determine the operation status > + // > + if ( !EFI_ERROR ( Status )) { > + Status =3D CmdStatus; > + } > + else { > + // > + // Display any errors > + // > + DEBUG (( DEBUG_INFO, > + "Ax88772UsbCommand - Status: %r\n", > + Status )); > + > + // > + // Only use status values associated with the Simple Network protoco= l > + // > + if ( EFI_TIMEOUT =3D=3D Status ) { > + Status =3D EFI_DEVICE_ERROR; > + } > + } > + > + // > + // Return the operation status > + // > + DBG_EXIT_STATUS ( Status ); > + return Status; > +} > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h > new file mode 100644 > index 0000000000..8840a4f464 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.h > @@ -0,0 +1,969 @@ > +/** @file > + Definitions for ASIX AX88772 Ethernet adapter. > + > + Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _AX88772_H_ > +#define _AX88772_H_ > + > +#include > + > +#include > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +//----------------------------------------------------------------------= -------- > +// Macros > +//----------------------------------------------------------------------= -------- > +// > +//Too many output debug info hangs system in Debug tip > +// > +//#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler spec= ifics. > */ > +//#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 =3D=3D Status) ? L"FALSE" : L"TRU= E" )) > ///< 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 decima= l > value > +#define DBG_EXIT_HEX(Status) ///< Display routine exit with hex va= lue > +#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) !=3D 0) ///< Return TRUE/FALSE for IN direction > +#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) > =3D=3D 0) ///< Return TRUE/FALSE for OUT direction > +#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BI= T1)) > =3D=3D USB_ENDPOINT_BULK) ///< Return TRUE/FALSE for BULK type > +#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | > BIT1)) =3D=3D 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 v= alues > +#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 t= he 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 >=3D 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 =3D 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 <=3D tpl ); \ > + } \ > +} > + > +#else // MDEPKG_NDEBUG > + > +#define VERIFY_TPL(tpl) > + > +#endif // MDEPKG_NDEBUG > + > +//----------------------------------------------------------------------= -------- > +// Hardware Definition > +//----------------------------------------------------------------------= -------- > + > +#define DEV_SIGNATURE SIGNATURE_32 ('A','X','8','8') ///< Signatur= e 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 addres= s hash > table > +#define RXC_AP 0x0020 ///< Accept physical address from Mul= ticast > 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=3D100, 0=3D10 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=3DAuto select, 0=3DManual sele= ct > + > +// > +// Software Reset register > +// > + > +#define SRR_RR 0x01 ///< Clear receive frame length error > +#define SRR_RT 0x02 ///< Clear transmit frame length erro= r > +#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, V= alue: > 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 ad= vertisement > register > +#define PHY_ANLPAR 5 ///< Autonegotiation li= nk parter > ability register > +#define PHY_ANER 6 ///< Autonegotiation ex= pansion > register > + > +// BMCR - Register 0 > + > +#define BMCR_RESET 0x8000 ///< 1 =3D Reset the PH= Y, bit clears > after reset > +#define BMCR_LOOPBACK 0x4000 ///< 1 =3D Loopback ena= bled > +#define BMCR_100MBPS 0x2000 ///< 100 Mbits/Sec > +#define BMCR_10MBPS 0 ///< 10 Mbits/Sec > +#define BMCR_AUTONEGOTIATION_ENABLE 0x1000 ///< 1 =3D Enable > autonegotiation > +#define BMCR_POWER_DOWN 0x0800 ///< 1 =3D Power down > +#define BMCR_ISOLATE 0x0400 ///< 0 =3D Isolate PHY > +#define BMCR_RESTART_AUTONEGOTIATION 0x0200 ///< 1 =3D Restart > autonegotiation > +#define BMCR_FULL_DUPLEX 0x0100 ///< Full duplex operat= ion > +#define BMCR_HALF_DUPLEX 0 ///< Half duplex operat= ion > +#define BMCR_COLLISION_TEST 0x0080 ///< 1 =3D Collision te= st > enabled > + > +// BSMR - Register 1 > + > +#define BMSR_100BASET4 0x8000 ///< 1 =3D 100BASE-T4 m= ode > +#define BMSR_100BASETX_FDX 0x4000 ///< 1 =3D 100BASE-TX f= ull > duplex > +#define BMSR_100BASETX_HDX 0x2000 ///< 1 =3D 100BASE-TX h= alf > duplex > +#define BMSR_10BASET_FDX 0x1000 ///< 1 =3D 10BASE-T ful= l duplex > +#define BMSR_10BASET_HDX 0x0800 ///< 1 =3D 10BASE-T hal= f > duplex > +#define BMSR_MF 0x0040 ///< 1 =3D PHY accepts = frames with > preamble suppressed > +#define BMSR_AUTONEG_CMPLT 0x0020 ///< 1 =3D Autonegotiat= ion > complete > +#define BMSR_RF 0x0010 ///< 1 =3D Remote fault > +#define BMSR_AUTONEG 0x0008 ///< 1 =3D Able to perf= orm > autonegotiation > +#define BMSR_LINKST 0x0004 ///< 1 =3D Link up > +#define BMSR_JABBER_DETECT 0x0002 ///< 1 =3D jabber condi= tion > detected > +#define BMSR_EXTENDED_CAPABILITY 0x0001 ///< 1 =3D Extended > register capable > + > +// ANAR and ANLPAR Registers 4, 5 > + > +#define AN_NP 0x8000 ///< 1 =3D Next page av= ailable > +#define AN_ACK 0x4000 ///< 1 =3D Link partner= acknowledged > +#define AN_RF 0x2000 ///< 1 =3D Remote fault= indicated by > link partner > +#define AN_FCS 0x0400 ///< 1 =3D Flow control= ability > +#define AN_T4 0x0200 ///< 1 =3D 100BASE-T4 s= upport > +#define AN_TX_FDX 0x0100 ///< 1 =3D 100BASE-TX F= ull duplex > +#define AN_TX_HDX 0x0080 ///< 1 =3D 100BASE-TX s= upport > +#define AN_10_FDX 0x0040 ///< 1 =3D 10BASE-T Ful= l duplex > +#define AN_10_HDX 0x0020 ///< 1 =3D 10BASE-T sup= port > +#define AN_CSMA_CD 0x0001 ///< 1 =3D IEEE 802.3 C= SMA/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 =3D 10 Mbps > + BOOLEAN bComplete; ///< Current state of auto-negotiation > + BOOLEAN bFullDuplex; ///< Current duplex > + BOOLEAN bLinkUp; ///< Current link state > + BOOLEAN bLinkIdle; ///< TRUE =3D No received traffic > + EFI_EVENT Timer; ///< Timer to monitor link state and receiv= e > packets > + UINTN PollCount; ///< Number of times the autonegotiation st= atus > 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 perfo= rm > 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 FALS= E > + then the current station address is changed to the address specified b= y > + 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 t= o the > + network interface's permanent address. > + @param [in] pNew New station address to be used for the n= etwork > + 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 tab= le 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 an= d > 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 mus= t not be NULL. > + @param [in] BufferSize The size, in bytes, of the entire packet= (media > header and > + data) to be transmitted through the netw= ork interface. > + @param [in] pBuffer A pointer to the packet (media header fo= llowed > by data) to > + to be transmitted. This parameter can n= ot be NULL. If > + HeaderSize is zero, then the media heade= r 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 HeaderSiz= e is > zero, then > + this parameter is ignored. If HeaderSiz= e is nonzero and > + SrcAddr is NULL, then SimpleNetwork->Mod= e- > >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 HeaderS= ize 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 acc= ept > 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 containin= g 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 containin= g 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 w= as > polled > + @param [out] pbComplete Address of boolean to receive complate > status. > + @param [out] pbLinkUp Address of boolean to receive link status= , > TRUE=3Dup. > + @param [out] pbHiSpeed Address of boolean to receive link speed, > TRUE=3D100Mbps. > + @param [out] pbFullDuplex Address of boolean to receive link duplex= , > TRUE=3Dfull. > + > + @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 re= gister > 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 packe= t > + 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 =3D 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 drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 3066 or ISO 639-2 language code f= ormat. > + @param [out] ppDriverName A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + @param [in] ChildHandle The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + @param [in] pLanguage A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 3066 or ISO 639-2 language code form= at. > + @param [out] ppControllerName A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf > new file mode 100644 > index 0000000000..12e7ebc5a2 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf > @@ -0,0 +1,61 @@ > +## @file > +# Component description file for ASIX AX88772 USB/Ethernet driver. > +# > +# This module provides support for the ASIX AX88772 USB/Ethernet > adapter. > +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010018 > + BASE_NAME =3D Ax88772 > + FILE_GUID =3D B15239D6-6A01-4808-A0F7-B7F20F07355= 5 > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 1.0 > + > + ENTRY_POINT =3D EntryPoint > + > +# > +# VALID_ARCHITECTURES =3D IA32 X64 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/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentNa > me.c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentNa > me.c > new file mode 100644 > index 0000000000..b6dce7e7cb > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/ComponentNa > me.c > @@ -0,0 +1,178 @@ > +/** @file > + UEFI Component Name(2) protocol implementation. > + > + Copyright (c) 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Ax88772.h" > + > +/** > + EFI Component Name Protocol declaration > +**/ > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME_PROTOCOL gComponentName =3D { > + GetDriverName, > + GetControllerName, > + "eng" > +}; > + > +/** > + EFI Component Name 2 Protocol declaration > +**/ > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 =3D { > + (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[] =3D { > + {"eng;en", L"AX88772 Ethernet Driver"}, > + {NULL, NULL} > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 3066 or ISO 639-2 language code f= ormat. > + @param [out] ppDriverName A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 =3D LookupUnicodeString2 ( > + pLanguage, > + pThis->SupportedLanguages, > + mDriverNameTable, > + ppDriverName, > + (BOOLEAN)(pThis =3D=3D &gComponentName) > + ); > + DBG_EXIT_HEX ( Status ); > + return Status; > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + @param [in] ChildHandle The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + @param [in] pLanguage A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 3066 or ISO 639-2 language code form= at. > + @param [out] ppControllerName A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 =3D L"AX88772 10/100 Ethernet"; > + Status =3D EFI_SUCCESS; > + > + // > + // Return the operation status > + // > + DBG_EXIT_HEX ( Status ); > + return Status; > +} > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c > new file mode 100644 > index 0000000000..5bcde4b211 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/DriverBinding.c > @@ -0,0 +1,507 @@ > +/** @file > + Implement the driver binding protocol for Asix AX88772 Ethernet driver= . > + > + Copyright (c) 2011-2013, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 =3D 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 =3D pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device ); > + if (!EFI_ERROR ( Status )) { > + > + // > + // Validate the adapter > + // > + if (( VENDOR_ID !=3D Device.IdVendor ) > + || ( PRODUCT_ID !=3D Device.IdProduct )) { > + Status =3D 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 protoc= ols. > + Initialize PXE structures, create a copy of the Controller Device Path= with > the > + NIC's MAC address appended to it, install the NetworkInterfaceIdentifi= er > 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 =3D sizeof ( *pNicDevice ); > + Status =3D 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 =3D DEV_SIGNATURE; > + > + // > + // Connect to the USB I/O protocol > + // > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + (VOID **) &pNicDevice->pUsbIo, > + pThis->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + > + if ( !EFI_ERROR ( Status )) { > + // > + // Allocate the necessary events > + // > + Status =3D 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 =3D Controller; > + SN_Setup ( pNicDevice ); > + > + // > + // Start the timer > + // > + Status =3D gBS->SetTimer ( pNicDevice->Timer, > + TimerPeriodic, > + TIMER_MSEC ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Install both the simple network and device path protocols. > + // > + Status =3D 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 dev= ice. > + > +**/ > +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 =3D 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 !=3D 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 =3D { > + 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 =3D 0; > + pHandle =3D NULL; > + Status =3D gBS->LocateHandle ( > + ByProtocol, > + &gEfiCallerIdGuid, > + NULL, > + &BufferSize, > + NULL ); > + if ( EFI_BUFFER_TOO_SMALL =3D=3D Status ) { > + for ( ; ; ) { > + // > + // One or more block IO devices are present > + // > + Status =3D 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 =3D 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 =3D BufferSize / sizeof ( pHandle[ 0 ]); > + for ( Index =3D 0; Max > Index; Index++ ) { > + Status =3D 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 =3D=3D Status ) { > + // > + // No devices were found > + // > + Status =3D EFI_SUCCESS; > + } > + } > + > + // > + // Free the handle array > + // > + if ( NULL !=3D 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 =3D 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/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork > .c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork > .c > new file mode 100644 > index 0000000000..0105d04f5d > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/SimpleNetwork > .c > @@ -0,0 +1,1503 @@ > +/** @file > + Provides the Simple Network functions. > + > + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pMode =3D pSimpleNetwork->Mode; > + Status =3D Ax88772MacAddressSet ( pNicDevice, > + &pMode->CurrentAddress.Addr[0]); > + if ( !EFI_ERROR ( Status )) { > + // > + // Clear the multicast hash table > + // > + Ax88772MulticastClear ( pNicDevice ); > + > + // > + // Load the multicast hash table > + // > + if ( 0 !=3D ( pMode->ReceiveFilterSetting & > EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) { > + for ( Index =3D 0; > + ( !EFI_ERROR ( Status )) && ( Index < pMode->MCastFilterCoun= t ); > + Index++ ) { > + // > + // Enable the next multicast address > + // > + Ax88772MulticastSet ( pNicDevice, > + &pMode->MCastFilter[ Index ].Addr[0]); > + } > + } > + > + // > + // Enable the receiver > + // > + if ( !EFI_ERROR ( Status )) { > + Status =3D Ax88772RxControl ( pNicDevice, pMode->ReceiveFilterSett= ing ); > + } > + } > + > + // > + // 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 wi= ll not be read from > + the device. If this is not NULL, the in= terrupt status will > + be read from teh device. When the inter= rupt status is > read, > + it will also be cleared. Clearing the t= ransmit interrupt > + does not empty the recycled transmit buf= fer array. > + @param [out] ppTxBuf Recycled transmit buffer address. The > network interface will > + not transmit if its internal recycled tr= ansmit buffer array is > + full. Reading the transmit buffer does = not clear the > transmit > + interrupt. If this is NULL, then the tr= ansmit buffer status > + will not be read. If there are not tran= smit buffers to > recycle > + and TxBuf is not NULL, *TxBuf will be se= t 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Return the transmit buffer > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + if (( NULL !=3D ppTxBuf ) && ( NULL !=3D pNicDevice->pTxBuffer )) { > + *ppTxBuf =3D pNicDevice->pTxBuffer; > + pNicDevice->pTxBuffer =3D NULL; > + } > + > + // > + // Determine if interface is running > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStopped !=3D pMode->State ) { > + // > + // Synchronize with Ax88772Timer > + // > + VERIFY_TPL ( TPL_AX88772 ); > + TplPrevious =3D gBS->RaiseTPL ( TPL_AX88772 ); > + > + // > + // Update the link status > + // > + bLinkIdle =3D pNicDevice->bLinkIdle; > + pNicDevice->bLinkIdle =3D TRUE; > + Ax88772Rx ( pNicDevice, bLinkIdle ); > + pMode->MediaPresent =3D pNicDevice->bLinkUp; > + > + // > + // Release the synchronization with Ax88772Timer > + // > + gBS->RestoreTPL ( TplPrevious ); > + > + // > + // Return the interrupt status > + // > + if ( NULL !=3D pInterruptStatus ) { > + *pInterruptStatus =3D 0; > + } > + Status =3D EFI_SUCCESS; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + > + // > + // Return the operation status > + // > + DBG_EXIT_STATUS ( Status ); > + return Status; > +} > + > + > +/** > + Resets the network adapter and allocates the transmit and receive buff= ers > + required by the network interface; optionally, also requests allocatio= n 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 buff= er > allocation > + @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buf= fer > allocation > + > + @retval EFI_SUCCESS This operation was successful. > + @retval EFI_NOT_STARTED The network interface was not started. > + @retval EFI_OUT_OF_RESOURCES 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Determine if the interface is already started > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStarted =3D=3D pMode->State ) { > + if (( 0 =3D=3D ExtraRxBufferSize ) && ( 0 =3D=3D ExtraTxBufferSize= )) { > + // > + // Start the adapter > + // > + Status =3D SN_Reset ( pSimpleNetwork, FALSE ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Update the network state > + // > + pMode->State =3D EfiSimpleNetworkInitialized; > + } > + } > + else { > + Status =3D EFI_UNSUPPORTED; > + } > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 c= onverted > 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 =3D 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 writ= e > 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 fro= m the > NVRAM device. > + This must also be a multiple of NvramAcc= essSize. > + @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 =3D 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 netwo= rk > + 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 pac= ket > + will be placed in Buffer, and BufferSize will be udpated with the actu= al > + size of the packet. In addition, if SrcAddr, DestAddr, and Protocol a= re > + not NULL, then these values will be extracted from the media header an= d > + 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 mus= t not be NULL. > + @param [out] pBufferSize The size, in bytes, of the entire packet > (media header and > + data) to be transmitted through the netw= ork interface. > + @param [out] pBuffer A pointer to the packet (media header > followed by data) to > + to be transmitted. This parameter can n= ot be NULL. If > + HeaderSize is zero, then the media heade= r 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 HeaderSiz= e is > zero, then > + this parameter is ignored. If HeaderSiz= e is nonzero and > + SrcAddr is NULL, then SimpleNetwork->Mod= e- > >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 HeaderS= ize 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // The interface must be running > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Synchronize with Ax88772Timer > + // > + VERIFY_TPL ( TPL_AX88772 ); > + TplPrevious =3D gBS->RaiseTPL ( TPL_AX88772 ); > + > + // > + // Update the link status > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + Ax88772Rx ( pNicDevice, FALSE ); > + pMode->MediaPresent =3D pNicDevice->bLinkUp; > + if ( pMode->MediaPresent ) { > + // > + // Attempt to receive a packet > + // > + pRxPacket =3D pNicDevice->pRxHead; > + if ( NULL !=3D pRxPacket ) { > + pNicDevice->pRxHead =3D pRxPacket->pNext; > + if ( NULL =3D=3D pNicDevice->pRxHead ) { > + pNicDevice->pRxTail =3D NULL; > + } > + > + // > + // Copy the received packet into the receive buffer > + // > + *pBufferSize =3D pRxPacket->Length; > + CopyMem ( pBuffer, &pRxPacket->Data[0], pRxPacket->Length ); > + pHeader =3D (ETHERNET_HEADER *) &pRxPacket->Data[0]; > + if ( NULL !=3D pHeaderSize ) { > + *pHeaderSize =3D sizeof ( *pHeader ); > + } > + if ( NULL !=3D pDestAddr ) { > + CopyMem ( pDestAddr, &pHeader->dest_addr, > PXE_HWADDR_LEN_ETHER ); > + } > + if ( NULL !=3D pSrcAddr ) { > + CopyMem ( pSrcAddr, &pHeader->src_addr, > PXE_HWADDR_LEN_ETHER ); > + } > + if ( NULL !=3D pProtocol ) { > + Type =3D pHeader->type; > + Type =3D (UINT16)(( Type >> 8 ) | ( Type << 8 )); > + *pProtocol =3D Type; > + } > + Status =3D EFI_SUCCESS; > + } > + else { > + // > + // No receive packets available > + // > + Status =3D EFI_NOT_READY; > + } > + } > + else { > + // > + // Link no up > + // > + Status =3D EFI_NOT_READY; > + } > + > + // > + // Release the synchronization with Ax88772Timer > + // > + gBS->RestoreTPL ( TplPrevious ); > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 hardwar= e > + a more liberal setting is selected. > + > + If the same bits are set in the Enable and Disable parameters, then th= e 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 filt= ers > + instead. The receiving software is responsible for discarding any ext= ra > + 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 receiv= e > + 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 multicas= t > + 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 T= RUE. > + @param [in] bResetMCastFilter Set to TRUE to reset the contents of the > multicast receive > + filters on the network interface to thei= r 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 rec= eive > filter HW MAC > + addresses. This list will replace any e= xisting multicast > + HW MAC address list. This field is opti= onal 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 =3D EFI_INVALID_PARAMETER; > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + pMode =3D pSimpleNetwork->Mode; > + > + // > + // Update the multicast list if necessary > + // > + if ( !bResetMCastFilter ) { > + if ( 0 !=3D MCastFilterCnt ) { > + if (( MAX_MCAST_FILTER_CNT >=3D MCastFilterCnt ) > + && ( NULL !=3D pMCastFilter )) { > + // > + // Verify the multicast addresses > + // > + pMulticastAddress =3D pMCastFilter; > + pTableEnd =3D pMulticastAddress + MCastFilterCnt; > + while ( pTableEnd > pMulticastAddress ) { > + // > + // The first digit of the multicast address must have the LS= B set > + // > + if ( 0 =3D=3D ( pMulticastAddress->Addr[0] & 1 )) { > + // > + // Invalid multicast address > + // > + break; > + } > + pMulticastAddress +=3D 1; > + } > + if ( pTableEnd =3D=3D pMulticastAddress ) { > + // > + // Update the multicast filter list. > + // > + CopyMem (&pMode->MCastFilter[0], > + pMCastFilter, > + MCastFilterCnt * sizeof ( *pMCastFilter )); > + Status =3D EFI_SUCCESS; > + } > + } > + } > + else { > + Status =3D EFI_SUCCESS; > + } > + } > + else { > + // > + // No multicast address list is specified > + // > + MCastFilterCnt =3D 0; > + Status =3D EFI_SUCCESS; > + } > + if ( !EFI_ERROR ( Status )) { > + // > + // The parameters are valid! > + // > + pMode->ReceiveFilterSetting |=3D Enable; > + pMode->ReceiveFilterSetting &=3D ~Disable; > + pMode->MCastFilterCount =3D (UINT32)MCastFilterCnt; > + > + // > + // Update the receive filters in the adapter > + // > + Status =3D 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 perfo= rm > 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Synchronize with Ax88772Timer > + // > + VERIFY_TPL ( TPL_AX88772 ); > + TplPrevious =3D gBS->RaiseTPL ( TPL_AX88772 ); > + > + // > + // Update the device state > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pNicDevice->bComplete =3D FALSE; > + pNicDevice->bLinkUp =3D FALSE; > + > + pMode =3D pSimpleNetwork->Mode; > + pMode->MediaPresent =3D FALSE; > + > + // > + // Discard any received packets > + // > + while ( NULL !=3D pNicDevice->pRxHead ) { > + // > + // Remove the packet from the received packet list > + // > + pRxPacket =3D pNicDevice->pRxHead; > + pNicDevice->pRxHead =3D pRxPacket->pNext; > + > + // > + // Queue the packet to the free list > + // > + pRxPacket->pNext =3D pNicDevice->pRxFree; > + pNicDevice->pRxFree =3D pRxPacket; > + } > + pNicDevice->pRxTail =3D NULL; > + > + // > + // Reset the device > + // > + Status =3D Ax88772Reset ( pNicDevice ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Update the receive filters in the adapter > + // > + Status =3D ReceiveFilterUpdate ( pSimpleNetwork ); > + > + // > + // Try to get a connection to the network > + // > + if ( !EFI_ERROR ( Status )) { > + // > + // Start the autonegotiation > + // > + Status =3D Ax88772NegotiateLinkStart ( pNicDevice ); > + } > + } > + > + // > + // Release the synchronization with Ax88772Timer > + // > + gBS->RestoreTPL ( TplPrevious ); > + } > + else { > + Status =3D 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 =3D &pNicDevice->SimpleNetwork; > + pSimpleNetwork->Revision =3D > EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; > + pSimpleNetwork->Start =3D (EFI_SIMPLE_NETWORK_START)SN_Start; > + pSimpleNetwork->Stop =3D (EFI_SIMPLE_NETWORK_STOP)SN_Stop; > + pSimpleNetwork->Initialize =3D > (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize; > + pSimpleNetwork->Reset =3D (EFI_SIMPLE_NETWORK_RESET)SN_Reset; > + pSimpleNetwork->Shutdown =3D > (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown; > + pSimpleNetwork->ReceiveFilters =3D > (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters; > + pSimpleNetwork->StationAddress =3D > (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress; > + pSimpleNetwork->Statistics =3D > (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics; > + pSimpleNetwork->MCastIpToMac =3D > (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC; > + pSimpleNetwork->NvData =3D (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData; > + pSimpleNetwork->GetStatus =3D > (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus; > + pSimpleNetwork->Transmit =3D > (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit; > + pSimpleNetwork->Receive =3D (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive; > + pSimpleNetwork->WaitForPacket =3D NULL; > + pMode =3D &pNicDevice->SimpleNetworkData; > + pSimpleNetwork->Mode =3D pMode; > + > + pMode->State =3D EfiSimpleNetworkStopped; > + pMode->HwAddressSize =3D PXE_HWADDR_LEN_ETHER; > + pMode->MediaHeaderSize =3D sizeof ( ETHERNET_HEADER ); > + pMode->MaxPacketSize =3D MAX_ETHERNET_PKT_SIZE; > + pMode->NvRamSize =3D 0; > + pMode->NvRamAccessSize =3D 0; > + pMode->ReceiveFilterMask =3D 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 =3D EFI_SIMPLE_NETWORK_RECEIVE_UNICAST > + | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; > + pMode->MaxMCastFilterCount =3D MAX_MCAST_FILTER_CNT; > + pMode->MCastFilterCount =3D 0; > + SetMem ( &pMode->BroadcastAddress, > + PXE_HWADDR_LEN_ETHER, > + 0xff ); > + pMode->IfType =3D EfiNetworkInterfaceUndi; > + pMode->MacAddressChangeable =3D TRUE; > + pMode->MultipleTxSupported =3D TRUE; > + pMode->MediaPresentSupported =3D TRUE; > + pMode->MediaPresent =3D FALSE; > + > + // > + // Read the MAC address > + // > + pNicDevice->PhyId =3D PHY_ID_INTERNAL; > + pNicDevice->b100Mbps =3D TRUE; > + pNicDevice->bFullDuplex =3D TRUE; > + > + Status =3D 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 =3D 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 =3D EFI_INVALID_PARAMETER; > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStopped =3D=3D pMode->State ) { > + // > + // Initialize the mode structure > + // NVRAM access is not supported > + // > + ZeroMem ( pMode, sizeof ( *pMode )); > + > + pMode->State =3D EfiSimpleNetworkStarted; > + pMode->HwAddressSize =3D PXE_HWADDR_LEN_ETHER; > + pMode->MediaHeaderSize =3D sizeof ( ETHERNET_HEADER ); > + pMode->MaxPacketSize =3D MAX_ETHERNET_PKT_SIZE; > + pMode->ReceiveFilterMask =3D 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 =3D > EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; > + pMode->MaxMCastFilterCount =3D MAX_MCAST_FILTER_CNT; > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + Status =3D Ax88772MacAddressGet ( pNicDevice, &pMode- > >PermanentAddress.Addr[0]); > + CopyMem ( &pMode->CurrentAddress, > + &pMode->PermanentAddress, > + sizeof ( pMode->CurrentAddress )); > + pMode->BroadcastAddress.Addr[0] =3D 0xff; > + pMode->BroadcastAddress.Addr[1] =3D 0xff; > + pMode->BroadcastAddress.Addr[2] =3D 0xff; > + pMode->BroadcastAddress.Addr[3] =3D 0xff; > + pMode->BroadcastAddress.Addr[4] =3D 0xff; > + pMode->BroadcastAddress.Addr[5] =3D 0xff; > + pMode->IfType =3D 1; > + pMode->MacAddressChangeable =3D TRUE; > + pMode->MultipleTxSupported =3D TRUE; > + pMode->MediaPresentSupported =3D TRUE; > + pMode->MediaPresent =3D FALSE; > + } > + else { > + Status =3D 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 FALS= E > + then the current station address is changed to the address specified b= y > + 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 t= o the > + network interface's permanent address. > + @param [in] pNew New station address to be used for the n= etwork > + 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 !=3D pSimpleNetwork ) > + && ( NULL !=3D pSimpleNetwork->Mode ) > + && (( !bReset ) || ( bReset && ( NULL !=3D pNew )))) { > + // > + // Verify that the adapter is already started > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStarted =3D=3D 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 =3D Ax88772MacAddressSet ( pNicDevice, &pMode- > >CurrentAddress.Addr[0]); > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 tab= le 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 =3D 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Determine if the interface is started > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStopped !=3D pMode->State ) { > + if ( EfiSimpleNetworkStarted =3D=3D pMode->State ) { > + // > + // Release the resources acquired in SN_Start > + // > + > + // > + // Mark the adapter as stopped > + // > + pMode->State =3D EfiSimpleNetworkStopped; > + Status =3D EFI_SUCCESS; > + } > + else { > + Status =3D EFI_UNSUPPORTED; > + } > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 an= d > 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Determine if the interface is already started > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Stop the adapter > + // > + RxFilter =3D pMode->ReceiveFilterSetting; > + pMode->ReceiveFilterSetting =3D 0; > + Status =3D SN_Reset ( pSimpleNetwork, FALSE ); > + pMode->ReceiveFilterSetting =3D RxFilter; > + if ( !EFI_ERROR ( Status )) { > + // > + // Release the resources acquired by SN_Initialize > + // > + > + // > + // Update the network state > + // > + pMode->State =3D EfiSimpleNetworkStarted; > + } > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 mus= t not be NULL. > + @param [in] BufferSize The size, in bytes, of the entire packet= (media > header and > + data) to be transmitted through the netw= ork interface. > + @param [in] pBuffer A pointer to the packet (media header fo= llowed > by data) to > + to be transmitted. This parameter can n= ot be NULL. If > + HeaderSize is zero, then the media heade= r 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 HeaderSiz= e is > zero, then > + this parameter is ignored. If HeaderSiz= e is nonzero and > + SrcAddr is NULL, then SimpleNetwork->Mod= e- > >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 HeaderS= ize 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 acc= ept > 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // The interface must be running > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Synchronize with Ax88772Timer > + // > + VERIFY_TPL ( TPL_AX88772 ); > + TplPrevious =3D gBS->RaiseTPL ( TPL_AX88772 ); > + > + // > + // Update the link status > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + > + // > + //No need to call receive to receive packet > + // > + //Ax88772Rx ( pNicDevice, FALSE ); > + pMode->MediaPresent =3D 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 =3D (UINT16) BufferSize; > + > + // > + // Transmit the packet > + // > + pHeader =3D (ETHERNET_HEADER *) &Packet.Data[0]; > + if ( 0 !=3D HeaderSize ) { > + if ( NULL !=3D pDestAddr ) { > + CopyMem ( &pHeader->dest_addr, pDestAddr, > PXE_HWADDR_LEN_ETHER ); > + } > + if ( NULL !=3D 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 !=3D pProtocol ) { > + Type =3D *pProtocol; > + } > + else { > + Type =3D Packet.Length; > + } > + Type =3D (UINT16)(( Type >> 8 ) | ( Type << 8 )); > + pHeader->type =3D Type; > + } > + if ( Packet.Length < MIN_ETHERNET_PKT_SIZE ) { > + Packet.Length =3D 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-%02= x- > %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 =3D ~Packet.Length; > + TransferLength =3D sizeof ( Packet.Length ) > + + sizeof ( Packet.LengthBar ) > + + Packet.Length; > + > + // > + // Work around USB bus driver bug where a timeout set by receiv= e > + // succeeds but the timeout expires immediately after, causing = the > + // transmit operation to timeout. > + // > + pUsbIo =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbBulkTransfer ( pUsbIo, > + BULK_OUT_ENDPOINT, > + &Packet.Length, > + &TransferLength, > + 0xfffffffe, > + &TransferStatus ); > + if ( !EFI_ERROR ( Status )) { > + Status =3D TransferStatus; > + } > + if (( !EFI_ERROR ( Status )) > + && ( TransferLength !=3D (UINTN)( Packet.Length + 4 ))) { > + Status =3D EFI_WARN_WRITE_FAILURE; > + } > + if ( EFI_SUCCESS =3D=3D Status ) { > + pNicDevice->pTxBuffer =3D 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 =3D=3D Status ) { > + SN_Reset ( pSimpleNetwork, FALSE ); > + } > + } > + } > + else { > + // > + // No packets available. > + // > + Status =3D EFI_NOT_READY; > + } > + } > + else { > + Status =3D 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 =3D EFI_INVALID_PARAMETER; > + } > + > + // > + // Return the operation status > + // > + DBG_EXIT_STATUS ( Status ); > + return Status; > +} > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c > new file mode 100644 > index 0000000000..12684a6bd1 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.c > @@ -0,0 +1,875 @@ > +/** @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 availa= ble. > + > + Copyright (c) 2011, Intel Corporation. All rights reserved. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Ax88772.h" > + > + > +/** > + Compute the CRC > + > + @param [in] pMacAddress Address of a six byte buffer to containin= g 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 =3D -1; > + pEnd =3D &pMacAddress[ PXE_HWADDR_LEN_ETHER ]; > + while ( pEnd > pMacAddress ) { > + Data =3D *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 =3D 0; 8 > BitNumber; BitNumber++ ) { > + Carry =3D (( Crc >> 31 ) & 1 ) ^ ( Data & 1 ); > + Crc <<=3D 1; > + if ( 0 !=3D Carry ) { > + Crc ^=3D 0x04c11db7; > + } > + Data >>=3D 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 =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MAC_ADDRESS_READ; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D PXE_HWADDR_LEN_ETHER; > + > + // > + // Read the PHY register > + // > + Status =3D 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 containin= g 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MAC_ADDRESS_WRITE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D PXE_HWADDR_LEN_ETHER; > + > + // > + // Read the PHY register > + // > + Status =3D 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 =3D 0; > + // > + // Clear the multicast hash table > + // > + for ( i =3D 0 ; i < 8 ; i ++ ) > + pNicDevice->MulticastHash[0] =3D 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 containin= g the > MAC address. > + > +**/ > +VOID > +Ax88772MulticastSet ( > + IN NIC_DEVICE * pNicDevice, > + IN UINT8 * pMacAddress > + ) > +{ > + UINT32 Crc; > + > + // > + // Compute the CRC on the destination address > + // > + Crc =3D Ax88772Crc ( pMacAddress ) >> 26; > + > + // > + // Set the bit corresponding to the destination address > + // > + pNicDevice->MulticastHash [ Crc >> 3 ] |=3D ( 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 =3D 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 =3D BMCR_AUTONEGOTIATION_ENABLE > + | BMCR_RESTART_AUTONEGOTIATION; > + if ( pNicDevice->b100Mbps ) { > + Control |=3D BMCR_100MBPS; > + } > + if ( pNicDevice->bFullDuplex ) { > + Control |=3D BMCR_FULL_DUPLEX; > + } > + Status =3D Ax88772PhyWrite ( pNicDevice, PHY_BMCR, Control ); > + } > + > + if (!EFI_ERROR(Status)) { > + i =3D 0; > + do { > + > + if (pNicDevice->bComplete && pNicDevice->bLinkUp) { > + pNicDevice->SimpleNetwork.Mode->MediaPresent > + =3D pNicDevice->bLinkUp & pNicDevice->bComplete; > + break; > + } > + else { > + gBS->Stall(AUTONEG_DELAY); > + Status =3D 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 w= as > polled > + @param [out] pbComplete Address of boolean to receive complate > status. > + @param [out] pbLinkUp Address of boolean to receive link status= , > TRUE=3Dup. > + @param [out] pbHiSpeed Address of boolean to receive link speed, > TRUE=3D100Mbps. > + @param [out] pbFullDuplex Address of boolean to receive link duplex= , > TRUE=3Dfull. > + > + @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 =3D FALSE; > + > + // > + // Get the link status > + // > + Status =3D Ax88772PhyRead ( pNicDevice, > + PHY_BMSR, > + &PhyData ); > + > + if ( !EFI_ERROR ( Status )) { > + *pbLinkUp =3D (BOOLEAN)( 0 !=3D ( PhyData & BMSR_LINKST )); > + if ( 0 =3D=3D *pbLinkUp ) { > + DEBUG (( EFI_D_INFO, "Link Down\n" )); > + } > + else { > + *pbComplete =3D (BOOLEAN)( 0 !=3D ( PhyData & 0x20 )); > + if ( 0 =3D=3D *pbComplete ) { > + DEBUG (( EFI_D_INFO, "Autoneg is not yet Complete\n" )); > + } > + else { > + Status =3D Ax88772PhyRead ( pNicDevice, > + PHY_ANLPAR, > + &PhyData ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Autonegotiation is complete > + // Determine the link speed. > + // > + *pbHiSpeed =3D (BOOLEAN)( 0 !=3D ( PhyData & ( AN_TX_FDX | > AN_TX_HDX ))); > + > + // > + // Determine the link duplex. > + // > + Mask =3D ( *pbHiSpeed ) ? AN_TX_FDX : AN_10_FDX; > + *pbFullDuplex =3D (BOOLEAN)( 0 !=3D ( 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_SOFTWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Read the PHY register address. > + // > + SetupMsg.RequestType =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_REG_READ; > + SetupMsg.Value =3D pNicDevice->PhyId; > + SetupMsg.Index =3D RegisterAddress; > + SetupMsg.Length =3D sizeof ( *pPhyData ); > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + pPhyData ); > + if ( !EFI_ERROR ( Status )) { > + > + // > + // Release the PHY to the hardware > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_HARDWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 re= gister > 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 =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_SOFTWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Write the PHY register > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_REG_WRITE; > + SetupMsg.Value =3D pNicDevice->PhyId; > + SetupMsg.Index =3D RegisterAddress; > + SetupMsg.Length =3D sizeof ( PhyData ); > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + &PhyData ); > + if ( !EFI_ERROR ( Status )) { > + > + // > + // Release the PHY to the hardware > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_HARDWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_ACCESS_HARDWARE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_SELECT; > + SetupMsg.Value =3D SPHY_PSEL; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RESET; > + SetupMsg.Value =3D SRR_IPRL ; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RESET; > + SetupMsg.Value =3D SRR_IPPD | SRR_IPRL ; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + gBS->Stall ( 200000 ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RESET; > + SetupMsg.Value =3D SRR_IPRL ; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + gBS->Stall ( 200000 ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RESET; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_PHY_SELECT; > + SetupMsg.Value =3D SPHY_PSEL; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RESET; > + SetupMsg.Value =3D SRR_IPRL | SRR_BZ | SRR_BZTYPE; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RX_CONTROL_WRITE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + > + if (EFI_ERROR(Status)) goto err; > + > + if (pNicDevice->Flags !=3D FLAG_TYPE_AX88772) { > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RXQTC; > + SetupMsg.Value =3D 0x8000; > + SetupMsg.Index =3D 0x8001; > + SetupMsg.Length =3D 0; > + Status =3D 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 =3D pNicDevice->pUsbIo; > + Status =3D 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 !=3D RxFilter ) { > + // > + // Enable the receiver > + // > + SetupMsg.RequestType =3D USB_ENDPOINT_DIR_IN > + | USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MEDIUM_STATUS_READ; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D sizeof ( MediumStatus ); > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + &MediumStatus ); > + if ( !EFI_ERROR ( Status )) { > + if ( 0 =3D=3D ( MediumStatus & MS_RE )) { > + MediumStatus |=3D MS_RE | MS_ONE; > + > + if ( pNicDevice->bFullDuplex ) > + MediumStatus |=3D MS_TFC | MS_RFC | MS_FD; > + else > + MediumStatus &=3D ~(MS_TFC | MS_RFC | MS_FD); > + > + if ( pNicDevice->b100Mbps ) > + MediumStatus |=3D MS_PS; > + else > + MediumStatus &=3D ~MS_PS; > + > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MEDIUM_STATUS_WRITE; > + SetupMsg.Value =3D MediumStatus; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D 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 =3D RXC_SO | RXC_RH1M; > + // > + // Enable multicast if requested > + // > + if ( 0 !=3D ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) { > + RxControl |=3D RXC_AM; > + // > + // Update the multicast hash table > + // > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_MULTICAST_HASH_WRITE; > + SetupMsg.Value =3D 0; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D sizeof ( pNicDevice ->MulticastHash ); > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + &pNicDevice->MulticastHash ); > + } > + // > + // Enable all multicast if requested > + // > + if ( 0 !=3D ( RxFilter & > EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST )) { > + RxControl |=3D RXC_AMALL; > + } > + > + // > + // Enable broadcast if requested > + // > + if ( 0 !=3D ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST )) { > + RxControl |=3D RXC_AB; > + } > + > + // > + // Enable promiscuous mode if requested > + // > + if ( 0 !=3D ( RxFilter & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS )) { > + RxControl |=3D RXC_PRO; > + } > + > + // > + // Update the receiver control > + // > + if (pNicDevice->CurRxControl !=3D RxControl) { > + SetupMsg.RequestType =3D USB_REQ_TYPE_VENDOR > + | USB_TARGET_DEVICE; > + SetupMsg.Request =3D CMD_RX_CONTROL_WRITE; > + SetupMsg.Value =3D RxControl; > + SetupMsg.Index =3D 0; > + SetupMsg.Length =3D 0; > + Status =3D Ax88772UsbCommand ( pNicDevice, > + &SetupMsg, > + NULL ); > + if ( !EFI_ERROR ( Status )) { > + pNicDevice->CurRxControl =3D 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 =3D EfiUsbNoData; > + if ( 0 !=3D pRequest->Length ) { > + Direction =3D ( 0 !=3D ( pRequest->RequestType & USB_ENDPOINT_DIR_IN= )) > + ? EfiUsbDataIn : EfiUsbDataOut; > + } > + > + // > + // Issue the command > + // > + pUsbIo =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbControlTransfer ( pUsbIo, > + pRequest, > + Direction, > + USB_BUS_TIMEOUT, > + pBuffer, > + pRequest->Length, > + &CmdStatus ); > + // > + // Determine the operation status > + // > + if ( !EFI_ERROR ( Status )) { > + Status =3D CmdStatus; > + } > + else { > + // > + // Only use status values associated with the Simple Network protoco= l > + // > + if ( EFI_TIMEOUT =3D=3D Status ) { > + Status =3D EFI_DEVICE_ERROR; > + } > + } > + return Status; > +} > + > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h > new file mode 100644 > index 0000000000..365929489b > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772.h > @@ -0,0 +1,1026 @@ > +/** @file > + Definitions for ASIX AX88772 Ethernet adapter. > + > + Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _AX88772_H_ > +#define _AX88772_H_ > + > +#include > + > +#include > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#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 specif= ics. > */ > +#define DBG_ENTER() DEBUG (( 0xffffffff, "Entering " __FUNCT= ION__ > "\n" )) ///< Display routine entry > +#define DBG_EXIT() DEBUG (( 0xffffffff, "Exiting " __FUNCTI= ON__ > "\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 =3D=3D Status) ? L"FALSE" : L"TRU= E" )) > ///< 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 decima= l > value > +#define DBG_EXIT_HEX(Status) ///< Display routine exit with hex va= lue > +#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) !=3D 0) ///< Return TRUE/FALSE for IN direction > +#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) > =3D=3D 0) ///< Return TRUE/FALSE for OUT direction > +#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BI= T1)) > =3D=3D USB_ENDPOINT_BULK) ///< Return TRUE/FALSE for BULK type > +#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | > BIT1)) =3D=3D 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 v= alues > +#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 t= he 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 >=3D 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 =3D 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 <=3D 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') ///< Signatur= e of > data structures in memory > + > +#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 addres= s hash > table > +#define RXC_AP 0x0020 ///< Accept physical address from Mul= ticast > 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=3D100, 0=3D10 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=3DAuto select, 0=3DManual sele= ct > + > +// > +// Software Reset register > +// > + > +#define SRR_RR 0x01 ///< Clear receive frame length error > +#define SRR_RT 0x02 ///< Clear transmit frame length erro= r > +#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, V= alue: > 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 ad= vertisement > register > +#define PHY_ANLPAR 5 ///< Autonegotiation li= nk parter > ability register > +#define PHY_ANER 6 ///< Autonegotiation ex= pansion > register > + > +// BMCR - Register 0 > + > +#define BMCR_RESET 0x8000 ///< 1 =3D Reset the PH= Y, bit clears > after reset > +#define BMCR_LOOPBACK 0x4000 ///< 1 =3D Loopback ena= bled > +#define BMCR_100MBPS 0x2000 ///< 100 Mbits/Sec > +#define BMCR_10MBPS 0 ///< 10 Mbits/Sec > +#define BMCR_AUTONEGOTIATION_ENABLE 0x1000 ///< 1 =3D Enable > autonegotiation > +#define BMCR_POWER_DOWN 0x0800 ///< 1 =3D Power down > +#define BMCR_ISOLATE 0x0400 ///< 0 =3D Isolate PHY > +#define BMCR_RESTART_AUTONEGOTIATION 0x0200 ///< 1 =3D Restart > autonegotiation > +#define BMCR_FULL_DUPLEX 0x0100 ///< Full duplex operat= ion > +#define BMCR_HALF_DUPLEX 0 ///< Half duplex operat= ion > +#define BMCR_COLLISION_TEST 0x0080 ///< 1 =3D Collision te= st > enabled > + > +// BSMR - Register 1 > + > +#define BMSR_100BASET4 0x8000 ///< 1 =3D 100BASE-T4 m= ode > +#define BMSR_100BASETX_FDX 0x4000 ///< 1 =3D 100BASE-TX f= ull > duplex > +#define BMSR_100BASETX_HDX 0x2000 ///< 1 =3D 100BASE-TX h= alf > duplex > +#define BMSR_10BASET_FDX 0x1000 ///< 1 =3D 10BASE-T ful= l duplex > +#define BMSR_10BASET_HDX 0x0800 ///< 1 =3D 10BASE-T hal= f > duplex > +#define BMSR_MF 0x0040 ///< 1 =3D PHY accepts = frames with > preamble suppressed > +#define BMSR_AUTONEG_CMPLT 0x0020 ///< 1 =3D Autonegotiat= ion > complete > +#define BMSR_RF 0x0010 ///< 1 =3D Remote fault > +#define BMSR_AUTONEG 0x0008 ///< 1 =3D Able to perf= orm > autonegotiation > +#define BMSR_LINKST 0x0004 ///< 1 =3D Link up > +#define BMSR_JABBER_DETECT 0x0002 ///< 1 =3D jabber condi= tion > detected > +#define BMSR_EXTENDED_CAPABILITY 0x0001 ///< 1 =3D Extended > register capable > + > +// ANAR and ANLPAR Registers 4, 5 > + > +#define AN_NP 0x8000 ///< 1 =3D Next page av= ailable > +#define AN_ACK 0x4000 ///< 1 =3D Link partner= acknowledged > +#define AN_RF 0x2000 ///< 1 =3D Remote fault= indicated by > link partner > +#define AN_FCS 0x0400 ///< 1 =3D Flow control= ability > +#define AN_T4 0x0200 ///< 1 =3D 100BASE-T4 s= upport > +#define AN_TX_FDX 0x0100 ///< 1 =3D 100BASE-TX F= ull duplex > +#define AN_TX_HDX 0x0080 ///< 1 =3D 100BASE-TX s= upport > +#define AN_10_FDX 0x0040 ///< 1 =3D 10BASE-T Ful= l duplex > +#define AN_10_HDX 0x0020 ///< 1 =3D 10BASE-T sup= port > +#define AN_CSMA_CD 0x0001 ///< 1 =3D IEEE 802.3 C= SMA/CD > support > + > +// asix_flags defines > +#define FLAG_NONE 0 > +#define FLAG_TYPE_AX88172 BIT0 > +#define FLAG_TYPE_AX88772 BIT1 > +#define FLAG_TYPE_AX88772B BIT2 > +#define FLAG_EEPROM_MAC BIT3 // initial mac address in eeprom > + > +//----------------------------------------------------------------------= -------- > +// Data Types > +//----------------------------------------------------------------------= -------- > + > +typedef struct { > + UINT16 VendorId; > + UINT16 ProductId; > + INT32 Flags; > +}ASIX_DONGLE; > + > +/** > + 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 =3D 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 st= atus > 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; > + > + INT32 Flags; > + > +} 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 perfo= rm > 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 FALS= E > + then the current station address is changed to the address specified b= y > + 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 t= o the > + network interface's permanent address. > + @param [in] pNew New station address to be used for the n= etwork > + 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 tab= le 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 an= d > 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 mus= t not be NULL. > + @param [in] BufferSize The size, in bytes, of the entire packet= (media > header and > + data) to be transmitted through the netw= ork interface. > + @param [in] pBuffer A pointer to the packet (media header fo= llowed > by data) to > + to be transmitted. This parameter can n= ot be NULL. If > + HeaderSize is zero, then the media heade= r 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 HeaderSiz= e is > zero, then > + this parameter is ignored. If HeaderSiz= e is nonzero and > + SrcAddr is NULL, then SimpleNetwork->Mod= e- > >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 HeaderS= ize 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 acc= ept > 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 containin= g 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 containin= g 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 w= as > polled > + @param [out] pbComplete Address of boolean to receive complate > status. > + @param [out] pbLinkUp Address of boolean to receive link status= , > TRUE=3Dup. > + @param [out] pbHiSpeed Address of boolean to receive link speed, > TRUE=3D100Mbps. > + @param [out] pbFullDuplex Address of boolean to receive link duplex= , > TRUE=3Dfull. > + > + @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 re= gister > 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 packe= t > + 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 =3D 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 drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 3066 or ISO 639-2 language code f= ormat. > + @param [out] ppDriverName A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + @param [in] ChildHandle The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + @param [in] pLanguage A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 3066 or ISO 639-2 language code form= at. > + @param [out] ppControllerName A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf > new file mode 100644 > index 0000000000..60e43fd275 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf > @@ -0,0 +1,61 @@ > +## @file > +# Component description file for ASIX AX88772 USB/Ethernet driver. > +# > +# This module provides support for the ASIX AX88772 USB/Ethernet > adapter. > +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010018 > + BASE_NAME =3D Ax88772b > + FILE_GUID =3D 95C8D770-E1A4-4422-B263-E32F14FD818= 6 > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 1.0 > + > + ENTRY_POINT =3D EntryPoint > + > +# > +# VALID_ARCHITECTURES =3D IA32 X64 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/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentNa > me.c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentN > ame.c > new file mode 100644 > index 0000000000..76a732a7b0 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/ComponentN > ame.c > @@ -0,0 +1,175 @@ > +/** @file > + UEFI Component Name(2) protocol implementation. > + > + Copyright (c) 2011, Intel Corporation. All rights reserved. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Ax88772.h" > + > +/** > + EFI Component Name Protocol declaration > +**/ > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME_PROTOCOL gComponentName =3D { > + GetDriverName, > + GetControllerName, > + "eng" > +}; > + > +/** > + EFI Component Name 2 Protocol declaration > +**/ > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 =3D { > + (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[] =3D { > + {"eng;en", L"ASIX AX88772B Ethernet Driver 1.0"}, > + {NULL, NULL} > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 3066 or ISO 639-2 language code f= ormat. > + @param [out] ppDriverName A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 =3D LookupUnicodeString2 ( > + pLanguage, > + pThis->SupportedLanguages, > + mDriverNameTable, > + ppDriverName, > + (BOOLEAN)(pThis =3D=3D &gComponentName) > + ); > + > + return Status; > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + @param [in] ChildHandle The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + @param [in] pLanguage A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 3066 or ISO 639-2 language code form= at. > + @param [out] ppControllerName A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 =3D L"ASIX AX88772B USB Fast Ethernet Controller"; > + Status =3D EFI_SUCCESS; > + > + // > + // Return the operation status > + // > + > + return Status; > +} > diff --git > a/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding. > c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding. > c > new file mode 100644 > index 0000000000..2bec944140 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/DriverBinding. > c > @@ -0,0 +1,696 @@ > +/** @file > + Implement the driver binding protocol for Asix AX88772 Ethernet driver= . > + > + Copyright (c) 2011-2013, Intel Corporation. All rights reserved. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Ax88772.h" > + > +ASIX_DONGLE ASIX_DONGLES[] =3D { > + { 0x05AC, 0x1402, FLAG_TYPE_AX88772 }, // Apple USB Ethernet Adapter > + // ASIX 88772B > + { 0x0B95, 0x772B, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC }, > + { 0x0000, 0x0000, FLAG_NONE } // END - Do not remove > +}; > + > +/** > + 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; > + UINT32 Index; > + > + // > + // Connect to the USB stack > + // > + Status =3D 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 =3D pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device ); > + if (EFI_ERROR ( Status )) { > + Status =3D EFI_UNSUPPORTED; > + } > + else { > + // > + // Validate the adapter > + // > + for (Index =3D 0; ASIX_DONGLES[Index].VendorId !=3D 0; Index++) { > + if (ASIX_DONGLES[Index].VendorId =3D=3D Device.IdVendor && > + ASIX_DONGLES[Index].ProductId =3D=3D Device.IdProduct) { > + DEBUG ((EFI_D_INFO, "Found the AX88772B\r\n")); > + break; > + } > + } > + > + if (ASIX_DONGLES[Index].VendorId =3D=3D 0) > + Status =3D 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 protoc= ols. > + Initialize PXE structures, create a copy of the Controller Device Path= with > the > + NIC's MAC address appended to it, install the NetworkInterfaceIdentifi= er > 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 =3D NULL; > + MAC_ADDR_DEVICE_PATH MacDeviceNode; > + EFI_USB_DEVICE_DESCRIPTOR Device; > + UINT32 Index; > + > + // > + // Allocate the device structure > + // > + LengthInBytes =3D sizeof ( *pNicDevice ); > + Status =3D gBS->AllocatePool ( > + EfiRuntimeServicesData, > + LengthInBytes, > + (VOID **) &pNicDevice > + ); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "gBS->AllocatePool:pNicDevice > ERROR Status =3D %r\n", Status)); > + goto EXIT; > + } > + > + // > + // Set the structure signature > + // > + ZeroMem ( pNicDevice, LengthInBytes ); > + pNicDevice->Signature =3D DEV_SIGNATURE; > + > + Status =3D 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 =3D %r\n", Status)); > + gBS->FreePool ( pNicDevice ); > + goto EXIT; > + } > + > + // > + // Initialize the simple network protocol > + // > + Status =3D SN_Setup ( pNicDevice ); > + > + if (EFI_ERROR(Status)){ > + DEBUG ((EFI_D_ERROR, "SN_Setup ERROR Status =3D %r\n", Status)); > + gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + pThis->DriverBindingHandle, > + Controller > + ); > + gBS->FreePool ( pNicDevice ); > + goto EXIT; > + } > + > + Status =3D pNicDevice->pUsbIo->UsbGetDeviceDescriptor ( pNicDevice- > >pUsbIo, &Device ); > + if (EFI_ERROR ( Status )) { > + gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + pThis->DriverBindingHandle, > + Controller > + ); > + gBS->FreePool ( pNicDevice ); > + goto EXIT; > + } else { > + // > + // Validate the adapter > + // > + for (Index =3D 0; ASIX_DONGLES[Index].VendorId !=3D 0; Index++) { > + if (ASIX_DONGLES[Index].VendorId =3D=3D Device.IdVendor && > + ASIX_DONGLES[Index].ProductId =3D=3D Device.IdProduct) { > + break; > + } > + } > + > + if (ASIX_DONGLES[Index].VendorId =3D=3D 0) { > + gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + pThis->DriverBindingHandle, > + Controller > + ); > + gBS->FreePool ( pNicDevice ); > + goto EXIT; > + } > + > + pNicDevice->Flags =3D ASIX_DONGLES[Index].Flags; > + } > + > + // > + // Set Device Path > + // > + Status =3D 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 =3D %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 =3D MESSAGING_DEVICE_PATH; > + MacDeviceNode.Header.SubType =3D MSG_MAC_ADDR_DP; > + > + SetDevicePathNodeLength (&MacDeviceNode.Header, sizeof > (MAC_ADDR_DEVICE_PATH)); > + > + CopyMem (&MacDeviceNode.MacAddress, > + &pNicDevice- > >SimpleNetworkData.CurrentAddress, > + > PXE_HWADDR_LEN_ETHER); > + > + MacDeviceNode.IfType =3D pNicDevice->SimpleNetworkData.IfType; > + > + pNicDevice->MyDevPath =3D AppendDevicePathNode ( > + ParentDevicePath, > + (EFI_DEVICE_PATH_PROTOCOL *) &= MacDeviceNode > + ); > + > + pNicDevice->Controller =3D NULL; > + > + // > + // Install both the simple network and device path protocols. > + // > + Status =3D 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 =3D %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 =3D 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 dev= ice. > + > +**/ > +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 =3D EFI_SUCCESS; > + NIC_DEVICE > *pNicDevice; > + > + // > + // Complete all outstanding transactions to Controller. > + // Don't allow any new transaction to Controller to be > started. > + // > + if (NumberOfChildren =3D=3D 0) { > + > + Status =3D 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 =3D DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork ); > + > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > + Controller, >=20 > + &gEfiCallerIdGuid, > + pNicDevice, > + &gEfiSimpleNetworkProtocolGuid, > + &pNicDevice->SimpleNetwork, > + > &gEfiDevicePathProtocolGuid, > + pNicDevice- > >MyDevPath, > + NULL > + ); > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // > + // Close the bus driver > + // > + Status =3D 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 =3D 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 =3D TRUE; > + > + for (Index =3D 0; Index < NumberOfChildren; Index++) { > + > + Status =3D gBS->OpenProtocol ( > + ChildHandleBuffer[Index], > + &gEfiSimpleNetworkProtocolGuid, > + (VOID **) &SimpleNetwork, > + pThis->DriverBindingHandle, > + Controller, > + > EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + > + if (EFI_ERROR (Status)) { > + AllChildrenStopped =3D FALSE; > + DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handl= e > when opening SimpleNetwork\n", (UINT32)Index)); > + continue; > + } > + > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( SimpleNetwork ); > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + pThis->DriverBindingHandle, > + ChildHandleBuffer[Index] > + ); > + > + Status =3D gBS- > >UninstallMultipleProtocolInterfaces ( > + ChildHandleBuffer[Index], >=20 > + &gEfiCallerIdGuid, > + pNicDevice, > + &gEfiSimpleNetworkProtocolGuid, > + &pNicDevice->SimpleNetwork, > + > &gEfiDevicePathProtocolGuid, > + pNicDevice- > >MyDevPath, > + NULL > + ); > + > + if (EFI_ERROR (Status)) { > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiUsbIoProtocolGuid, > + (VOID **) &pNicDevice->pUsbIo, > + pThis->DriverBindingHandle, > + ChildHandleBuffer[Index], > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER > + ); > + } > + else { > + int i; > + RX_PKT * pCurr =3D pNicDevice->QueueHead; > + RX_PKT * pFree; > + > + for ( i =3D 0 ; i < MAX_QUEUE_SIZE ; i++) { > + if ( NULL !=3D pCurr ) { > + pFree =3D pCurr; > + pCurr =3D pCurr->pNext; > + gBS->FreePool (pFree); > + } > + } > + > + if ( NULL !=3D pNicDevice->pRxTest) > + gBS->FreePool (pNicDevice- > >pRxTest); > + > + if ( NULL !=3D pNicDevice->pTxTest) > + gBS->FreePool (pNicDevice- > >pTxTest); > + > + if ( NULL !=3D pNicDevice->MyDevPath) > + gBS->FreePool (pNicDevice- > >MyDevPath); > + > + if ( NULL !=3D pNicDevice) > + gBS->FreePool (pNicDevice); > + } > + } > + > + if (!AllChildrenStopped) { > + return EFI_DEVICE_ERROR; > + } > + return EFI_SUCCESS; > +} > + > + > +/** > + Driver binding protocol declaration > +**/ > +EFI_DRIVER_BINDING_PROTOCOL gDriverBinding =3D { > + 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 =3D 0; > + pHandle =3D NULL; > + Status =3D gBS->LocateHandle ( > + ByProtocol, > + &gEfiCallerIdGuid, > + NULL, > + &BufferSize, > + NULL ); > + if ( EFI_BUFFER_TOO_SMALL =3D=3D Status ) { > + for ( ; ; ) { > + // > + // One or more block IO devices are present > + // > + Status =3D 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 =3D gBS->LocateHandle ( > + ByProtocol, > + &gEfiCallerIdGuid, > + NULL, > + &BufferSize, > + pHandle ); > + if ( EFI_ERROR ( Status )) { > + // > + // Error getting handles > + // > + break; > + } > + > + // > + // Remove any use of the driver > + // > + Max =3D BufferSize / sizeof ( pHandle[ 0 ]); > + for ( Index =3D 0; Max > Index; Index++ ) { > + Status =3D 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 =3D=3D Status ) { > + // > + // No devices were found > + // > + Status =3D EFI_SUCCESS; > + } > + } > + > + // > + // Free the handle array > + // > + if ( NULL !=3D 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 =3D 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/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwor > k.c > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwor > k.c > new file mode 100644 > index 0000000000..76babedb20 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/SimpleNetwor > k.c > @@ -0,0 +1,1657 @@ > +/** @file > + Provides the Simple Network functions. > + > + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved. > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pMode =3D pSimpleNetwork->Mode; > + > + // > + // Clear the multicast hash table > + // > + Ax88772MulticastClear ( pNicDevice ); > + > + // > + // Load the multicast hash table > + // > + if ( 0 !=3D ( pMode->ReceiveFilterSetting & > EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST )) { > + for ( Index =3D 0; Index < pMode->MCastFilterCount; Index++ ) { > + // > + // Enable the next multicast address > + // > + Ax88772MulticastSet ( pNicDevice, > + &pMode->MCastFilter[ Index ].Addr[0]); > + } > + } > + > + Status =3D 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 wi= ll not be read from > + the device. If this is not NULL, the in= terrupt status will > + be read from teh device. When the inter= rupt status is > read, > + it will also be cleared. Clearing the t= ransmit interrupt > + does not empty the recycled transmit buf= fer array. > + @param [out] ppTxBuf Recycled transmit buffer address. The > network interface will > + not transmit if its internal recycled tr= ansmit buffer array is > + full. Reading the transmit buffer does = not clear the > transmit > + interrupt. If this is NULL, then the tr= ansmit buffer status > + will not be read. If there are not tran= smit buffers to > recycle > + and TxBuf is not NULL, *TxBuf will be se= t 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Return the transmit buffer > + // > + > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + if (( NULL !=3D ppTxBuf ) && ( NULL !=3D pNicDevice->pTxBuffer )) { > + *ppTxBuf =3D pNicDevice->pTxBuffer; > + pNicDevice->pTxBuffer =3D NULL; > + } > + > + // > + // Determine if interface is running > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + > + if ( pNicDevice->LinkIdleCnt > MAX_LINKIDLE_THRESHOLD) { > + > + bLinkUp =3D pNicDevice->bLinkUp; > + bSpeed100 =3D pNicDevice->b100Mbps; > + bFullDuplex =3D pNicDevice->bFullDuplex; > + Status =3D 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 =3D 0; > + DEBUG (( EFI_D_INFO , "Reset to establish prop= er link > setup: %d Mbps, %a duplex\r\n", > + pNicDevice->b100Mbps ? 100 : 10, pNi= cDevice- > >bFullDuplex ? "Full" : "Half")); > + Status =3D SN_Reset ( &pNicDevice->SimpleNetwo= rk, FALSE ); > + } > + if (( !bLinkUp ) && pNicDevice->bLinkUp ) { > + // > + // Display the autonegotiation status > + // > + DEBUG (( EFI_D_INFO , "Link: Up, %d Mbps, %a duple= x\r\n", > + pNicDevice->b100Mbps ? 100 : 10, pNicDev= ice- > >bFullDuplex ? "Full" : "Half")); > + > + } > + pNicDevice->LinkIdleCnt =3D 0; > + } > + } > + // > + // Update the link status > + // > + if ( bLinkUp && ( !pNicDevice->bLinkUp )) { > + DEBUG (( EFI_D_INFO , "Link: Down\r\n")); > + } > + } > + > + pMode->MediaPresent =3D pNicDevice->bLinkUp; > + // > + // Return the interrupt status > + // > + if ( NULL !=3D pInterruptStatus ) { > + *pInterruptStatus =3D 0; > + } > + Status =3D EFI_SUCCESS; > + } > + else { > + if ( EfiSimpleNetworkStarted =3D=3D pMode->State ) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + > + } > + else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + gBS->RestoreTPL(TplPrevious) ; > + > + return Status; > +} > + > + > +/** > + Resets the network adapter and allocates the transmit and receive buff= ers > + required by the network interface; optionally, also requests allocatio= n 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 buff= er > allocation > + @param [in] ExtraTxBufferSize Size in bytes to add to the transmit buf= fer > allocation > + > + @retval EFI_SUCCESS This operation was successful. > + @retval EFI_NOT_STARTED The network interface was not started. > + @retval EFI_OUT_OF_RESOURCES 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 =3D gBS->RaiseTPL (TPL_CALLBACK); > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Determine if the interface is already started > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStarted =3D=3D pMode->State ) { > + if (( 0 =3D=3D ExtraRxBufferSize ) && ( 0 =3D=3D ExtraTxBufferSize= )) { > + // > + // Start the adapter > + // > + TmpState =3D pMode->State; > + pMode->State =3D EfiSimpleNetworkInitialized; > + Status =3D SN_Reset ( pSimpleNetwork, FALSE ); > + if ( EFI_ERROR ( Status )) { > + // > + // Update the network state > + // > + pMode->State =3D TmpState; > + DEBUG (( EFI_D_ERROR , "SN_reset failed\n")); > + } > + } > + else { > + DEBUG (( EFI_D_ERROR , "Increase ExtraRxBufferSize =3D %d > ExtraTxBufferSize=3D%d\n", > + ExtraRxBufferSize, ExtraTxBufferSize)); > + Status =3D EFI_UNSUPPORTED; > + } > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 c= onverted > 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Get pointer to SNP driver instance for *this. > + // > + if (pSimpleNetwork =3D=3D NULL) { > + gBS->RestoreTPL(TplPrevious); > + return EFI_INVALID_PARAMETER; > + } > + > + if (pIP =3D=3D NULL || pMAC =3D=3D NULL) { > + gBS->RestoreTPL(TplPrevious); > + return EFI_INVALID_PARAMETER; > + } > + > + if (bIPv6){ > + Status =3D EFI_UNSUPPORTED; > + } > + else { > + // > + // check if the ip given is a mcast IP > + // > + if ((pIP->v4.Addr[0] & 0xF0) !=3D 0xE0) { > + gBS->RestoreTPL(TplPrevious); > + return EFI_INVALID_PARAMETER; > + } > + else { > + if (pSimpleNetwork->Mode->State =3D=3D EfiSimpleNetworkInitializ= ed) > + { > + pMAC->Addr[0] =3D 0x01; > + pMAC->Addr[1] =3D 0x00; > + pMAC->Addr[2] =3D 0x5e; > + pMAC->Addr[3] =3D (UINT8) (pIP->v4.Addr[1] & 0x7f); > + pMAC->Addr[4] =3D (UINT8) pIP->v4.Addr[2]; > + pMAC->Addr[5] =3D (UINT8) pIP->v4.Addr[3]; > + Status =3D EFI_SUCCESS; > + } > + else if (pSimpleNetwork->Mode->State =3D=3D EfiSimpleNetworkStar= ted) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D 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 writ= e > 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 fro= m the > NVRAM device. > + This must also be a multiple of NvramAcc= essSize. > + @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 =3D 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 =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork); > + for ( offset =3D 0; offset < BufLength; ){ > + pLength =3D (UINT16*) (pNicDevice->pBulkInBuff + offset); > + pLengthBar =3D (UINT16*) (pNicDevice->pBulkInBuff + offset +2); > + > + *pLength &=3D 0x7ff; > + *pLengthBar &=3D 0x7ff; > + *pLengthBar |=3D 0xf800; > + > + if ((*pLength ^ *pLengthBar ) !=3D 0xFFFF) { > + DEBUG (( EFI_D_ERROR , "Pkt length error. BufLength =3D %d\n", > BufLength)); > + return; > + } > + > + if (TRUE =3D=3D pNicDevice->pNextFill->f_Used) { > + return; > + } > + else { > + pData =3D pNicDevice->pBulkInBuff + offset + 4; > + pNicDevice->pNextFill->f_Used =3D TRUE; > + pNicDevice->pNextFill->Length =3D *pLength; > + CopyMem (&pNicDevice->pNextFill->Data[0], pData, *pLength); > + > + pNicDevice->pNextFill =3D pNicDevice->pNextFill->pNext; > + offset +=3D ((*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 =3D gBS->RaiseTPL (TPL_CALLBACK); > + > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && > + ( NULL !=3D pSimpleNetwork->Mode ) && > + (NULL !=3D pBufferSize) && > + (NULL !=3D pBuffer)) { > + // > + // The interface must be running > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Update the link status > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pNicDevice->LinkIdleCnt++; > + pMode->MediaPresent =3D pNicDevice->bLinkUp; > + > + if ( pMode->MediaPresent && pNicDevice->bComplete) { > + > + > + if (pNicDevice->PktCntInQueue !=3D 0 ) { > + DEBUG (( EFI_D_INFO, "pNicDevice->PktCntInQueue =3D %d\n", > + pNicDevice->PktCntInQueue)); > + } > + > + LengthInBytes =3D MAX_BULKIN_SIZE; > + if (pNicDevice->PktCntInQueue =3D=3D 0 ){ > + // > + // Attempt to do bulk in > + // > + SetMem (&pNicDevice->pBulkInBuff[0], 4, 0); > + pUsbIo =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbBulkTransfer ( pUsbIo, > + USB_ENDPOINT_DIR_IN | BULK_IN_END= POINT, > + &pNicDevice->pBulkInBuff[0], > + &LengthInBytes, > + BULKIN_TIMEOUT, > + &TransferStatus ); > + > + if (LengthInBytes !=3D 0 && !EFI_ERROR(Status) > && !EFI_ERROR(TransferStatus) ){ > + FillPkt2Queue(pSimpleNetwork, LengthInBytes); > + } > + } > + > + pFirstFill =3D pNicDevice->pFirstFill; > + > + if (TRUE =3D=3D pFirstFill->f_Used) { > + ETHERNET_HEADER * pHeader; > + pNicDevice->LinkIdleCnt =3D 0; > + CopyMem (pBuffer, &pFirstFill->Data[0], pFirstFill->Length)= ; > + pHeader =3D (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 !=3D pHeaderSize ) { > + *pHeaderSize =3D sizeof ( *pHeader ); > + } > + if ( NULL !=3D pDestAddr ) { > + CopyMem ( pDestAddr, &pHeader->dest_addr, > PXE_HWADDR_LEN_ETHER ); > + } > + if ( NULL !=3D pSrcAddr ) { > + CopyMem ( pSrcAddr, &pHeader->src_addr, > PXE_HWADDR_LEN_ETHER ); > + } > + if ( NULL !=3D pProtocol ) { > + Type =3D pHeader->type; > + Type =3D (UINT16)(( Type >> 8 ) | ( Type << 8 )); > + *pProtocol =3D Type; > + } > + Status =3D EFI_SUCCESS; > + if (*pBufferSize < pFirstFill->Length) { > + DEBUG (( EFI_D_ERROR, "RX: Buffer was too small")); > + Status =3D EFI_BUFFER_TOO_SMALL; > + } > + *pBufferSize =3D pFirstFill->Length; > + pFirstFill->f_Used =3D FALSE; > + pNicDevice->pFirstFill =3D pFirstFill->pNext; > + pNicDevice->PktCntInQueue--; > + } > + else { > + pNicDevice->LinkIdleCnt++; > + Status =3D EFI_NOT_READY; > + } > + } > + else { > + // > + // Link no up > + // > + pNicDevice->LinkIdleCnt++; > + Status =3D EFI_NOT_READY; > + } > + > + } > + else { > + if (EfiSimpleNetworkStarted =3D=3D pMode->State) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + } > + else { > + Status =3D 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 hardwar= e > + a more liberal setting is selected. > + > + If the same bits are set in the Enable and Disable parameters, then th= e 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 filt= ers > + instead. The receiving software is responsible for discarding any ext= ra > + 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 receiv= e > + 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 multicas= t > + 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 T= RUE. > + @param [in] bResetMCastFilter Set to TRUE to reset the contents of the > multicast receive > + filters on the network interface to thei= r 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 rec= eive > filter HW MAC > + addresses. This list will replace any e= xisting multicast > + HW MAC address list. This field is opti= onal 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 =3D EFI_SUCCESS; > + EFI_TPL TplPrevious; > + > + TplPrevious =3D gBS->RaiseTPL(TPL_CALLBACK); > + pMode =3D pSimpleNetwork->Mode; > + > + if (pSimpleNetwork =3D=3D NULL) { > + gBS->RestoreTPL(TplPrevious); > + return EFI_INVALID_PARAMETER; > + } > + > + switch (pMode->State) { > + case EfiSimpleNetworkInitialized: > + break; > + case EfiSimpleNetworkStopped: > + Status =3D EFI_NOT_STARTED; > + gBS->RestoreTPL(TplPrevious); > + return Status; > + default: > + Status =3D 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) !=3D 0) || > + ((Disable &~pMode->ReceiveFilterMask) !=3D 0)) { > + Status =3D EFI_INVALID_PARAMETER; > + gBS->RestoreTPL(TplPrevious); > + return Status; > + } > + > + if (bResetMCastFilter) { > + Disable |=3D (EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & pMode- > >ReceiveFilterMask); > + pMode->MCastFilterCount =3D 0; > + if ( (0 =3D=3D (pMode->ReceiveFilterSetting & > EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST)) > + && Enable =3D=3D 0 && Disable =3D=3D 2) { > + gBS->RestoreTPL(TplPrevious); > + return EFI_SUCCESS; > + } > + } > + else { > + if (MCastFilterCnt !=3D 0) { > + UINTN i; > + EFI_MAC_ADDRESS * pMulticastAddress; > + pMulticastAddress =3D pMCastFilter; > + > + if ((MCastFilterCnt > pMode->MaxMCastFilterCount) || > + (pMCastFilter =3D=3D NULL)) { > + Status =3D EFI_INVALID_PARAMETER; > + gBS->RestoreTPL(TplPrevious); > + return Status; > + } > + > + for ( i =3D 0 ; i < MCastFilterCnt ; i++ ) { > + UINT8 tmp; > + tmp =3D pMulticastAddress->Addr[0]; > + if ( (tmp & 0x01) !=3D 0x01 ) { > + gBS->RestoreTPL(TplPrevious); > + return EFI_INVALID_PARAMETER; > + } > + pMulticastAddress++; > + } > + > + pMode->MCastFilterCount =3D (UINT32)MCastFilterCnt; > + CopyMem (&pMode->MCastFilter[0], > + pMCastFilter, > + MCastFilterCnt * sizeof ( EFI_MAC_ADDRESS)); > + } > + } > + > + if (Enable =3D=3D 0 && Disable =3D=3D 0 && !bResetMCastFilter && MCast= FilterCnt > =3D=3D 0) { > + Status =3D EFI_SUCCESS; > + gBS->RestoreTPL(TplPrevious); > + return Status; > + } > + > + if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) !=3D 0 && > MCastFilterCnt =3D=3D 0) { > + Status =3D EFI_INVALID_PARAMETER; > + gBS->RestoreTPL(TplPrevious); > + return Status; > + } > + > + pMode->ReceiveFilterSetting |=3D Enable; > + pMode->ReceiveFilterSetting &=3D ~Disable; > + Status =3D ReceiveFilterUpdate (pSimpleNetwork); > + > + if (EFI_DEVICE_ERROR =3D=3D Status || EFI_INVALID_PARAMETER =3D=3D Sta= tus) > + Status =3D 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 perfo= rm > 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Update the device state > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pNicDevice->bComplete =3D FALSE; > + pNicDevice->bLinkUp =3D FALSE; > + pNicDevice->bHavePkt =3D FALSE; > + pMode =3D pSimpleNetwork->Mode; > + pMode->MediaPresent =3D FALSE; > + > + // > + // Reset the device > + // > + Status =3D Ax88772Reset ( pNicDevice ); > + if ( !EFI_ERROR ( Status )) { > + // > + // Update the receive filters in the adapter > + // > + Status =3D ReceiveFilterUpdate ( pSimpleNetwork ); > + > + // > + // Try to get a connection to the network > + // > + if ( !EFI_ERROR ( Status )) { > + // > + // Start the autonegotiation > + // > + Status =3D Ax88772NegotiateLinkStart ( pNicDevice ); > + } > + } > + } > + else { > + if (EfiSimpleNetworkStarted =3D=3D pMode->State) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + } > + else { > + Status =3D 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 =3D NULL; > + RX_PKT * pPrev =3D NULL; > + > + pSimpleNetwork =3D &pNicDevice->SimpleNetwork; > + pSimpleNetwork->Revision =3D > EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; > + pSimpleNetwork->Start =3D (EFI_SIMPLE_NETWORK_START)SN_Start; > + pSimpleNetwork->Stop =3D (EFI_SIMPLE_NETWORK_STOP)SN_Stop; > + pSimpleNetwork->Initialize =3D > (EFI_SIMPLE_NETWORK_INITIALIZE)SN_Initialize; > + pSimpleNetwork->Reset =3D (EFI_SIMPLE_NETWORK_RESET)SN_Reset; > + pSimpleNetwork->Shutdown =3D > (EFI_SIMPLE_NETWORK_SHUTDOWN)SN_Shutdown; > + pSimpleNetwork->ReceiveFilters =3D > (EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)SN_ReceiveFilters; > + pSimpleNetwork->StationAddress =3D > (EFI_SIMPLE_NETWORK_STATION_ADDRESS)SN_StationAddress; > + pSimpleNetwork->Statistics =3D > (EFI_SIMPLE_NETWORK_STATISTICS)SN_Statistics; > + pSimpleNetwork->MCastIpToMac =3D > (EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)SN_MCastIPtoMAC; > + pSimpleNetwork->NvData =3D (EFI_SIMPLE_NETWORK_NVDATA)SN_NvData; > + pSimpleNetwork->GetStatus =3D > (EFI_SIMPLE_NETWORK_GET_STATUS)SN_GetStatus; > + pSimpleNetwork->Transmit =3D > (EFI_SIMPLE_NETWORK_TRANSMIT)SN_Transmit; > + pSimpleNetwork->Receive =3D (EFI_SIMPLE_NETWORK_RECEIVE)SN_Receive; > + pSimpleNetwork->WaitForPacket =3D NULL; > + pMode =3D &pNicDevice->SimpleNetworkData; > + pSimpleNetwork->Mode =3D pMode; > + pMode->State =3D EfiSimpleNetworkStopped; > + pMode->HwAddressSize =3D PXE_HWADDR_LEN_ETHER; > + pMode->MediaHeaderSize =3D sizeof ( ETHERNET_HEADER ); > + pMode->MaxPacketSize =3D MAX_ETHERNET_PKT_SIZE; > + pMode->NvRamSize =3D 0; > + pMode->NvRamAccessSize =3D 0; > + pMode->ReceiveFilterMask =3D 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 =3D EFI_SIMPLE_NETWORK_RECEIVE_UNICAST > + | EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; > + pMode->MaxMCastFilterCount =3D MAX_MCAST_FILTER_CNT; > + pMode->MCastFilterCount =3D 0; > + SetMem ( &pMode->BroadcastAddress, > + PXE_HWADDR_LEN_ETHER, > + 0xff ); > + pMode->IfType =3D EfiNetworkInterfaceUndi; > + pMode->MacAddressChangeable =3D TRUE; > + pMode->MultipleTxSupported =3D FALSE; > + pMode->MediaPresentSupported =3D TRUE; > + pMode->MediaPresent =3D FALSE; > + pNicDevice->LinkIdleCnt =3D 0; > + // > + // Read the MAC address > + // > + pNicDevice->PhyId =3D PHY_ID_INTERNAL; > + pNicDevice->b100Mbps =3D TRUE; > + pNicDevice->bFullDuplex =3D TRUE; > + > + Status =3D 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 =3D 0; > + > + for ( i =3D 0 ; i < MAX_QUEUE_SIZE ; i++) { > + Status =3D 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 =3D FALSE; > + > + if ( i ) { > + pPrev->pNext =3D pCurr; > + } > + else { > + pNicDevice->QueueHead =3D pCurr; > + } > + > + if (MAX_QUEUE_SIZE - 1 =3D=3D i) { > + pCurr->pNext =3D pNicDevice->QueueHead; > + } > + > + pPrev =3D pCurr; > + } > + > + pNicDevice->pNextFill =3D pNicDevice->QueueHead; > + pNicDevice->pFirstFill =3D pNicDevice->QueueHead; > + > + Status =3D gBS->AllocatePool (EfiRuntimeServicesData, > + MAX_BULKIN_SIZE, > + (VOID **) &pNicDevice->pBulkInBuff); > + > + if (EFI_ERROR(Status)) { > + DEBUG (( EFI_D_ERROR, "gBS->AllocatePool for pBulkInBuff error. > Status =3D %r\n", > + Status)); > + return Status; > + } > + } > + else { > + DEBUG (( EFI_D_ERROR, "Ax88772MacAddressGet error. Status =3D %r\n", > Status)); > + return Status; > + } > + > + Status =3D gBS->AllocatePool ( EfiRuntimeServicesData, > + sizeof ( RX_TX_PACKET ), > + (VOID **) &pNicDevice->pRxTest ); > + > + if (EFI_ERROR (Status)) { > + DEBUG (( EFI_D_ERROR, "gBS->AllocatePool:pNicDevice->pRxTest error. > Status =3D %r\n", > + Status)); > + return Status; > + } > + > + Status =3D gBS->AllocatePool ( EfiRuntimeServicesData, > + sizeof ( RX_TX_PACKET ), > + (VOID **) &pNicDevice->pTxTest ); > + > + if (EFI_ERROR (Status)) { > + DEBUG (( EFI_D_ERROR, "gBS->AllocatePool:pNicDevice->pTxTest error. > Status =3D %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 =3D 0; > + RX_PKT * pCurr =3D NULL; > + > + TplPrevious =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Verify the parameters > + // > + Status =3D EFI_INVALID_PARAMETER; > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStopped =3D=3D pMode->State ) { > + // > + // Initialize the mode structuref > + // NVRAM access is not supported > + // > + ZeroMem ( pMode, sizeof ( *pMode )); > + > + pMode->State =3D EfiSimpleNetworkStarted; > + pMode->HwAddressSize =3D PXE_HWADDR_LEN_ETHER; > + pMode->MediaHeaderSize =3D sizeof ( ETHERNET_HEADER ); > + pMode->MaxPacketSize =3D MAX_ETHERNET_PKT_SIZE; > + pMode->ReceiveFilterMask =3D 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 =3D > EFI_SIMPLE_NETWORK_RECEIVE_UNICAST; > + pMode->MaxMCastFilterCount =3D MAX_MCAST_FILTER_CNT; > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + Status =3D Ax88772MacAddressGet ( pNicDevice, &pMode- > >PermanentAddress.Addr[0]); > + CopyMem ( &pMode->CurrentAddress, > + &pMode->PermanentAddress, > + sizeof ( pMode->CurrentAddress )); > + SetMem(&pMode->BroadcastAddress, PXE_HWADDR_LEN_ETHER, 0xff); > + pMode->IfType =3D EfiNetworkInterfaceUndi; > + pMode->MacAddressChangeable =3D TRUE; > + pMode->MultipleTxSupported =3D FALSE; > + pMode->MediaPresentSupported =3D TRUE; > + pMode->MediaPresent =3D FALSE; > + pNicDevice->PktCntInQueue =3D 0; > + pNicDevice->pNextFill =3D pNicDevice->QueueHead; > + pNicDevice->pFirstFill =3D pNicDevice->QueueHead; > + pCurr =3D pNicDevice->QueueHead; > + > + for ( i =3D 0 ; i < MAX_QUEUE_SIZE ; i++) { > + pCurr->f_Used =3D FALSE; > + pCurr =3D pCurr->pNext; > + } > + > + } > + else { > + Status =3D 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 FALS= E > + then the current station address is changed to the address specified b= y > + 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 t= o the > + network interface's permanent address. > + @param [in] pNew New station address to be used for the n= etwork > + 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) > + && ( NULL !=3D pSimpleNetwork->Mode ) > + && (( bReset ) || ( ( !bReset) && ( NULL !=3D pNew )))) { > + // > + // Verify that the adapter is already started > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D 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 =3D Ax88772MacAddressSet ( pNicDevice, &pMode- > >CurrentAddress.Addr[0]); > + } > + else { > + if (EfiSimpleNetworkStarted =3D=3D pMode->State) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + } > + else { > + Status =3D 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 tab= le 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 !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + pMode =3D pSimpleNetwork->Mode; > + // > + // Determine if the interface is started > + // > + if (EfiSimpleNetworkInitialized =3D=3D pMode->State){ > + // > + // Determine if the StatisticsSize is big enough > + // > + if (sizeof (EFI_NETWORK_STATISTICS) <=3D *pStatisticsSize){ > + if (bReset) { > + Status =3D EFI_SUCCESS; > + } > + else { > + Status =3D EFI_UNSUPPORTED; > + } > + } > + else { > + Status =3D EFI_BUFFER_TOO_SMALL; > + } > + } > + else{ > + if (EfiSimpleNetworkStarted =3D=3D pMode->State) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + } > + else { > + Status =3D 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Determine if the interface is started > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkStarted =3D=3D pMode->State ) { > + pMode->State =3D EfiSimpleNetworkStopped; > + Status =3D EFI_SUCCESS; > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 an= d > 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + // > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && ( NULL !=3D pSimpleNetwork->Mode )= ) { > + // > + // Determine if the interface is already started > + // > + pMode =3D pSimpleNetwork->Mode; > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Stop the adapter > + // > + RxFilter =3D pMode->ReceiveFilterSetting; > + pMode->ReceiveFilterSetting =3D 0; > + Status =3D SN_Reset ( pSimpleNetwork, FALSE ); > + pMode->ReceiveFilterSetting =3D RxFilter; > + if ( !EFI_ERROR ( Status )) { > + > + // > + // Update the network state > + // > + pMode->State =3D EfiSimpleNetworkStarted; > + } > + else if ( EFI_DEVICE_ERROR =3D=3D Status ) { > + pMode->State =3D EfiSimpleNetworkStopped; > + } > + } > + else { > + Status =3D EFI_NOT_STARTED; > + } > + } > + else { > + Status =3D 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 mus= t not be NULL. > + @param [in] BufferSize The size, in bytes, of the entire packet= (media > header and > + data) to be transmitted through the netw= ork interface. > + @param [in] pBuffer A pointer to the packet (media header fo= llowed > by data) to > + to be transmitted. This parameter can n= ot be NULL. If > + HeaderSize is zero, then the media heade= r 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 HeaderSiz= e is > zero, then > + this parameter is ignored. If HeaderSiz= e is nonzero and > + SrcAddr is NULL, then SimpleNetwork->Mod= e- > >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 HeaderS= ize 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 acc= ept > 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 =3D gBS->RaiseTPL(TPL_CALLBACK); > + > + // Verify the parameters > + // > + if (( NULL !=3D pSimpleNetwork ) && > + ( NULL !=3D pSimpleNetwork->Mode ) && > + ( NULL !=3D pBuffer) && > + ( (HeaderSize =3D=3D 0) || ( (NULL !=3D pDestAddr) && (NULL !=3D p= Protocol) ))) { > + // > + // The interface must be running > + // > + pMode =3D pSimpleNetwork->Mode; > + // > + // Verify parameter of HeaderSize > + // > + if ((HeaderSize =3D=3D 0) || (HeaderSize =3D=3D pMode->MediaHeaderSi= ze)){ > + // > + // Determine if BufferSize is big enough > + // > + if (BufferSize >=3D pMode->MediaHeaderSize){ > + if ( EfiSimpleNetworkInitialized =3D=3D pMode->State ) { > + // > + // Update the link status > + // > + pNicDevice =3D DEV_FROM_SIMPLE_NETWORK ( pSimpleNetwork ); > + pMode->MediaPresent =3D 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 =3D (UINT16) BufferSize; > + > + // > + // Transmit the packet > + // > + pHeader =3D (ETHERNET_HEADER *) &pNicDevice->pTxTest->Data[0= ]; > + if ( 0 !=3D HeaderSize ) { > + if ( NULL !=3D pDestAddr ) { > + CopyMem ( &pHeader->dest_addr, pDestAddr, > PXE_HWADDR_LEN_ETHER ); > + } > + if ( NULL !=3D 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 !=3D pProtocol ) { > + Type =3D *pProtocol; > + } > + else { > + Type =3D pNicDevice->pTxTest->Length; > + } > + Type =3D (UINT16)(( Type >> 8 ) | ( Type << 8 )); > + pHeader->type =3D Type; > + } > + if ( pNicDevice->pTxTest->Length < MIN_ETHERNET_PKT_SIZE ) { > + pNicDevice->pTxTest->Length =3D 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 =3D ~(pNicDevice->pTxTest->Le= ngth); > + TransferLength =3D sizeof ( pNicDevice->pTxTest->Length ) > + + sizeof ( pNicDevice->pTxTest->LengthBar ) > + + pNicDevice->pTxTest->Length; > + > + if (TransferLength % 512 =3D=3D 0 || TransferLength % 1024 = =3D=3D 0) > + TransferLength +=3D4; > + > + // > + // Work around USB bus driver bug where a timeout set by re= ceive > + // succeeds but the timeout expires immediately after, caus= ing the > + // transmit operation to timeout. > + // > + pUsbIo =3D pNicDevice->pUsbIo; > + Status =3D pUsbIo->UsbBulkTransfer ( pUsbIo, > + BULK_OUT_ENDPOINT, > + &pNicDevice->pTxTest->Len= gth, > + &TransferLength, > + 0xfffffffe, > + &TransferStatus ); > + if ( !EFI_ERROR ( Status )) { > + Status =3D TransferStatus; > + } > + > + if ( !EFI_ERROR ( Status )) { > + pNicDevice->pTxBuffer =3D pBuffer; > + } > + else { > + if ((TransferLength !=3D (UINTN)( pNicDevice->pTxTest->Len= gth + 4 )) > && > + (TransferLength !=3D (UINTN)(( pNicDevice->pTxTest->L= ength + 4 ) > + 4))) { > + DEBUG ((EFI_D_INFO, "TransferLength didn't match Packet > Length\n")); > + } > + // > + // Reset the controller to fix the error > + // > + if ( EFI_DEVICE_ERROR =3D=3D Status ) { > + SN_Reset ( pSimpleNetwork, FALSE ); > + } > + Status =3D EFI_NOT_READY; > + } > + } > + else { > + // > + // No packets available. > + // > + Status =3D EFI_NOT_READY; > + } > + > + } > + else { > + if (EfiSimpleNetworkStarted =3D=3D pMode->State) { > + Status =3D EFI_DEVICE_ERROR; > + } > + else { > + Status =3D EFI_NOT_STARTED ; > + } > + } > + } > + else { > + Status =3D EFI_BUFFER_TOO_SMALL; > + } > + } > + else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + } > + else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + > + gBS->RestoreTPL (TplPrevious); > + > + return Status; > +} > diff --git a/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c > new file mode 100644 > index 0000000000..4e7830ea94 > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.c > @@ -0,0 +1,917 @@ > +/** @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.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +// > +// Cirrus Logic 5430 Controller Driver > +// > +#include "CirrusLogic5430.h" > + > +EFI_DRIVER_BINDING_PROTOCOL gCirrusLogic5430DriverBinding =3D { > + CirrusLogic5430ControllerDriverSupported, > + CirrusLogic5430ControllerDriverStart, > + CirrusLogic5430ControllerDriverStop, > + 0x10, > + NULL, > + NULL > +}; > + > +/// > +/// Generic Attribute Controller Register Settings > +/// > +UINT8 AttributeController[21] =3D { > + 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] =3D { > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF > +}; > + > +// > +// 640 x 480 x 256 color @ 60 Hertz > +// > +UINT8 Crtc_640_480_256_60[28] =3D { > + 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] =3D { > + 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] =3D { > + 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] =3D { > + 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] =3D { > + 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] =3D { > + 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[] =3D { > + { 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 functio= n > 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 =3D 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 =3D PciIo->Pci.Read ( > + PciIo, > + EfiPciIoWidthUint32, > + 0, > + sizeof (Pci) / sizeof (UINT32), > + &Pci > + ); > + if (EFI_ERROR (Status)) { > + goto Done; > + } > + > + Status =3D EFI_UNSUPPORTED; > + // > + // See if the I/O enable is on. Most systems only allow one VGA devic= e to > be turned on > + // at a time, so see if this is one that is turned on. > + // > + // if (((Pci.Hdr.Command & 0x01) =3D=3D 0x01)) { > + // > + // See if this is a Cirrus Logic PCI controller > + // > + if (Pci.Hdr.VendorId =3D=3D CIRRUS_LOGIC_VENDOR_ID) { > + // > + // See if this is a 5430 or a 5446 PCI controller > + // > + if (Pci.Hdr.DeviceId =3D=3D CIRRUS_LOGIC_5430_DEVICE_ID || > + Pci.Hdr.DeviceId =3D=3D CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID || > + Pci.Hdr.DeviceId =3D=3D CIRRUS_LOGIC_5446_DEVICE_ID) { > + > + Status =3D EFI_SUCCESS; > + // > + // If this is an Intel 945 graphics controller, > + // go further check RemainingDevicePath validation > + // > + if (RemainingDevicePath !=3D NULL) { > + Node =3D (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 !=3D ACPI_DEVICE_PATH || > + Node->DevPath.SubType !=3D ACPI_ADR_DP || > + DevicePathNodeLength(&Node->DevPath) !=3D > sizeof(ACPI_ADR_DEVICE_PATH)) { > + Status =3D 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 functio= n > 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 =3D FALSE; > + // > + // Allocate Private context data for UGA Draw inteface. > + // > + Private =3D AllocateZeroPool (sizeof (CIRRUS_LOGIC_5430_PRIVATE_DATA))= ; > + if (Private =3D=3D NULL) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Error; > + } > + > + // > + // Set up context record > + // > + Private->Signature =3D CIRRUS_LOGIC_5430_PRIVATE_DATA_SIGNATURE; > + Private->Handle =3D NULL; > + > + // > + // Open PCI I/O Protocol > + // > + Status =3D 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 =3D Private->PciIo->Attributes ( > + Private->PciIo, > + EfiPciIoAttributeOperationSupported, > + 0, > + &Supports > + ); > + if (EFI_ERROR (Status)) { > + goto Error; > + } > + > + Supports &=3D (EFI_PCI_IO_ATTRIBUTE_VGA_IO | > EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); > + if (Supports =3D=3D 0 || Supports =3D=3D (EFI_PCI_IO_ATTRIBUTE_VGA_IO = | > EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) { > + Status =3D EFI_UNSUPPORTED; > + goto Error; > + } > + > + // > + // Save original PCI attributes > + // > + Status =3D Private->PciIo->Attributes ( > + Private->PciIo, > + EfiPciIoAttributeOperationGet, > + 0, > + &Private->OriginalPciAttributes > + ); > + > + if (EFI_ERROR (Status)) { > + goto Error; > + } > + PciAttributesSaved =3D TRUE; > + > + Status =3D 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 =3D gBS->HandleProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + (VOID **) &ParentDevicePath > + ); > + if (EFI_ERROR (Status)) { > + goto Error; > + } > + > + if (FeaturePcdGet (PcdSupportGop)) { > + // > + // Set Gop Device Path > + // > + if (RemainingDevicePath =3D=3D NULL) { > + ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH)); > + AcpiDeviceNode.Header.Type =3D ACPI_DEVICE_PATH; > + AcpiDeviceNode.Header.SubType =3D ACPI_ADR_DP; > + AcpiDeviceNode.ADR =3D 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 =3D 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 =3D AppendDevicePathNode (ParentDevicePath, > RemainingDevicePath); > + } else { > + // > + // If RemainingDevicePath is the End of Device Path Node, > + // don't create child device and return EFI_SUCCESS > + // > + Private->GopDevicePath =3D NULL; > + } > + > + if (Private->GopDevicePath !=3D NULL) { > + // > + // Creat child handle and device path protocol firstly > + // > + Private->Handle =3D NULL; > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &Private->Handle, > + &gEfiDevicePathProtocolGuid, > + Private->GopDevicePath, > + NULL > + ); > + } > + } > + > + // > + // Construct video mode buffer > + // > + Status =3D CirrusLogic5430VideoModeSetup (Private); > + if (EFI_ERROR (Status)) { > + goto Error; > + } > + > + if (FeaturePcdGet (PcdSupportUga)) { > + // > + // Start the UGA Draw software stack. > + // > + Status =3D CirrusLogic5430UgaDrawConstructor (Private); > + ASSERT_EFI_ERROR (Status); > + > + Private->UgaDevicePath =3D ParentDevicePath; > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &Controller, > + &gEfiUgaDrawProtocolGuid, > + &Private->UgaDraw, > + &gEfiDevicePathProtocolGuid, > + Private->UgaDevicePath, > + NULL > + ); > + > + } else if (FeaturePcdGet (PcdSupportGop)) { > + if (Private->GopDevicePath =3D=3D NULL) { > + // > + // If RemainingDevicePath is the End of Device Path Node, > + // don't create child device and return EFI_SUCCESS > + // > + Status =3D EFI_SUCCESS; > + } else { > + > + // > + // Start the GOP software stack. > + // > + Status =3D CirrusLogic5430GraphicsOutputConstructor (Private); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D 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 =3D EFI_UNSUPPORTED; > + } > + > + > +Error: > + if (EFI_ERROR (Status)) { > + if (Private) { > + if (Private->PciIo) { > + if (PciAttributesSaved =3D=3D 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 =3D 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 =3D 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 =3D gBS->UninstallMultipleProtocolInterfaces ( > + Private->Handle, > + &gEfiUgaDrawProtocolGuid, > + &Private->UgaDraw, > + &gEfiGraphicsOutputProtocolGuid, > + &Private->GraphicsOutput, > + NULL > + ); > + } else { > + // > + // Remove the UGA Draw interface from the system > + // > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > + Private->Handle, > + &gEfiUgaDrawProtocolGuid, > + &Private->UgaDraw, > + NULL > + ); > + } > + } else { > + Status =3D 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 =3D > CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS > (GraphicsOutput); > + > + CirrusLogic5430GraphicsOutputDestructor (Private); > + // > + // Remove the GOP protocol interface from the system > + // > + Status =3D 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 =3D 0; > + for (RedIndex =3D 0; RedIndex < 8; RedIndex++) { > + for (GreenIndex =3D 0; GreenIndex < 8; GreenIndex++) { > + for (BlueIndex =3D 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 =3D 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 =3D 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 =3D 0; Index < 15; Index++) { > + outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]); > + } > + > + if (DeviceId !=3D CIRRUS_LOGIC_5446_DEVICE_ID) { > + outb (Private, SEQ_ADDRESS_REGISTER, 0x0f); > + Byte =3D (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 =3D 0; Index < 28; Index++) { > + outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData- > >CrtcSettings[Index] << 8) | Index)); > + } > + > + for (Index =3D 0; Index < 9; Index++) { > + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) > ((GraphicsController[Index] << 8) | Index)); > + } > + > + inb (Private, INPUT_STATUS_1_REGISTER); > + > + for (Index =3D 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 =3D 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 =3D PcdGet32 > (PcdDriverSupportedEfiVersion); > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &ImageHandle, > + &gEfiDriverSupportedEfiVersionProtocolGuid, > + &gCirrusLogic5430DriverSupportedEfiVersion, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > diff --git a/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h > new file mode 100644 > index 0000000000..355f0418b3 > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430.h > @@ -0,0 +1,432 @@ > +/** @file > + Cirrus Logic 5430 Controller Driver > + > + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +// > +// Cirrus Logic 5430 Controller Driver > +// > + > +#ifndef _CIRRUS_LOGIC_5430_H_ > +#define _CIRRUS_LOGIC_5430_H_ > + > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +// > +// 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 drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf > new file mode 100644 > index 0000000000..3e8b7b087f > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430Dxe.inf > @@ -0,0 +1,84 @@ > +## @file > +# Component description file for CirrusLogic5430 module > +# > +# Cirrus Logic 5430 Controller Driver.This driver is a sample implementa= tion > +# of the UGA Draw Protocol for the Cirrus Logic 5430 family of PCI vide= o > controllers. > +# This driver is only usable in the EFI pre-boot environment. This samp= le 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 - 2018, Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D CirrusLogic5430Dxe > + FILE_GUID =3D 555F76EA-785F-40d7-9174-153C43636C6= 8 > + MODULE_TYPE =3D UEFI_DRIVER > + VERSION_STRING =3D 1.0 > + > + ENTRY_POINT =3D InitializeCirrusLogic5430 > + > + PCI_VENDOR_ID =3D 0x1013 > + PCI_DEVICE_ID =3D 0x00A8 > + PCI_CLASS_CODE =3D 0x030000 > + PCI_REVISION =3D 0x00 > + PCI_COMPRESS =3D TRUE > + > +# > +# The following information is for reference only and not required by th= e > build tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 EBC > +# > +# DRIVER_BINDING =3D gCirrusLogic5430DriverBinding > +# COMPONENT_NAME =3D 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/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutpu > t.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutp > ut.c > new file mode 100644 > index 0000000000..b74d84b131 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430GraphicsOutp > ut.c > @@ -0,0 +1,556 @@ > +/** @file > +Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +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 > + > + > +STATIC > +VOID > +CirrusLogic5430CompleteModeInfo ( > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info > + ) > +{ > + Info->Version =3D 0; > + Info->PixelFormat =3D PixelBitMask; > + Info->PixelInformation.RedMask =3D PIXEL_RED_MASK; > + Info->PixelInformation.GreenMask =3D PIXEL_GREEN_MASK; > + Info->PixelInformation.BlueMask =3D PIXEL_BLUE_MASK; > + Info->PixelInformation.ReservedMask =3D 0; > + Info->PixelsPerScanLine =3D 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 =3D Mode->Info; > + CirrusLogic5430CompleteModeInfo (Info); > + > + Private->PciIo->GetBarAttributes ( > + Private->PciIo, > + 0, > + NULL, > + (VOID**) &FrameBufDesc > + ); > + > + Mode->FrameBufferBase =3D FrameBufDesc->AddrRangeMin; > + Mode->FrameBufferSize =3D 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 informa= tion 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 SetMo= de () > + EFI_INVALID_PARAMETER - One of the input args was NULL. > + > +--*/ > +{ > + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; > + > + Private =3D > CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This); > + > + if (Private->HardwareNeedsStarting) { > + return EFI_NOT_STARTED; > + } > + > + if (Info =3D=3D NULL || SizeOfInfo =3D=3D NULL || ModeNumber >=3D This= ->Mode- > >MaxMode) { > + return EFI_INVALID_PARAMETER; > + } > + > + *Info =3D AllocatePool (sizeof > (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); > + if (*Info =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + *SizeOfInfo =3D sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); > + > + (*Info)->HorizontalResolution =3D Private- > >ModeData[ModeNumber].HorizontalResolution; > + (*Info)->VerticalResolution =3D 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 th= e > request. > + EFI_UNSUPPORTED - ModeNumber is not supported by this device. > + > +--*/ > +{ > + CIRRUS_LOGIC_5430_PRIVATE_DATA *Private; > + CIRRUS_LOGIC_5430_MODE_DATA *ModeData; > + > + Private =3D > CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This); > + > + if (ModeNumber >=3D This->Mode->MaxMode) { > + return EFI_UNSUPPORTED; > + } > + > + ModeData =3D &Private->ModeData[ModeNumber]; > + > + if (Private->LineBuffer) { > + gBS->FreePool (Private->LineBuffer); > + } > + > + Private->LineBuffer =3D NULL; > + Private->LineBuffer =3D AllocatePool (ModeData->HorizontalResolution); > + if (Private->LineBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[ModeData- > >ModeNumber]); > + > + This->Mode->Mode =3D ModeNumber; > + This->Mode->Info->HorizontalResolution =3D ModeData- > >HorizontalResolution; > + This->Mode->Info->VerticalResolution =3D ModeData->VerticalResolution; > + This->Mode->SizeOfInfo =3D > sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); > + > + CirrusLogic5430CompleteModeData (Private, This->Mode); > + > + Private->HardwareNeedsStarting =3D 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 de= vice > + > +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 pixel= s > + Height - The height of a rectangle in the blt rectangle in pixe= ls > + Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo op= eration. > + 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 =3D > CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This); > + > + if ((UINT32)BltOperation >=3D EfiGraphicsOutputBltOperationMax) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Width =3D=3D 0 || Height =3D=3D 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 i= s Width > pixels size, > + // the number of bytes in each row can be computed. > + // > + if (Delta =3D=3D 0) { > + Delta =3D 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 r= ow of > + // the image. > + // > + > + CurrentMode =3D 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 =3D=3D 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 fram= e > buffer. > + // We would not want a timer based event (Cursor, ...) to come in whil= e > we are > + // doing this operation. > + // > + OriginalTPL =3D gBS->RaiseTPL (TPL_NOTIFY); > + > + switch (BltOperation) { > + case EfiBltVideoToBltBuffer: > + // > + // Video to BltBuffer: Source is Video, destination is BltBuffer > + // > + for (SrcY =3D SourceY, DstY =3D DestinationY; DstY < (Height + Desti= nationY); > SrcY++, DstY++) { > + > + Offset =3D (SrcY * Private->ModeData[CurrentMode].HorizontalResolu= tion) > + SourceX; > + if (((Offset & 0x03) =3D=3D 0) && ((Width & 0x03) =3D=3D 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 =3D 0; X < Width; X++) { > + Blt =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) Blt= Buffer + > (DstY * Delta) + (DestinationX + X) * sizeof > (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); > + > + Blt->Red =3D PIXEL_TO_RED_BYTE (Private->LineBuffer[X]); > + Blt->Green =3D PIXEL_TO_GREEN_BYTE (Private->LineBuffer[X]); > + Blt->Blue =3D PIXEL_TO_BLUE_BYTE (Private->LineBuffer[X]); > + } > + } > + break; > + > + case EfiBltVideoToVideo: > + // > + // Perform hardware acceleration for Video to Video operations > + // > + ScreenWidth =3D Private->ModeData[CurrentMode].HorizontalResolutio= n; > + SourceOffset =3D (SourceY * Private- > >ModeData[CurrentMode].HorizontalResolution) + (SourceX); > + Offset =3D (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) =3D=3D 0x01) > + ; > + break; > + > + case EfiBltVideoFill: > + Blt =3D BltBuffer; > + Pixel =3D RGB_BYTES_TO_PIXEL (Blt->Red, Blt->Green, Blt->Blue); > + WidePixel =3D (Pixel << 8) | Pixel; > + WidePixel =3D (WidePixel << 16) | WidePixel; > + > + if (DestinationX =3D=3D 0 && Width =3D=3D Private- > >ModeData[CurrentMode].HorizontalResolution) { > + Offset =3D DestinationY * Private- > >ModeData[CurrentMode].HorizontalResolution; > + if (((Offset & 0x03) =3D=3D 0) && (((Width * Height) & 0x03) =3D= =3D 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 =3D SourceY, DstY =3D DestinationY; SrcY < (Height + Sou= rceY); > SrcY++, DstY++) { > + Offset =3D (DstY * Private- > >ModeData[CurrentMode].HorizontalResolution) + DestinationX; > + if (((Offset & 0x03) =3D=3D 0) && ((Width & 0x03) =3D=3D 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 =3D SourceY, DstY =3D DestinationY; SrcY < (Height + Sourc= eY); > SrcY++, DstY++) { > + > + for (X =3D 0; X < Width; X++) { > + Blt =3D > + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ( > + (UINT8 *) BltBuffer + > + (SrcY * Delta) + > + ((SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) > + ); > + Private->LineBuffer[X] =3D > + RGB_BYTES_TO_PIXEL (Blt->Red, Blt->Green, Blt->Blue); > + } > + > + Offset =3D (DstY * Private->ModeData[CurrentMode].HorizontalResolu= tion) > + DestinationX; > + > + if (((Offset & 0x03) =3D=3D 0) && ((Width & 0x03) =3D=3D 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 =3D &Private->GraphicsOutput; > + GraphicsOutput->QueryMode =3D > CirrusLogic5430GraphicsOutputQueryMode; > + GraphicsOutput->SetMode =3D CirrusLogic5430GraphicsOutputSetMode; > + GraphicsOutput->Blt =3D CirrusLogic5430GraphicsOutputBlt; > + > + // > + // Initialize the private data > + // > + Status =3D gBS->AllocatePool ( > + EfiBootServicesData, > + sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), > + (VOID **) &Private->GraphicsOutput.Mode > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + Status =3D gBS->AllocatePool ( > + EfiBootServicesData, > + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), > + (VOID **) &Private->GraphicsOutput.Mode->Info > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + Private->GraphicsOutput.Mode->MaxMode =3D (UINT32) Private->MaxMode; > + Private->GraphicsOutput.Mode->Mode =3D > GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; > + Private->HardwareNeedsStarting =3D TRUE; > + Private->LineBuffer =3D 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 !=3D NULL) { > + if (Private->GraphicsOutput.Mode->Info !=3D NULL) { > + gBS->FreePool (Private->GraphicsOutput.Mode->Info); > + } > + gBS->FreePool (Private->GraphicsOutput.Mode); > + } > + > + return EFI_SUCCESS; > +} > + > + > diff --git a/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c > new file mode 100644 > index 0000000000..0cec8670b7 > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.c > @@ -0,0 +1,427 @@ > +/** @file > + I2C Bus implementation upon CirrusLogic. > + > + Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 C= lock 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 =3D (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << B= it)) ; > + Byte =3D (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 =3D 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 =3D 0; > + // > + // Read byte data from I2C Bus > + // > + for (Index =3D 0; Index < 8; Index --) { > + I2cPinWrite (PciIo, I2CCLK_OUT, 1); > + I2cDelay (); > + Data =3D (UINT8) (Data << 1); > + Data =3D (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) =3D=3D 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 !=3D 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) =3D=3D FALSE) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Send register address > + // > + I2cSendByte (PciIo, RegisterAddress); > + > + // > + // Wait for ACK signal > + // > + if (I2cWaitAck (PciIo) =3D=3D FALSE) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Send slave address with enabling read flag > + // > + I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01)); > + > + // > + // Wait for ACK signal > + // > + if (I2cWaitAck (PciIo) =3D=3D FALSE) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Read byte data from I2C Bus > + // > + *Data =3D 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 !=3D NULL); > + > + I2cStart (PciIo); > + // > + // Send slave address with enabling write flag > + // > + I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe)); > + > + // > + // Wait for ACK signal > + // > + if (I2cWaitAck (PciIo) =3D=3D FALSE) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Send register address > + // > + I2cSendByte (PciIo, RegisterAddress); > + > + // > + // Wait for ACK signal > + // > + if (I2cWaitAck (PciIo) =3D=3D FALSE) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Send byte data onto I2C Bus > + // > + I2cSendByte (PciIo, *Data); > + > + // > + // Wait for ACK signal > + // > + if (I2cWaitAck (PciIo) =3D=3D FALSE) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Stop a I2C transfer > + // > + I2cStop (PciIo); > + > + return EFI_SUCCESS; > +} > + > + > + > diff --git a/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h > new file mode 100644 > index 0000000000..505575cc99 > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430I2c.h > @@ -0,0 +1,62 @@ > +/** @file > + I2c Bus byte read/write functions. > + > + Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _CIRRUS_LOGIC_I2C_H_ > +#define _CIRRUS_LOGIC_I2C_H_ > + > +#include > + > +/** > + 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/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c > new file mode 100644 > index 0000000000..bdcbd3450c > --- /dev/null > +++ > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/CirrusLogic5430UgaDraw.c > @@ -0,0 +1,412 @@ > +/** @file > + This file produces the graphics abstration of UGA Draw. It is called b= y > + 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.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 =3D CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS > (This); > + > + if (Private->HardwareNeedsStarting) { > + return EFI_NOT_STARTED; > + } > + > + if ((HorizontalResolution =3D=3D NULL) || > + (VerticalResolution =3D=3D NULL) || > + (ColorDepth =3D=3D NULL) || > + (RefreshRate =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + *HorizontalResolution =3D Private->ModeData[Private- > >CurrentMode].HorizontalResolution; > + *VerticalResolution =3D Private->ModeData[Private- > >CurrentMode].VerticalResolution; > + *ColorDepth =3D Private->ModeData[Private- > >CurrentMode].ColorDepth; > + *RefreshRate =3D 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 =3D CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS > (This); > + > + for (Index =3D 0; Index < Private->MaxMode; Index++) { > + > + if (HorizontalResolution !=3D Private- > >ModeData[Index].HorizontalResolution) { > + continue; > + } > + > + if (VerticalResolution !=3D Private->ModeData[Index].VerticalResolut= ion) { > + continue; > + } > + > + if (ColorDepth !=3D Private->ModeData[Index].ColorDepth) { > + continue; > + } > + > + if (RefreshRate !=3D Private->ModeData[Index].RefreshRate) { > + continue; > + } > + > + if (Private->LineBuffer) { > + gBS->FreePool (Private->LineBuffer); > + } > + > + Private->LineBuffer =3D NULL; > + Private->LineBuffer =3D AllocatePool (HorizontalResolution); > + if (Private->LineBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[Private- > >ModeData[Index].ModeNumber]); > + > + Private->CurrentMode =3D Index; > + > + Private->HardwareNeedsStarting =3D 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 =3D CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS > (This); > + > + if ((UINT32)BltOperation >=3D EfiUgaBltMax) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (Width =3D=3D 0 || Height =3D=3D 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 i= s Width > pixels size, > + // the number of bytes in each row can be computed. > + // > + if (Delta =3D=3D 0) { > + Delta =3D 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 r= ow 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 =3D=3D 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 fram= e > buffer. > + // We would not want a timer based event (Cursor, ...) to come in whil= e > we are > + // doing this operation. > + // > + OriginalTPL =3D gBS->RaiseTPL (TPL_NOTIFY); > + > + switch (BltOperation) { > + case EfiUgaVideoToBltBuffer: > + // > + // Video to BltBuffer: Source is Video, destination is BltBuffer > + // > + for (SrcY =3D SourceY, DstY =3D DestinationY; DstY < (Height + Desti= nationY); > SrcY++, DstY++) { > + > + Offset =3D (SrcY * Private->ModeData[Private- > >CurrentMode].HorizontalResolution) + SourceX; > + if (((Offset & 0x03) =3D=3D 0) && ((Width & 0x03) =3D=3D 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 =3D 0; X < Width; X++) { > + Blt =3D (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (DstY *= Delta) + > (DestinationX + X) * sizeof (EFI_UGA_PIXEL)); > + > + Blt->Red =3D (UINT8) (Private->LineBuffer[X] & 0xe0); > + Blt->Green =3D (UINT8) ((Private->LineBuffer[X] & 0x1c) << 3); > + Blt->Blue =3D (UINT8) ((Private->LineBuffer[X] & 0x03) << 6); > + } > + } > + break; > + > + case EfiUgaVideoToVideo: > + // > + // Perform hardware acceleration for Video to Video operations > + // > + ScreenWidth =3D Private->ModeData[Private- > >CurrentMode].HorizontalResolution; > + SourceOffset =3D (SourceY * Private->ModeData[Private- > >CurrentMode].HorizontalResolution) + (SourceX); > + Offset =3D (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) =3D=3D 0x01) > + ; > + break; > + > + case EfiUgaVideoFill: > + Blt =3D BltBuffer; > + Pixel =3D (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c= ) | ((Blt- > >Blue >> 6) & 0x03)); > + WidePixel =3D (Pixel << 8) | Pixel; > + WidePixel =3D (WidePixel << 16) | WidePixel; > + > + if (DestinationX =3D=3D 0 && Width =3D=3D Private->ModeData[Private- > >CurrentMode].HorizontalResolution) { > + Offset =3D DestinationY * Private->ModeData[Private- > >CurrentMode].HorizontalResolution; > + if (((Offset & 0x03) =3D=3D 0) && (((Width * Height) & 0x03) =3D= =3D 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 =3D SourceY, DstY =3D DestinationY; SrcY < (Height + Sou= rceY); > SrcY++, DstY++) { > + Offset =3D (DstY * Private->ModeData[Private- > >CurrentMode].HorizontalResolution) + DestinationX; > + if (((Offset & 0x03) =3D=3D 0) && ((Width & 0x03) =3D=3D 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 =3D SourceY, DstY =3D DestinationY; SrcY < (Height + Sourc= eY); > SrcY++, DstY++) { > + > + for (X =3D 0; X < Width; X++) { > + Blt =3D (EFI_UGA_PIXEL *) ((UINT8 *) BltBuff= er + (SrcY * Delta) > + (SourceX + X) * sizeof (EFI_UGA_PIXEL)); > + Private->LineBuffer[X] =3D (UINT8) ((Blt->Red & 0xe0) | ((Blt->= Green >> 3) > & 0x1c) | ((Blt->Blue >> 6) & 0x03)); > + } > + > + Offset =3D (DstY * Private->ModeData[Private- > >CurrentMode].HorizontalResolution) + DestinationX; > + > + if (((Offset & 0x03) =3D=3D 0) && ((Width & 0x03) =3D=3D 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 =3D &Private->UgaDraw; > + > + UgaDraw->GetMode =3D CirrusLogic5430UgaDrawGetMode; > + UgaDraw->SetMode =3D CirrusLogic5430UgaDrawSetMode; > + UgaDraw->Blt =3D CirrusLogic5430UgaDrawBlt; > + > + // > + // Initialize the private data > + // > + Private->CurrentMode =3D 0; > + Private->HardwareNeedsStarting =3D TRUE; > + Private->LineBuffer =3D 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/Drivers/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c > new file mode 100644 > index 0000000000..3792937bed > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/ComponentName.c > @@ -0,0 +1,203 @@ > +/** @file > + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "CirrusLogic5430.h" > + > +// > +// EFI Component Name Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME_PROTOCOL gCirrusLogic5430ComponentName =3D { > + CirrusLogic5430ComponentNameGetDriverName, > + CirrusLogic5430ComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME2_PROTOCOL gCirrusLogic5430ComponentName2 =3D > { > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) > CirrusLogic5430ComponentNameGetDriverName, > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) > CirrusLogic5430ComponentNameGetControllerName, > + "en" > +}; > + > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mCirrusLogic5430DriverNameTable[] =3D { > + { "eng;en", L"Cirrus Logic 5430 Driver" }, > + { NULL , NULL } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mCirrusLogic5430ControllerNameTable[] =3D { > + { "eng;en", L"Cirrus Logic 5430 PCI Adapter" }, > + { NULL , NULL } > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 =3D=3D &gCirrusLogic5430ComponentName) > + ); > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 !=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Make sure this driver is currently managing ControllHandle > + // > + Status =3D 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 =3D=3D &gCirrusLogic5430ComponentName) > + ); > +} > diff --git > a/Drivers/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c > new file mode 100644 > index 0000000000..2d8412bf53 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/DriverSupportedEfiVersion.c > @@ -0,0 +1,14 @@ > +/** @file > + Copyright (c) 2007, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > + Module Name: DriverSupportEfiVersion.c > + > +**/ > +#include "CirrusLogic5430.h" > + > +EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL > gCirrusLogic5430DriverSupportedEfiVersion =3D { > + sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of > Protocol structure. > + 0 // Version number = to be filled at start up. > +}; > + > diff --git a/Drivers/OptionRomPkg/CirrusLogic5430Dxe/Edid.c > b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/Edid.c > new file mode 100644 > index 0000000000..5f288d219e > --- /dev/null > +++ b/Drivers/OptionRomPkg/CirrusLogic5430Dxe/Edid.c > @@ -0,0 +1,525 @@ > +/** @file > + Read EDID information and parse EDID information. > + > + Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "CirrusLogic5430.h" > +#include "CirrusLogic5430I2c.h" > + > +// > +// EDID block > +// > +typedef struct { > + UINT8 Header[8]; //EDID header "00 FF FF FF F= F 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 Gy= 1Gy0 > + UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy= 1 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-b= yte 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[] =3D { > + // > + // 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 =3D 0; Index < EDID_BLOCK_SIZE * 2; Index ++) { > + I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]); > + } > + > + // > + // Search for the EDID signature > + // > + ValidEdid =3D &EdidData[0]; > + Signature =3D 0x00ffffffffffff00ull; > + for (Index =3D 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++)= { > + if (CompareMem (ValidEdid, &Signature, 8) =3D=3D 0) { > + break; > + } > + } > + > + if (Index =3D=3D 256) { > + // > + // No EDID signature found > + // > + return EFI_UNSUPPORTED; > + } > + > + *EdidDataBlock =3D AllocateCopyPool ( > + EDID_BLOCK_SIZE, > + ValidEdid > + ); > + if (*EdidDataBlock =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Currently only support EDID 1.x > + // > + *EdidSize =3D 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 =3D (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 =3D CalculateEdidKey (EdidTiming); > + > + for (Index =3D 0; Index < ValidEdidTiming->ValidNumber; Index ++) { > + if (Key =3D=3D 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 =3D (EDID_BLOCK *) EdidBuffer; > + > + // > + // Check the checksum of EDID data > + // > + CheckSum =3D 0; > + for (Index =3D 0; Index < EDID_BLOCK_SIZE; Index ++) { > + CheckSum =3D (UINT8) (CheckSum + EdidBuffer[Index]); > + } > + if (CheckSum !=3D 0) { > + return FALSE; > + } > + > + ValidNumber =3D 0; > + SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0); > + > + if ((EdidDataBlock->EstablishedTimings[0] !=3D 0) || > + (EdidDataBlock->EstablishedTimings[1] !=3D 0) || > + (EdidDataBlock->EstablishedTimings[2] !=3D 0) > + ) { > + // > + // Established timing data > + // > + TimingBits =3D EdidDataBlock->EstablishedTimings[0] | > + (EdidDataBlock->EstablishedTimings[1] << 8) | > + ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ; > + for (Index =3D 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; > Index ++) { > + if (TimingBits & 0x1) { > + ValidEdidTiming->Key[ValidNumber] =3D CalculateEdidKey > (&mVbeEstablishedEdidTiming[Index]); > + ValidNumber ++; > + } > + TimingBits =3D TimingBits >> 1; > + } > + } else { > + // > + // If no Established timing data, read the standard timing data > + // > + BufferIndex =3D &EdidDataBlock->StandardTimingIdentification[0]; > + for (Index =3D 0; Index < 8; Index ++) { > + if ((BufferIndex[0] !=3D 0x1) && (BufferIndex[1] !=3D 0x1)){ > + // > + // A valid Standard Timing > + // > + HorizontalResolution =3D (UINT16) (BufferIndex[0] * 8 + 248); > + AspectRatio =3D (UINT8) (BufferIndex[1] >> 6); > + switch (AspectRatio) { > + case 0: > + VerticalResolution =3D (UINT16) (HorizontalResolution / 16 *= 10); > + break; > + case 1: > + VerticalResolution =3D (UINT16) (HorizontalResolution / 4 * = 3); > + break; > + case 2: > + VerticalResolution =3D (UINT16) (HorizontalResolution / 5 * = 4); > + break; > + case 3: > + VerticalResolution =3D (UINT16) (HorizontalResolution / 16 *= 9); > + break; > + default: > + VerticalResolution =3D (UINT16) (HorizontalResolution / 4 * = 3); > + break; > + } > + RefreshRate =3D (UINT8) ((BufferIndex[1] & 0x1f) + 60); > + TempTiming.HorizontalResolution =3D HorizontalResolution; > + TempTiming.VerticalResolution =3D VerticalResolution; > + TempTiming.RefreshRate =3D RefreshRate; > + ValidEdidTiming->Key[ValidNumber] =3D CalculateEdidKey > (&TempTiming); > + ValidNumber ++; > + } > + BufferIndex +=3D 2; > + } > + } > + > + ValidEdidTiming->ValidNumber =3D 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 =3D NULL; > + Private->EdidDiscovered.SizeOfEdid =3D 0; > + Private->EdidActive.Edid =3D NULL; > + Private->EdidActive.SizeOfEdid =3D 0; > + > + EdidFound =3D FALSE; > + EdidOverrideFound =3D FALSE; > + EdidAttributes =3D 0xff; > + EdidOverrideDataSize =3D 0; > + EdidOverrideDataBlock =3D NULL; > + EdidActiveDataSize =3D 0; > + EdidActiveDataBlock =3D NULL; > + EdidDiscoveredDataBlock =3D NULL; > + > + // > + // Find EDID Override protocol firstly, this protocol is installed by = platform > if needed. > + // > + Status =3D gBS->LocateProtocol ( > + &gEfiEdidOverrideProtocolGuid, > + NULL, > + (VOID **) &EdidOverride > + ); > + if (!EFI_ERROR (Status)) { > + // > + // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to > avoid overflow > + // > + EdidOverrideDataBlock =3D AllocatePool (EDID_BLOCK_SIZE * 2); > + if (NULL =3D=3D EdidOverrideDataBlock) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + Status =3D EdidOverride->GetEdid ( > + EdidOverride, > + Private->Handle, > + &EdidAttributes, > + &EdidOverrideDataSize, > + (UINT8 **) &EdidOverrideDataBlock > + ); > + if (!EFI_ERROR (Status) && > + EdidAttributes =3D=3D 0 && > + EdidOverrideDataSize !=3D 0) { > + // > + // Succeeded to get EDID Override Data > + // > + EdidOverrideFound =3D TRUE; > + } > + } > + > + if (EdidOverrideFound !=3D TRUE || EdidAttributes =3D=3D > 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) =3D=3D EFI_SUCCESS) { > + Private->EdidDiscovered.SizeOfEdid =3D (UINT32) EdidDiscoveredData= Size; > + Private->EdidDiscovered.Edid =3D (UINT8 *) AllocateCopyPool ( > + EdidDiscovered= DataSize, > + EdidDiscovered= DataBlock > + >=20 > ); > + > + if (NULL =3D=3D Private->EdidDiscovered.Edid) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + EdidActiveDataSize =3D Private->EdidDiscovered.SizeOfEdid; > + EdidActiveDataBlock =3D Private->EdidDiscovered.Edid; > + > + EdidFound =3D TRUE; > + } > + } > + > + if (EdidFound !=3D TRUE && EdidOverrideFound =3D=3D TRUE) { > + EdidActiveDataSize =3D EdidOverrideDataSize; > + EdidActiveDataBlock =3D EdidOverrideDataBlock; > + EdidFound =3D TRUE; > + } > + > + if (EdidFound =3D=3D TRUE) { > + // > + // Parse EDID data structure to retrieve modes supported by monitor > + // > + if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) = =3D=3D > TRUE) { > + // > + // Copy EDID Override Data to EDID Active Data > + // > + Private->EdidActive.SizeOfEdid =3D (UINT32) EdidActiveDataSize; > + Private->EdidActive.Edid =3D (UINT8 *) AllocateCopyPool ( > + EdidActiveDataSize, > + EdidActiveDataBlock > + ); > + if (NULL =3D=3D Private->EdidActive.Edid) { > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + } > + } else { > + Private->EdidActive.SizeOfEdid =3D 0; > + Private->EdidActive.Edid =3D NULL; > + EdidFound =3D FALSE; > + } > + > + if (EdidFound) { > + // > + // Initialize the private mode data with the supported modes. > + // > + ValidModeCount =3D 0; > + ModeData =3D &Private->ModeData[0]; > + VideoMode =3D &CirrusLogic5430VideoModes[0]; > + for (Index =3D 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index++) { > + > + TimingMatch =3D TRUE; > + > + // > + // Check whether match with CirrusLogic5430 video mode > + // > + TempTiming.HorizontalResolution =3D (UINT16) VideoMode->Width; > + TempTiming.VerticalResolution =3D (UINT16) VideoMode->Height; > + TempTiming.RefreshRate =3D (UINT16) VideoMode->RefreshRat= e; > + if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) !=3D TRUE) { > + TimingMatch =3D FALSE; > + } > + > + // > + // Not export Mode 0x0 as GOP mode, this is not defined in spec. > + // > + if ((VideoMode->Width =3D=3D 0) || (VideoMode->Height =3D=3D 0)) { > + TimingMatch =3D FALSE; > + } > + > + if (TimingMatch) { > + ModeData->ModeNumber =3D Index; > + ModeData->HorizontalResolution =3D VideoMode->Width; > + ModeData->VerticalResolution =3D VideoMode->Height; > + ModeData->ColorDepth =3D VideoMode->ColorDept= h; > + ModeData->RefreshRate =3D VideoMode->RefreshRa= te; > + > + ModeData ++; > + ValidModeCount ++; > + } > + > + VideoMode ++; > + } > + > + Private->MaxMode =3D ValidModeCount; > + > + } else { > + // > + // If EDID information wasn't found > + // > + ModeData =3D &Private->ModeData[0]; > + VideoMode =3D &CirrusLogic5430VideoModes[0]; > + for (Index =3D 0; Index < CIRRUS_LOGIC_5430_MODE_COUNT; Index ++) { > + ModeData->ModeNumber =3D Index; > + ModeData->HorizontalResolution =3D VideoMode->Width; > + ModeData->VerticalResolution =3D VideoMode->Height; > + ModeData->ColorDepth =3D VideoMode->ColorDepth; > + ModeData->RefreshRate =3D VideoMode->RefreshRate= ; > + > + ModeData ++ ; > + VideoMode ++; > + } > + Private->MaxMode =3D CIRRUS_LOGIC_5430_MODE_COUNT; > + } > + > + if (EdidOverrideDataBlock !=3D NULL) { > + FreePool (EdidOverrideDataBlock); > + } > + > + return EFI_SUCCESS; > + > +Done: > + if (EdidOverrideDataBlock !=3D NULL) { > + FreePool (EdidOverrideDataBlock); > + } > + if (Private->EdidDiscovered.Edid !=3D NULL) { > + FreePool (Private->EdidDiscovered.Edid); > + } > + if (Private->EdidDiscovered.Edid !=3D NULL) { > + FreePool (Private->EdidActive.Edid); > + } > + > + return EFI_DEVICE_ERROR; > +} > diff --git a/Drivers/OptionRomPkg/Include/Library/BltLib.h > b/Drivers/OptionRomPkg/Include/Library/BltLib.h > new file mode 100644 > index 0000000000..48990a296d > --- /dev/null > +++ b/Drivers/OptionRomPkg/Include/Library/BltLib.h > @@ -0,0 +1,253 @@ > +/** @file > + Library for performing video blt operations > + > + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef __BLT_LIB__ > +#define __BLT_LIB__ > + > +#include > + > + > +/** > + 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 rec= tangle in > pixels > + @param[in] Height - The height of a rectangle in the blt re= ctangle in > pixels > + @param[in] Delta - Not used for EfiBltVideoFill and > EfiBltVideoToVideo operation. > + If a Delta of 0 is used, the entire Blt= Buffer will be > operated on. > + If a subrectangle of the BltBuffer is u= sed, then Delta > represents > + the number of bytes in a row of the Blt= Buffer. > + > + @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/Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c > b/Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c > new file mode 100644 > index 0000000000..520fac4c63 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.c > @@ -0,0 +1,744 @@ > +/** @file > + FrameBufferBltLib - Library to perform blt operations on a frame buffe= r. > + > + Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "PiDxe.h" > +#include > +#include > +#include > +#include > + > +#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 =3D 0; > + Masks =3D (UINT32*) BitMask; > + for (Loop =3D 0; Loop < 3; Loop++) { > + ASSERT ((Loop =3D=3D 3) || (Masks[Loop] !=3D 0)); > + ASSERT ((MergedMasks & Masks[Loop]) =3D=3D 0); > + mPixelShl[Loop] =3D HighBitSet32 (Masks[Loop]) - 23 + (Loop * 8); > + if (mPixelShl[Loop] < 0) { > + mPixelShr[Loop] =3D -mPixelShl[Loop]; > + mPixelShl[Loop] =3D 0; > + } else { > + mPixelShr[Loop] =3D 0; > + } > + MergedMasks =3D (UINT32) (MergedMasks | Masks[Loop]); > + DEBUG ((EFI_D_INFO, "%d: shl:%d shr:%d mask:%x\n", Loop, > mPixelShl[Loop], mPixelShr[Loop], Masks[Loop])); > + } > + MergedMasks =3D (UINT32) (MergedMasks | Masks[3]); > + > + ASSERT (MergedMasks !=3D 0); > + mBltLibBytesPerPixel =3D (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 =3D > + { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; > + STATIC EFI_PIXEL_BITMASK BgrPixelMasks =3D > + { 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 !=3D PixelBltOnly); > + return EFI_UNSUPPORTED; > + default: > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > + } > + mPixelFormat =3D FrameBufferInfo->PixelFormat; > + > + mBltLibFrameBuffer =3D (UINT8*) FrameBuffer; > + mBltLibWidthInPixels =3D (UINTN) FrameBufferInfo->HorizontalResolution= ; > + mBltLibHeight =3D (UINTN) FrameBufferInfo->VerticalResolution; > + mBltLibWidthInBytes =3D 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 rec= tangle in > pixels > + @param[in] Height - The height of a rectangle in the blt re= ctangle in > pixels > + @param[in] Delta - Not used for EfiBltVideoFill and > EfiBltVideoToVideo operation. > + If a Delta of 0 is used, the entire Blt= Buffer will be > operated on. > + If a subrectangle of the BltBuffer is u= sed, then Delta > represents > + the number of bytes in a row of the Blt= Buffer. > + > + @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 *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 =3D=3D 0 || Height =3D=3D 0) { > + DEBUG ((EFI_D_INFO, "VideoFill: Width or Height is 0\n")); > + return EFI_INVALID_PARAMETER; > + } > + > + WidthInBytes =3D Width * mBltLibBytesPerPixel; > + > + Uint32 =3D *(UINT32*) Color; > + WideFill =3D > + (UINT32) ( > + (((Uint32 << mPixelShl[0]) >> mPixelShr[0]) & mPixelBitMasks.Red= Mask) > | > + (((Uint32 << mPixelShl[1]) >> mPixelShr[1]) & > mPixelBitMasks.GreenMask) | > + (((Uint32 << mPixelShl[2]) >> mPixelShr[2]) & mPixelBitMasks.Blu= eMask) > + ); > + VDEBUG ((EFI_D_INFO, "VideoFill: color=3D0x%x, wide-fill=3D0x%x\n", Ui= nt32, > WideFill)); > + > + // > + // If the size of the pixel data evenly divides the sizeof > + // WideFill, then a wide fill operation can be used > + // > + UseWideFill =3D TRUE; > + if ((sizeof (WideFill) % mBltLibBytesPerPixel) =3D=3D 0) { > + for (X =3D mBltLibBytesPerPixel; X < sizeof (WideFill); X++) { > + ((UINT8*)&WideFill)[X] =3D ((UINT8*)&WideFill)[X % mBltLibBytesPer= Pixel]; > + } > + } else { > + // > + // If all the bytes in the pixel are the same value, then use > + // a wide fill operation. > + // > + for ( > + X =3D 1, Uint8 =3D ((UINT8*)&WideFill)[0]; > + X < mBltLibBytesPerPixel; > + X++) { > + if (Uint8 !=3D ((UINT8*)&WideFill)[X]) { > + UseWideFill =3D FALSE; > + break; > + } > + } > + if (UseWideFill) { > + SetMem ((VOID*) &WideFill, sizeof (WideFill), Uint8); > + } > + } > + > + if (UseWideFill && (DestinationX =3D=3D 0) && (Width =3D=3D > mBltLibWidthInPixels)) { > + VDEBUG ((EFI_D_INFO, "VideoFill (wide, one-shot)\n")); > + Offset =3D DestinationY * mBltLibWidthInPixels; > + Offset =3D mBltLibBytesPerPixel * Offset; > + BltMemDst =3D (VOID*) (mBltLibFrameBuffer + Offset); > + SizeInBytes =3D WidthInBytes * Height; > + if (SizeInBytes >=3D 8) { > + SetMem32 (BltMemDst, SizeInBytes & ~3, (UINT32) WideFill); > + SizeInBytes =3D SizeInBytes & 3; > + } > + if (SizeInBytes > 0) { > + SetMem (BltMemDst, SizeInBytes, (UINT8)(UINTN) WideFill); > + } > + } else { > + LineBufferReady =3D FALSE; > + for (DstY =3D DestinationY; DstY < (Height + DestinationY); DstY++) = { > + Offset =3D (DstY * mBltLibWidthInPixels) + DestinationX; > + Offset =3D mBltLibBytesPerPixel * Offset; > + BltMemDst =3D (VOID*) (mBltLibFrameBuffer + Offset); > + > + if (UseWideFill && (((UINTN) BltMemDst & 7) =3D=3D 0)) { > + VDEBUG ((EFI_D_INFO, "VideoFill (wide)\n")); > + SizeInBytes =3D WidthInBytes; > + if (SizeInBytes >=3D 8) { > + SetMem64 (BltMemDst, SizeInBytes & ~7, WideFill); > + SizeInBytes =3D 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 =3D 1; X < Width; ) { > + CopyMem( > + (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)), > + mBltLibLineBuffer, > + MIN (X, Width - X) * mBltLibBytesPerPixel > + ); > + X =3D X + MIN (X, Width - X); > + } > + LineBufferReady =3D 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 =3D=3D 0 || Height =3D=3D 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 i= s Width > pixels size, > + // the number of bytes in each row can be computed. > + // > + if (Delta =3D=3D 0) { > + Delta =3D Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); > + } > + > + WidthInBytes =3D Width * mBltLibBytesPerPixel; > + > + // > + // Video to BltBuffer: Source is Video, destination is BltBuffer > + // > + for (SrcY =3D SourceY, DstY =3D DestinationY; DstY < (Height + Destina= tionY); > SrcY++, DstY++) { > + > + Offset =3D (SrcY * mBltLibWidthInPixels) + SourceX; > + Offset =3D mBltLibBytesPerPixel * Offset; > + BltMemSrc =3D (VOID *) (mBltLibFrameBuffer + Offset); > + > + if (mPixelFormat =3D=3D PixelBlueGreenRedReserved8BitPerColor) { > + BltMemDst =3D > + (VOID *) ( > + (UINT8 *) BltBuffer + > + (DstY * Delta) + > + (DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) > + ); > + } else { > + BltMemDst =3D (VOID *) mBltLibLineBuffer; > + } > + > + CopyMem (BltMemDst, BltMemSrc, WidthInBytes); > + > + if (mPixelFormat !=3D PixelBlueGreenRedReserved8BitPerColor) { > + for (X =3D 0; X < Width; X++) { > + Blt =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) Blt= Buffer + > (DstY * Delta) + (DestinationX + X) * sizeof > (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); > + Uint32 =3D *(UINT32*) (mBltLibLineBuffer + (X * mBltLibBytesPerP= ixel)); > + *(UINT32*) Blt =3D > + (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 =3D=3D 0 || Height =3D=3D 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 i= s Width > pixels size, > + // the number of bytes in each row can be computed. > + // > + if (Delta =3D=3D 0) { > + Delta =3D Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); > + } > + > + WidthInBytes =3D Width * mBltLibBytesPerPixel; > + > + for (SrcY =3D SourceY, DstY =3D DestinationY; SrcY < (Height + SourceY= ); SrcY++, > DstY++) { > + > + Offset =3D (DstY * mBltLibWidthInPixels) + DestinationX; > + Offset =3D mBltLibBytesPerPixel * Offset; > + BltMemDst =3D (VOID*) (mBltLibFrameBuffer + Offset); > + > + if (mPixelFormat =3D=3D PixelBlueGreenRedReserved8BitPerColor) { > + BltMemSrc =3D (VOID *) ((UINT8 *) BltBuffer + (SrcY * Delta)); > + } else { > + for (X =3D 0; X < Width; X++) { > + Blt =3D > + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ( > + (UINT8 *) BltBuffer + > + (SrcY * Delta) + > + ((SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) > + ); > + Uint32 =3D *(UINT32*) Blt; > + *(UINT32*) (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)) =3D > + (UINT32) ( > + (((Uint32 << mPixelShl[0]) >> mPixelShr[0]) & > mPixelBitMasks.RedMask) | > + (((Uint32 << mPixelShl[1]) >> mPixelShr[1]) & > mPixelBitMasks.GreenMask) | > + (((Uint32 << mPixelShl[2]) >> mPixelShr[2]) & > mPixelBitMasks.BlueMask) > + ); > + } > + BltMemSrc =3D (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 =3D=3D 0 || Height =3D=3D 0) { > + return EFI_INVALID_PARAMETER; > + } > + > + WidthInBytes =3D Width * mBltLibBytesPerPixel; > + > + Offset =3D (SourceY * mBltLibWidthInPixels) + SourceX; > + Offset =3D mBltLibBytesPerPixel * Offset; > + BltMemSrc =3D (VOID *) (mBltLibFrameBuffer + Offset); > + > + Offset =3D (DestinationY * mBltLibWidthInPixels) + DestinationX; > + Offset =3D mBltLibBytesPerPixel * Offset; > + BltMemDst =3D (VOID *) (mBltLibFrameBuffer + Offset); > + > + LineStride =3D mBltLibWidthInBytes; > + if ((UINTN) BltMemDst > (UINTN) BltMemSrc) { > + LineStride =3D -LineStride; > + } > + > + while (Height > 0) { > + CopyMem (BltMemDst, BltMemSrc, WidthInBytes); > + > + BltMemSrc =3D (VOID*) ((UINT8*) BltMemSrc + LineStride); > + BltMemDst =3D (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 !=3D NULL) { > + *Width =3D mBltLibWidthInPixels; > + } > + if (Height !=3D NULL) { > + *Height =3D mBltLibHeight; > + } > + > + return EFI_SUCCESS; > +} > + > diff --git > a/Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf > b/Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf > new file mode 100644 > index 0000000000..7af8a1baa0 > --- /dev/null > +++ > b/Drivers/OptionRomPkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf > @@ -0,0 +1,29 @@ > +## @file > +# FrameBufferBltLib - Library to perform blt operations on a frame buff= er. > +# > +# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D FrameBufferBltLib > + FILE_GUID =3D 2a40f516-c852-4baa-b7a8-0e9ea090d65= 9 > + MODULE_TYPE =3D BASE > + VERSION_STRING =3D 1.0 > + LIBRARY_CLASS =3D BltLib > + > +[Sources.common] > + FrameBufferBltLib.c > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + > +[Packages] > + MdePkg/MdePkg.dec > + OptionRomPkg/OptionRomPkg.dec > + > diff --git a/Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.c > b/Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.c > new file mode 100644 > index 0000000000..f28affd26b > --- /dev/null > +++ b/Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.c > @@ -0,0 +1,449 @@ > +/** @file > + GopBltLib - Library to perform blt using the UEFI Graphics Output Prot= ocol. > + > + Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "PiDxe.h" > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +EFI_GRAPHICS_OUTPUT_PROTOCOL *mGop =3D 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 =3D gBS->LocateHandleBuffer ( > + ByProtocol, > + &gEfiGraphicsOutputProtocolGuid, > + NULL, > + &HandleCount, > + &HandleBuffer > + ); > + if (!EFI_ERROR (Status)) { > + for (Index =3D 0; Index < HandleCount; Index++) { > + Status =3D gBS->HandleProtocol ( > + HandleBuffer[Index], > + &gEfiGraphicsOutputProtocolGuid, > + (VOID*) &Gop > + ); > + if (!EFI_ERROR (Status) && > + (FrameBuffer =3D=3D (VOID*)(UINTN) Gop->Mode->FrameBufferBase)= ) { > + mGop =3D 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 rec= tangle in > pixels > + @param[in] Height - The height of a rectangle in the blt re= ctangle in > pixels > + @param[in] Delta - Not used for EfiBltVideoFill and > EfiBltVideoToVideo operation. > + If a Delta of 0 is used, the entire Blt= Buffer will be > operated on. > + If a subrectangle of the BltBuffer is u= sed, then Delta > represents > + the number of bytes in a row of the Blt= Buffer. > + > + @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 =3D=3D 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 rec= tangle in > pixels > + @param[in] Height - The height of a rectangle in the blt re= ctangle in > pixels > + @param[in] Delta - Not used for EfiBltVideoFill and > EfiBltVideoToVideo operation. > + If a Delta of 0 is used, the entire Blt= Buffer will be > operated on. > + If a subrectangle of the BltBuffer is u= sed, then Delta > represents > + the number of bytes in a row of the Blt= Buffer. > + > + @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 !=3D NULL); > + > + if (Width !=3D NULL) { > + *Width =3D mGop->Mode->Info->HorizontalResolution; > + } > + if (Height !=3D NULL) { > + *Height =3D mGop->Mode->Info->VerticalResolution; > + } > + > + return EFI_SUCCESS; > +} > + > diff --git a/Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.inf > b/Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.inf > new file mode 100644 > index 0000000000..c5559133f9 > --- /dev/null > +++ b/Drivers/OptionRomPkg/Library/GopBltLib/GopBltLib.inf > @@ -0,0 +1,31 @@ > +## @file > +# GopBltLib - Library to perform blt using the UEFI Graphics Output > Protocol. > +# > +# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D GopBltLib > + FILE_GUID =3D b75b91f0-a0b4-42fe-ba62-849027999b3= 9 > + MODULE_TYPE =3D BASE > + VERSION_STRING =3D 1.0 > + LIBRARY_CLASS =3D BltLib > + > +[Sources.common] > + GopBltLib.c > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + MemoryAllocationLib > + UefiBootServicesTableLib > + > +[Packages] > + MdePkg/MdePkg.dec > + OptionRomPkg/OptionRomPkg.dec > + > diff --git a/Drivers/OptionRomPkg/OptionRomPkg.dec > b/Drivers/OptionRomPkg/OptionRomPkg.dec > new file mode 100644 > index 0000000000..6881f3648e > --- /dev/null > +++ b/Drivers/OptionRomPkg/OptionRomPkg.dec > @@ -0,0 +1,41 @@ > +## @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.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + DEC_SPECIFICATION =3D 0x00010005 > + PACKAGE_NAME =3D OptionRomPkg > + PACKAGE_GUID =3D AA3865E8-7F30-4f59-8696-99F56010185= 2 > + PACKAGE_VERSION =3D 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 =3D { 0x1e43298f, 0x3478, 0x41a7, { 0xb5, > 0x77, 0x86, 0x6, 0x46, 0x35, 0xc7, 0x28 } } > + > +[PcdsFeatureFlag] > + > gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN| > 0x00010001 > + > gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEA > N|0x00010002 > + > gOptionRomPkgTokenSpaceGuid.PcdSupportGop|TRUE|BOOLEAN|0x00010 > 004 > + > gOptionRomPkgTokenSpaceGuid.PcdSupportUga|TRUE|BOOLEAN|0x000100 > 05 > + > +[PcdsFixedAtBuild, PcdsPatchableInModule] > + > gOptionRomPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion|0x0002000a > |UINT32|0x00010003 > + > diff --git a/Drivers/OptionRomPkg/OptionRomPkg.dsc > b/Drivers/OptionRomPkg/OptionRomPkg.dsc > new file mode 100644 > index 0000000000..bea64b585e > --- /dev/null > +++ b/Drivers/OptionRomPkg/OptionRomPkg.dsc > @@ -0,0 +1,113 @@ > +## @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 - 2018, Intel Corporation. All rights reserved.
> +# Copyright (c) 2016, Linaro Ltd. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +############################################################## > ################## > +# > +# Defines Section - statements that will be processed to create a Makefi= le. > +# > +############################################################## > ################## > +[Defines] > + PLATFORM_NAME =3D OptionRomPkg > + PLATFORM_GUID =3D C7B25F37-B1F4-4c46-99CB-3EA7DCF5FCD= C > + PLATFORM_VERSION =3D 0.1 > + DSC_SPECIFICATION =3D 0x00010005 > + OUTPUT_DIRECTORY =3D Build/OptionRomPkg > + SUPPORTED_ARCHITECTURES =3D IA32|X64|EBC|ARM|AARCH64 > + BUILD_TARGETS =3D DEBUG|RELEASE > + SKUID_IDENTIFIER =3D 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/Base > DebugPrintErrorLevelLib.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/BaseTimerLibNullTem > plate.inf > + > UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBo > otServicesTableLib.inf > + > UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/ > UefiRuntimeServicesTableLib.inf > + > UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntry > Point.inf > + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf > + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > + > MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemo > ryAllocationLib.inf > + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf > + > UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiA > pplicationEntryPoint.inf > + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf > + > +[LibraryClasses.AARCH64, LibraryClasses.ARM] > + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf > + > +[LibraryClasses.ARM] > + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.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 modu= les 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 re= quired > 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 firmwa= re > 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 > + OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf > + OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf > + > +[Components.IA32, Components.X64] > + OptionRomPkg/Application/BltLibSample/BltLibSample.inf > diff --git a/Drivers/OptionRomPkg/ReadMe.txt > b/Drivers/OptionRomPkg/ReadMe.txt > new file mode 100644 > index 0000000000..99f97896da > --- /dev/null > +++ b/Drivers/OptionRomPkg/ReadMe.txt > @@ -0,0 +1,17 @@ > +AtapiPassThru: > + For now, AtapiPassThru driver in this package is to test Scsi Bus supp= ort: > + ScsiBus driver should support both/either ScsiPassThru and > ExtScsiPassThru > + installed on a controller handle. > + > + AtapiPassThru driver in this package can selectively produce ScsiPassT= hru > + 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 th= e > GOP/UGA, > + Component Name (2), EFI driver supported Verison protocol. > + > +Build Validation: > +ICC IA32 X64 IPF > + > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/ComponentName.c > b/Drivers/OptionRomPkg/UndiRuntimeDxe/ComponentName.c > new file mode 100644 > index 0000000000..b310143271 > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/ComponentName.c > @@ -0,0 +1,359 @@ > +/** @file > + UEFI Component Name(2) protocol implementation for EFI UNDI32 > driver. > + > +Copyright (c) 2012, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > + > +#include "Undi32.h" > + > +// > +// EFI Component Name Functions > +// > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 =3D { > + UndiComponentNameGetDriverName, > + UndiComponentNameGetControllerName, > + "eng" > +}; > + > +// > +// EFI Component Name 2 Protocol > +// > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_COMPONENT_NAME2_PROTOCOL gUndiComponentName2 =3D { > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) > UndiComponentNameGetDriverName, > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) > UndiComponentNameGetControllerName, > + "en" > +}; > + > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mUndiDriverNameTable[] =3D { > + { > + "eng;en", > + L"UNDI32 Driver" > + }, > + { > + NULL, > + NULL > + } > +}; > + > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE > mUndiControllerNameTable[] =3D { > + { > + "eng;en", > + L"UNDI32 Controller" > + }, > + { > + NULL, > + NULL > + } > +}; > + > +/** > + Retrieves a Unicode string that is the user readable name of the drive= r. > + > + 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 na= me 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 str= ing > + array indicating the language. This is t= he > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied > + in RFC 4646 or ISO 639-2 language code f= ormat. > + > + @param DriverName[out] A pointer to the Unicode string to retur= n. > + 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 specif= ied by > + This and the language specified by Langu= age 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 =3D=3D &gUndiComponentName) > + ); > +} > + > +/** > + Retrieves a Unicode string that is the user readable name of the contr= oller > + that is being managed by a driver. > + > + This function retrieves the user readable name of the controller speci= fied > by > + ControllerHandle and ChildHandle in the form of a Unicode string. If t= he > + driver specified by This has a user readable name in the language spec= ified > 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 doe= s > 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 driv= er > + specified by This is managing. This han= dle > + specifies the controller whose name is t= o be > + returned. > + > + @param ChildHandle[in] The handle of the child controller to re= trieve > + the name of. This is an optional parame= ter 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 bu= s > + controller. It will not be NULL for a b= us > + driver that wishes to retrieve the name = of a > + child controller. > + > + @param Language[in] A pointer to a Null-terminated ASCII str= ing > + array indicating the language. This is = the > + language of the driver name that the cal= ler is > + requesting, and it must match one of the > + languages specified in SupportedLanguage= s. The > + number of languages supported by a drive= r is up > + to the driver writer. Language is specif= ied in > + RFC 4646 or ISO 639-2 language code form= at. > + > + @param ControllerName[out] A pointer to the Unicode string to retur= n. > + 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 d= river > + specified by This. > + > + @retval EFI_SUCCESS The Unicode string for the user readable= name > in > + the language specified by Language for t= he > + 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 curr= ently > + 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 !=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + // > + // Make sure this driver is currently managing ControllHandle > + // > + Status =3D EfiTestManagedDevice ( > + ControllerHandle, > + gUndiDriverBinding.DriverBindingHandle, > + &gEfiPciIoProtocolGuid > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Retrieve an instance of a produced protocol from ControllerHandle > + // > + Status =3D 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 =3D=3D &gUndiComponentName) > + ); > +} > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/Decode.c > b/Drivers/OptionRomPkg/UndiRuntimeDxe/Decode.c > new file mode 100644 > index 0000000000..b7a2d16bc6 > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/Decode.c > @@ -0,0 +1,1516 @@ > +/** @file > + Provides the basic UNID functions. > + > +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Undi32.h" > + > +// > +// Global variables defined in this file > +// > +UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] =3D { \ > + {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),U > NDI_Start },\ > + > {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UN > DI_Stop },\ > + > {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STAR > TED, UNDI_GetInitInfo },\ > + > {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_S > TARTED, UNDI_GetConfigInfo },\ > + > {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHEC > K),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 informat= ion > 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 informa= tion > which > + the UNDI driver is layering on.. > + > + @return None > + > +**/ > +VOID > +UNDI_GetState ( > + IN PXE_CDB *CdbPtr, > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + CdbPtr->StatFlags =3D (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 (depe= nding > + on the version) pointed to in the caller's CpbPtr. This seeds the Del= ay, > + 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 ca= ll > + 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 informa= tion > 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 !=3D PXE_STATFLAGS_GET_STATE_STOPPED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_ALREADY_STARTED; > + return ; > + } > + > + if (CdbPtr->CPBsize !=3D sizeof(PXE_CPB_START_30) && > + CdbPtr->CPBsize !=3D sizeof(PXE_CPB_START_31)) { > + > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + CpbPtr =3D (PXE_CPB_START_30 *) (UINTN) (CdbPtr->CPBaddr); > + CpbPtr_31 =3D (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr); > + > + if (AdapterInfo->VersionFlag =3D=3D 0x30) { > + AdapterInfo->Delay_30 =3D (bsptr_30) (UINTN) CpbPtr->Delay; > + AdapterInfo->Virt2Phys_30 =3D (virtphys_30) (UINTN) CpbPtr->Virt2Phy= s; > + AdapterInfo->Block_30 =3D (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 GlobalIoFn= cs 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 t= he i/o > + // and memory address is abstracted by the device specific PciIoFncs= and > + // UNDI only uses the offset values. Since UNDI3.0 cannot provide an= y > + // identification to SNP, SNP cannot use nic specific PciIoFncs call= back! > + // > + // 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 bu= gs) > + // > + // This TmpMemIo function also takes a UniqueId parameter > + // (as in undi3.1 design) and so initialize the UniqueId as well her= e > + // 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 =3D (mem_io_30) (UINTN) CpbPtr->Mem_IO; > + AdapterInfo->Mem_Io =3D (mem_io) (UINTN) TmpMemIo; > + AdapterInfo->Unique_ID =3D (UINT64) (UINTN) AdapterInfo; > + > + } else { > + AdapterInfo->Delay =3D (bsptr) (UINTN) CpbPtr_31->Delay; > + AdapterInfo->Virt2Phys =3D (virtphys) (UINTN) CpbPtr_31->Virt2Phys; > + AdapterInfo->Block =3D (block) (UINTN) CpbPtr_31->Block; > + AdapterInfo->Mem_Io =3D (mem_io) (UINTN) CpbPtr_31->Mem_IO; > + > + AdapterInfo->Map_Mem =3D (map_mem) (UINTN) CpbPtr_31- > >Map_Mem; > + AdapterInfo->UnMap_Mem =3D (unmap_mem) (UINTN) CpbPtr_31- > >UnMap_Mem; > + AdapterInfo->Sync_Mem =3D (sync_mem) (UINTN) CpbPtr_31->Sync_Mem; > + AdapterInfo->Unique_ID =3D CpbPtr_31->Unique_ID; > + } > + > + AdapterInfo->State =3D 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, po= inters > 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 informa= tion > which > + the UNDI driver is layering on.. > + > + @return None > + > +**/ > +VOID > +UNDI_Stop ( > + IN PXE_CDB *CdbPtr, > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + if (AdapterInfo->State =3D=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_NOT_SHUTDOWN; > + return ; > + } > + > + AdapterInfo->Delay_30 =3D 0; > + AdapterInfo->Virt2Phys_30 =3D 0; > + AdapterInfo->Block_30 =3D 0; > + > + AdapterInfo->Delay =3D 0; > + AdapterInfo->Virt2Phys =3D 0; > + AdapterInfo->Block =3D 0; > + > + AdapterInfo->Map_Mem =3D 0; > + AdapterInfo->UnMap_Mem =3D 0; > + AdapterInfo->Sync_Mem =3D 0; > + > + AdapterInfo->State =3D PXE_STATFLAGS_GET_STATE_STOPPED; > + > + return ; > +} > + > + > +/** > + This routine is used to retrieve the initialization information that i= s needed > by drivers and > + applications to initialize the UNDI. This will fill in data in the Da= ta Block > structure that is > + pointed to by the caller's CdbPtr->DBaddr. The fields filled in are a= s > follows: > + MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, > MediaHeaderLen, HWaddrLen, > + MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Dupl= ex, > 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 informa= tion > 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 =3D (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr); > + > + DbPtr->MemoryRequired =3D MEMORY_NEEDED; > + DbPtr->FrameDataLen =3D PXE_MAX_TXRX_UNIT_ETHER; > + DbPtr->LinkSpeeds[0] =3D 10; > + DbPtr->LinkSpeeds[1] =3D 100; > + DbPtr->LinkSpeeds[2] =3D DbPtr->LinkSpeeds[3] =3D 0; > + DbPtr->NvCount =3D MAX_EEPROM_LEN; > + DbPtr->NvWidth =3D 4; > + DbPtr->MediaHeaderLen =3D PXE_MAC_HEADER_LEN_ETHER; > + DbPtr->HWaddrLen =3D PXE_HWADDR_LEN_ETHER; > + DbPtr->MCastFilterCnt =3D MAX_MCAST_ADDRESS_CNT; > + > + DbPtr->TxBufCnt =3D TX_BUFFER_COUNT; > + DbPtr->TxBufSize =3D (UINT16) sizeof (TxCB); > + DbPtr->RxBufCnt =3D RX_BUFFER_COUNT; > + DbPtr->RxBufSize =3D (UINT16) sizeof (RxFD); > + > + DbPtr->IFtype =3D PXE_IFTYPE_ETHERNET; > + DbPtr->SupportedDuplexModes =3D > PXE_DUPLEX_ENABLE_FULL_SUPPORTED | > + PXE_DUPLEX_FORCE_FULL_SUPPORTED; > + DbPtr->SupportedLoopBackModes =3D > PXE_LOOPBACK_INTERNAL_SUPPORTED | > + PXE_LOOPBACK_EXTERNAL_SUPPORTED; > + > + CdbPtr->StatFlags |=3D (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED | > + PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED); > + return ; > +} > + > + > +/** > + This routine is used to retrieve the configuration information about t= he > 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 NI= C's > PCI configuration space. > + > + @param CdbPtr Pointer to the command descriptor block. > + @param AdapterInfo Pointer to the NIC data structure informa= tion > 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 =3D (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DB= addr); > + > + DbPtr->pci.BusType =3D PXE_BUSTYPE_PCI; > + DbPtr->pci.Bus =3D AdapterInfo->Bus; > + DbPtr->pci.Device =3D AdapterInfo->Device; > + DbPtr->pci.Function =3D AdapterInfo->Function; > + > + for (Index =3D 0; Index < MAX_PCI_CONFIG_LEN; Index++) { > + DbPtr->pci.Config.Dword[Index] =3D 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 wit= h > 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 informa= tion > 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 !=3D PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) && > + (CdbPtr->OpFlags !=3D > PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + // > + // check if it is already initialized > + // > + if (AdapterInfo->State =3D=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_ALREADY_INITIALIZED; > + return ; > + } > + > + CpbPtr =3D (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr; > + > + if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CPB; > + return ; > + } > + > + // > + // default behaviour is to detect the cable, if the 3rd param is 1, > + // do not do that > + // > + AdapterInfo->CableDetect =3D (UINT8) ((CdbPtr->OpFlags =3D=3D (UINT16) > PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1); > + AdapterInfo->LinkSpeedReq =3D (UINT16) CpbPtr->LinkSpeed; > + AdapterInfo->DuplexReq =3D CpbPtr->DuplexMode; > + AdapterInfo->LoopBack =3D CpbPtr->LoopBackMode; > + AdapterInfo->MemoryPtr =3D CpbPtr->MemoryAddr; > + AdapterInfo->MemoryLength =3D CpbPtr->MemoryLength; > + > + CdbPtr->StatCode =3D (PXE_STATCODE) E100bInit (AdapterInfo); > + > + if (CdbPtr->StatCode !=3D PXE_STATCODE_SUCCESS) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + } else { > + AdapterInfo->State =3D 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 informa= tion > which > + the UNDI driver is layering on.. > + > + @return None > + > +**/ > +VOID > +UNDI_Reset ( > + IN PXE_CDB *CdbPtr, > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + if (CdbPtr->OpFlags !=3D PXE_OPFLAGS_NOT_USED && > + CdbPtr->OpFlags !=3D PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS && > + CdbPtr->OpFlags !=3D PXE_OPFLAGS_RESET_DISABLE_FILTERS ) { > + > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + CdbPtr->StatCode =3D (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags= ); > + > + if (CdbPtr->StatCode !=3D PXE_STATCODE_SUCCESS) { > + CdbPtr->StatFlags =3D 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 filt= ers and > external > + interrupt enables are disabled. Once the UNDI has been shutdown, it c= an > 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 informa= tion > 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 =3D (UINT16) E100bShutdown (AdapterInfo); > + > + if (CdbPtr->StatCode !=3D PXE_STATCODE_SUCCESS) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + } else { > + AdapterInfo->State =3D 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 externa= l > (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 i= n the > CdbPtr->StatFlags. > + > + @param CdbPtr Pointer to the command descriptor block. > + @param AdapterInfo Pointer to the NIC data structure informa= tion > which > + the UNDI driver is layering on.. > + > + @return None > + > +**/ > +VOID > +UNDI_Interrupt ( > + IN PXE_CDB *CdbPtr, > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + UINT8 IntMask; > + > + IntMask =3D (UINT8)(UINTN)(CdbPtr->OpFlags & > (PXE_OPFLAGS_INTERRUPT_RECEIVE | > + PXE_OPFLAGS_INTERRUPT_TRAN= SMIT | > + PXE_OPFLAGS_INTERRUPT_COMM= AND | > + PXE_OPFLAGS_INTERRUPT_SOFT= WARE)); > + > + switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) { > + case PXE_OPFLAGS_INTERRUPT_READ: > + break; > + > + case PXE_OPFLAGS_INTERRUPT_ENABLE: > + if (IntMask =3D=3D 0) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + AdapterInfo->int_mask =3D IntMask; > + E100bSetInterruptState (AdapterInfo); > + break; > + > + case PXE_OPFLAGS_INTERRUPT_DISABLE: > + if (IntMask !=3D 0) { > + AdapterInfo->int_mask =3D (UINT16) (AdapterInfo->int_mask & > ~(IntMask)); > + E100bSetInterruptState (AdapterInfo); > + break; > + } > + > + // > + // else fall thru. > + // > + default: > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) !=3D 0) { > + CdbPtr->StatFlags |=3D PXE_STATFLAGS_INTERRUPT_RECEIVE; > + > + } > + > + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) !=3D 0) > { > + CdbPtr->StatFlags |=3D PXE_STATFLAGS_INTERRUPT_TRANSMIT; > + > + } > + > + if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) !=3D 0) > { > + CdbPtr->StatFlags |=3D PXE_STATFLAGS_INTERRUPT_COMMAND; > + > + } > + > + return ; > +} > + > + > +/** > + This routine is used to read and change receive filters and, if suppor= ted, > read > + and change multicast MAC address filter list. > + > + @param CdbPtr Pointer to the command descriptor block. > + @param AdapterInfo Pointer to the NIC data structure informa= tion > 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 =3D CdbPtr->OpFlags; > + NewFilter =3D (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 !=3D 0) || (CdbPtr->CPBsize !=3D 0)) { > + goto BadCdb; > + > + } > + > + if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) =3D=3D= 0) > { > + goto JustRead; > + > + } > + > + NewFilter =3D (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 =3D=3D 0) { > + // > + // nothing to enable > + // > + goto BadCdb; > + } > + > + if (CdbPtr->CPBsize !=3D 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) > =3D=3D 0) || > + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != =3D > 0) || > + ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) !=3D 0= ) > || > + ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) !=3D 0) ) { > + goto BadCdb; > + } > + > + MacAddr =3D (UINT8 *) ((UINTN) (CdbPtr->CPBaddr)); > + MacCount =3D 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 va= lid. > + // > + InvalidMacAddr =3D FALSE; > + > + for (; MacCount-- !=3D 0; MacAddr +=3D sizeof (PXE_MAC_ADDR)) { > + if (MacAddr[0] =3D=3D 0x01) { > + // > + // This multicast MAC address is mapped from IPv4 address. > + // > + if (MacAddr[1] !=3D 0x00 || MacAddr[2] !=3D 0x5E || (MacAddr[3= ] & > 0x80) !=3D 0) { > + InvalidMacAddr =3D TRUE; > + } > + } else if (MacAddr[0] =3D=3D 0x33) { > + // > + // This multicast MAC address is mapped from IPv6 address. > + // > + if (MacAddr[1] !=3D 0x33) { > + InvalidMacAddr =3D TRUE; > + } > + } else { > + InvalidMacAddr =3D TRUE; > + } > + > + if (InvalidMacAddr) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CPB; > + return ; > + } > + } > + } > + > + // > + // check selective mcast case enable case > + // > + if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=3D > 0) { > + if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) !=3D = 0) > || > + ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) !=3D 0) = ) { > + goto BadCdb; > + > + } > + // > + // if no cpb, make sure we have an old list > + // > + if ((CdbPtr->CPBsize =3D=3D 0) && (AdapterInfo->mcast_list.list_le= n =3D=3D 0)) { > + goto BadCdb; > + } > + } > + // > + // if you want to enable anything, you got to have unicast > + // and you have what you already enabled! > + // > + NewFilter =3D (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 !=3D PXE_CPBSIZE_NOT_USED) { > + goto BadCdb; > + } > + > + NewFilter =3D (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo- > >Rx_Filter); > + > + break; > + > + default: > + goto BadCdb; > + } > + > + if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) !=3D 0) { > + AdapterInfo->mcast_list.list_len =3D 0; > + NewFilter &=3D (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST); > + } > + > + E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr- > >CPBsize); > + > +JustRead: > + // > + // give the current mcast list > + // > + if ((CdbPtr->DBsize !=3D 0) && (AdapterInfo->mcast_list.list_len !=3D = 0)) { > + // > + // copy the mc list to db > + // > + > + DbPtr =3D (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr; > + ptr1 =3D (UINT8 *) (&DbPtr->MCastList[0]); > + > + // > + // DbPtr->mc_count =3D AdapterInfo->mcast_list.list_len; > + // > + copy_len =3D (UINT16) (AdapterInfo->mcast_list.list_len * > PXE_MAC_LENGTH); > + > + if (copy_len > CdbPtr->DBsize) { > + copy_len =3D CdbPtr->DBsize; > + > + } > + > + ptr2 =3D (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]); > + for (Index =3D 0; Index < copy_len; Index++) { > + ptr1[Index] =3D ptr2[Index]; > + } > + } > + // > + // give the stat flags here > + // > + if (AdapterInfo->Receive_Started) { > + CdbPtr->StatFlags =3D (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterIn= fo- > >Rx_Filter); > + > + } > + > + return ; > + > +BadCdb: > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D 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 informa= tion > 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 =3D=3D 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 > + ) !=3D 0) { > + for (Index =3D 0; Index < PXE_MAC_LENGTH; Index++) { > + AdapterInfo->CurrentNodeAddress[Index] =3D AdapterInfo- > >PermNodeAddress[Index]; > + } > + > + E100bSetupIAAddr (AdapterInfo); > + } > + } > + > + if (CdbPtr->CPBaddr !=3D (UINT64) 0) { > + CpbPtr =3D (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr); > + // > + // configure the new address > + // > + for (Index =3D 0; Index < PXE_MAC_LENGTH; Index++) { > + AdapterInfo->CurrentNodeAddress[Index] =3D CpbPtr->StationAddr[Ind= ex]; > + } > + > + E100bSetupIAAddr (AdapterInfo); > + } > + > + if (CdbPtr->DBaddr !=3D (UINT64) 0) { > + DbPtr =3D (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr); > + // > + // fill it with the new values > + // > + for (Index =3D 0; Index < PXE_MAC_LENGTH; Index++) { > + DbPtr->StationAddr[Index] =3D AdapterInfo->CurrentNodeAddress[In= dex]; > + DbPtr->BroadcastAddr[Index] =3D AdapterInfo- > >BroadcastNodeAddress[Index]; > + DbPtr->PermanentAddr[Index] =3D AdapterInfo- > >PermNodeAddress[Index]; > + } > + } > + > + return ; > +} > + > + > +/** > + This routine is used to read and clear the NIC traffic statistics. Th= is > 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 receiv= e > 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 transm= it > 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 o= n this > subnet) > + > + @param CdbPtr Pointer to the command descriptor block. > + @param AdapterInfo Pointer to the NIC data structure informa= tion > 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)) !=3D 0) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) !=3D 0) { > + // > + // Reset the statistics > + // > + CdbPtr->StatCode =3D (UINT16) E100bStatistics (AdapterInfo, 0, 0); > + } else { > + CdbPtr->StatCode =3D (UINT16) E100bStatistics (AdapterInfo, CdbPtr- > >DBaddr, CdbPtr->DBsize); > + } > + > + return ; > +} > + > + > +/** > + This routine is used to translate a multicast IP address to a multicas= t MAC > address. > + This results in a MAC address composed of 25 bits of fixed data with t= he > upper 23 bits of the IP > + address being appended to it. Results passed back in the equivalent o= f > CdbPtr->DBaddr->MAC[0-5]. > + > + @param CdbPtr Pointer to the command descriptor block. > + @param AdapterInfo Pointer to the NIC data structure informa= tion > 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 =3D (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr; > + DbPtr =3D (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr; > + > + if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) !=3D 0) { > + // > + // for now this is not supported > + // > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_UNSUPPORTED; > + return ; > + } > + > + TmpPtr =3D (UINT8 *) (&CpbPtr->IP.IPv4); > + // > + // check if the ip given is a mcast IP > + // > + if ((TmpPtr[0] & 0xF0) !=3D 0xE0) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D 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 acces= sing > + // the UINT32 content hung the system... > + // > + DbPtr->MAC[0] =3D 0x01; > + DbPtr->MAC[1] =3D 0x00; > + DbPtr->MAC[2] =3D 0x5e; > + DbPtr->MAC[3] =3D (UINT8) (TmpPtr[1] & 0x7f); > + DbPtr->MAC[4] =3D (UINT8) TmpPtr[2]; > + DbPtr->MAC[5] =3D (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 informa= tion > 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 =3D=3D PXE_OPFLAGS_NVDATA_READ) !=3D 0) { > + > + if ((CdbPtr->DBsize =3D=3D PXE_DBSIZE_NOT_USED) !=3D 0) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + DbPtr =3D (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr; > + > + for (Index =3D 0; Index < MAX_PCI_CONFIG_LEN; Index++) { > + DbPtr->Data.Dword[Index] =3D AdapterInfo->NVData[Index]; > + > + } > + > + } else { > + // > + // no write for now > + // > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_UNSUPPORTED; > + } > + > + return ; > +} > + > + > +/** > + This routine returns the current interrupt status and/or the transmitt= ed > buffer addresses. > + If the current interrupt status is returned, pending interrupts will b= e > 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 informa= tion > 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 =3D &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; > + > + if ((RxPtr->cb_header.status & RX_COMPLETE) !=3D 0) { > + TmpGetStatus.RxFrameLen =3D RxPtr->ActualCount & 0x3fff; > + } else { > + TmpGetStatus.RxFrameLen =3D 0; > + } > + > + TmpGetStatus.reserved =3D 0; > + > + // > + // Fill in size of next available receive packet and > + // reserved field in caller's DB storage. > + // > + DbPtr =3D (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) !=3D 0) > { > + // > + // DBsize of zero is invalid if Tx buffers are requested. > + // > + if (CdbPtr->DBsize =3D=3D 0) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + // > + // remember this b4 we overwrite > + // > + NumEntries =3D (UINT16) (CdbPtr->DBsize - sizeof (UINT64)); > + > + // > + // We already filled in 2 UINT32s. > + // > + CdbPtr->DBsize =3D (UINT16) (sizeof (UINT32) * 2); > + > + // > + // will claim any hanging free CBs > + // > + CheckCBList (AdapterInfo); > + > + if (AdapterInfo->xmit_done_head =3D=3D AdapterInfo->xmit_done_tail) = { > + CdbPtr->StatFlags |=3D > PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY; > + } else { > + for (Index =3D 0; ((Index < MAX_XMIT_BUFFERS) && (NumEntries >=3D = sizeof > (UINT64))); Index++, NumEntries -=3D sizeof (UINT64)) { > + if (AdapterInfo->xmit_done_head !=3D AdapterInfo->xmit_done_tail= ) { > + DbPtr->TxBuffer[Index] =3D AdapterInfo->xmit_done[Adapter= Info- > >xmit_done_head]; > + AdapterInfo->xmit_done_head =3D next (AdapterInfo- > >xmit_done_head); > + CdbPtr->DBsize +=3D sizeof (UINT64); > + } else { > + break; > + } > + } > + } > + > + if (AdapterInfo->xmit_done_head !=3D AdapterInfo->xmit_done_tail) { > + CdbPtr->StatFlags |=3D 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) !=3D 0) { > + > + Status =3D InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); > + AdapterInfo->Int_Status =3D (UINT16) (AdapterInfo->Int_Status | Stat= us); > + > + // > + // acknoledge the interrupts > + // > + OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) > (AdapterInfo->ioaddr + SCBStatus)); > + > + // > + // report all the outstanding interrupts > + // > + Status =3D AdapterInfo->Int_Status; > + if ((Status & SCB_STATUS_FR) !=3D 0) { > + CdbPtr->StatFlags |=3D PXE_STATFLAGS_GET_STATUS_RECEIVE; > + } > + > + if ((Status & SCB_STATUS_SWI) !=3D 0) { > + CdbPtr->StatFlags |=3D PXE_STATFLAGS_GET_STATUS_SOFTWARE; > + } > + } > + > + // > + // Return current media status > + // > + if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) !=3D 0) { > + AdapterInfo->PhyAddress =3D 0xFF; > + AdapterInfo->CableDetect =3D 1; > + > + if (!PhyDetect (AdapterInfo)) { > + CdbPtr->StatFlags |=3D 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 informa= tion > 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 =3D=3D PXE_CPBSIZE_NOT_USED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) !=3D 0) { > + Cpbf =3D (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr- > >CPBaddr; > + > + // > + // assume 1st fragment is big enough for the mac header > + // > + if ((Cpbf->FragCnt =3D=3D 0) || (Cpbf->FragDesc[0].FragLen < > PXE_MAC_HEADER_LEN_ETHER)) { > + // > + // no buffers given > + // > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + MacHeader =3D (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr; > + // > + // we don't swap the protocol bytes > + // > + MacHeader->type =3D Cpbf->Protocol; > + > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + MacHeader->dest_addr[Index] =3D Cpbf->DestAddr[Index]; > + MacHeader->src_addr[Index] =3D Cpbf->SrcAddr[Index]; > + } > + } else { > + Cpb =3D (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr; > + > + MacHeader =3D (EtherHeader *) (UINTN) Cpb->MediaHeader; > + // > + // we don't swap the protocol bytes > + // > + MacHeader->type =3D Cpb->Protocol; > + > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + MacHeader->dest_addr[Index] =3D Cpb->DestAddr[Index]; > + MacHeader->src_addr[Index] =3D Cpb->SrcAddr[Index]; > + } > + } > + > + return ; > +} > + > + > +/** > + This routine is used to place a packet into the transmit queue. The d= ata > buffers given to > + this command are to be considered locked and the application or networ= k > driver loses > + ownership of these buffers and must not free or relocate them until th= e > 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 ch= ecked > 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 linke= d 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 fragmen= ts > into a local buffer > + before transmitting. > + > + @param CdbPtr Pointer to the command descriptor block. > + @param AdapterInfo Pointer to the NIC data structure informa= tion > which > + the UNDI driver is layering on.. > + > + @return None > + > +**/ > +VOID > +UNDI_Transmit ( > + IN PXE_CDB *CdbPtr, > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + > + if (CdbPtr->CPBsize =3D=3D PXE_CPBSIZE_NOT_USED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + CdbPtr->StatCode =3D (PXE_STATCODE) E100bTransmit (AdapterInfo, > CdbPtr->CPBaddr, CdbPtr->OpFlags); > + > + if (CdbPtr->StatCode !=3D PXE_STATCODE_SUCCESS) { > + CdbPtr->StatFlags =3D 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 informa= tion > 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 =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; > + return ; > + } > + > + > + CdbPtr->StatCode =3D (UINT16) E100bReceive (AdapterInfo, CdbPtr- > >CPBaddr, CdbPtr->DBaddr); > + if (CdbPtr->StatCode !=3D PXE_STATCODE_SUCCESS) { > + CdbPtr->StatFlags =3D 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 informa= tion > which > + the UNDI driver is layering on.. > + > + @return None > + > +**/ > +// TODO: cdb - add argument and description to function comment > +VOID > +EFIAPI > +UNDI_APIEntry_new ( > + IN UINT64 cdb > + ) > +{ > + PXE_CDB *CdbPtr; > + NIC_DATA_INSTANCE *AdapterInfo; > + > + if (cdb =3D=3D (UINT64) 0) { > + return ; > + > + } > + > + CdbPtr =3D (PXE_CDB *) (UINTN) cdb; > + > + if (CdbPtr->IFnum >=3D (pxe_31->IFcnt | pxe_31->IFcntExt << 8) ) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_INVALID_CDB; > + return ; > + } > + > + AdapterInfo =3D &(UNDI32DeviceList[CdbPtr->IFnum]->NicIn= fo); > + // > + // entering from older entry point > + // > + AdapterInfo->VersionFlag =3D 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 informa= tion > 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 =3D (PXE_CDB *) (UINTN) cdb; > + > + // > + // check the OPCODE range > + // > + if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) || > + (CdbPtr->StatCode !=3D PXE_STATCODE_INITIALIZE) || > + (CdbPtr->StatFlags !=3D PXE_STATFLAGS_INITIALIZE) || > + (CdbPtr->IFnum >=3D (pxe_31->IFcnt | pxe_31->IFcntExt << 8))) { > + goto badcdb; > + > + } > + > + if (CdbPtr->CPBsize =3D=3D PXE_CPBSIZE_NOT_USED) { > + if (CdbPtr->CPBaddr !=3D PXE_CPBADDR_NOT_USED) { > + goto badcdb; > + } > + } else if (CdbPtr->CPBaddr =3D=3D PXE_CPBADDR_NOT_USED) { > + goto badcdb; > + } > + > + if (CdbPtr->DBsize =3D=3D PXE_DBSIZE_NOT_USED) { > + if (CdbPtr->DBaddr !=3D PXE_DBADDR_NOT_USED) { > + goto badcdb; > + } > + } else if (CdbPtr->DBaddr =3D=3D PXE_DBADDR_NOT_USED) { > + goto badcdb; > + } > + > + // > + // check if cpbsize and dbsize are as needed > + // check if opflags are as expected > + // > + tab_ptr =3D &api_table[CdbPtr->OpCode]; > + > + if (tab_ptr->cpbsize !=3D (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != =3D > CdbPtr->CPBsize) { > + goto badcdb; > + } > + > + if (tab_ptr->dbsize !=3D (UINT16) (DONT_CHECK) && tab_ptr->dbsize !=3D > CdbPtr->DBsize) { > + goto badcdb; > + } > + > + if (tab_ptr->opflags !=3D (UINT16) (DONT_CHECK) && tab_ptr->opflags != =3D > CdbPtr->OpFlags) { > + goto badcdb; > + > + } > + > + AdapterInfo =3D &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo); > + > + // > + // check if UNDI_State is valid for this call > + // > + if (tab_ptr->state !=3D (UINT16) (-1)) { > + // > + // should atleast be started > + // > + if (AdapterInfo->State =3D=3D PXE_STATFLAGS_GET_STATE_STOPPED) { > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D PXE_STATCODE_NOT_STARTED; > + return ; > + } > + // > + // check if it should be initialized > + // > + if (tab_ptr->state =3D=3D 2) { > + if (AdapterInfo->State !=3D PXE_STATFLAGS_GET_STATE_INITIALIZED) { > + CdbPtr->StatCode =3D PXE_STATCODE_NOT_INITIALIZED; > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + return ; > + } > + } > + } > + // > + // set the return variable for success case here > + // > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_COMPLETE; > + CdbPtr->StatCode =3D PXE_STATCODE_SUCCESS; > + > + tab_ptr->api_ptr (CdbPtr, AdapterInfo); > + return ; > + // > + // %% AVL - check for command linking > + // > +badcdb: > + CdbPtr->StatFlags =3D PXE_STATFLAGS_COMMAND_FAILED; > + CdbPtr->StatCode =3D 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 =3D (PxePtr->IFcnt | PxePtr->IFcntExt << 8); > + > + if (NicPtr =3D=3D NULL) { > + if (NicNum > 0) { > + // > + // number of NICs this undi supports > + // > + NicNum --; > + } > + goto done; > + } > + > + // > + // number of NICs this undi supports > + // > + NicNum++; > + > +done: > + PxePtr->IFcnt =3D (UINT8)(NicNum & 0xFF); > + PxePtr->IFcntExt =3D (UINT8) ((NicNum & 0xFF00) >> 8); > + PxePtr->Fudge =3D (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOID *) Pxe= Ptr, > 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 =3D PXE_ROMID_SIGNATURE; > + PxePtr->Len =3D (UINT8) sizeof (PXE_SW_UNDI); > + // > + // cksum > + // > + PxePtr->Fudge =3D 0; > + // > + // number of NICs this undi supports > + // > + PxePtr->IFcnt =3D 0; > + PxePtr->IFcntExt =3D 0; > + PxePtr->Rev =3D PXE_ROMID_REV; > + PxePtr->MajorVer =3D PXE_ROMID_MAJORVER; > + PxePtr->MinorVer =3D PXE_ROMID_MINORVER; > + PxePtr->reserved1 =3D 0; > + > + PxePtr->Implementation =3D 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 =3D (UINT64) (UINTN) UNDI_APIEntry_new; > + PxePtr->MinorVer =3D PXE_ROMID_MINORVER_31; > + > + PxePtr->reserved2[0] =3D 0; > + PxePtr->reserved2[1] =3D 0; > + PxePtr->reserved2[2] =3D 0; > + PxePtr->BusCnt =3D 1; > + PxePtr->BusType[0] =3D PXE_BUSTYPE_PCI; > + > + PxePtr->Fudge =3D (UINT8) (PxePtr->Fudge - CalculateSum8 ((VOI= D *) > PxePtr, PxePtr->Len)); > +} > + > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.c > b/Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.c > new file mode 100644 > index 0000000000..199f5430ad > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.c > @@ -0,0 +1,3541 @@ > +/** @file > + Provides basic function upon network adapter card. > + > +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Undi32.h" > + > +UINT8 basic_config_cmd[22] =3D { > + 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=3DForce full-duple= x > + 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 =3D 2000; \ > + while ((InByte (AdapterInfo, cmd_ioaddr) !=3D 0) && --wait_count >=3D = 0) \ > + DelayIt (AdapterInfo, 10); \ > + if (wait_count =3D=3D 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 =3D 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 =3D 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 devic= e'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 =3D 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 =3D (UINT64 *) (UINTN) MappedAddr; > + // > + // mapping is different for theold and new NII protocols > + // > + if (AdapterInfo->VersionFlag =3D=3D 0x30) { > + if (AdapterInfo->Virt2Phys_30 =3D=3D (VOID *) NULL) { > + *PhyAddr =3D (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 =3D=3D (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 =3D 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 !=3D (VOID *) NULL) { > + (*AdapterInfo->UnMap_Mem) ( > + AdapterInfo->Unique_ID, > + MemAddr, > + Size, > + Direction, > + MappedAddr > + ); > + > + } > + } > + > + return ; > +} > + > + > +/** > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver is > + layering on.. > + > + > +**/ > +// TODO: MicroSeconds - add argument and description to function > comment > +VOID > +DelayIt ( > + IN NIC_DATA_INSTANCE *AdapterInfo, > + UINT16 MicroSeconds > + ) > +{ > + if (AdapterInfo->VersionFlag =3D=3D 0x30) { > + (*AdapterInfo->Delay_30) (MicroSeconds); > + } else { > + (*AdapterInfo->Delay) (AdapterInfo->Unique_ID, MicroSeconds); > + } > +} > + > + > +/** > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver is > + layering on.. > + > + > +**/ > +// TODO: flag - add argument and description to function comment > +VOID > +BlockIt ( > + IN NIC_DATA_INSTANCE *AdapterInfo, > + UINT32 flag > + ) > +{ > + if (AdapterInfo->VersionFlag =3D=3D 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 regist= ers > + // with 0's so that the entire physical address is our offset > + // > + // > + // we reset the statistics totals here because this is where we are lo= ading > stats addr > + // > + AdapterInfo->RxTotals =3D 0; > + AdapterInfo->TxTotals =3D 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 =3D 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 =3D 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) !=3D 0) { > + OutWord (AdapterInfo, SCB_STATUS_CNA, AdapterInfo->ioaddr + > SCBStatus); > + > + } > + > + if ((status & SCB_STATUS_CU_MASK) =3D=3D 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 &=3D > ~(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 =3D GetFreeCB (AdapterInfo); > + ASSERT (cmd_ptr !=3D NULL); > + data_ptr =3D (UINT8 *) cmd_ptr + sizeof (struct CB_Header); > + > + // > + // start the config data right after the command header > + // > + for (Index =3D 0; Index < sizeof (basic_config_cmd); Index++) { > + data_ptr[Index] =3D basic_config_cmd[Index]; > + } > + > + my_filter =3D (UINT8) ((AdapterInfo->Rx_Filter & > PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS) ? 1 : 0); > + my_filter =3D (UINT8) (my_filter | ((AdapterInfo->Rx_Filter & > PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST) ? 0 : 2)); > + > + data_ptr[15] =3D (UINT8) (data_ptr[15] | my_filter); > + data_ptr[19] =3D (UINT8) (AdapterInfo->Duplex ? 0xC0 : 0x80); > + data_ptr[21] =3D (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) !=3D 0) { > + data_ptr[15] |=3D 0x80; > + data_ptr[8] =3D 0; > + } > + > + BlockIt (AdapterInfo, TRUE); > + cmd_ptr->cb_header.command =3D 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 =3D cmd_ptr->PhysArrayAddr; > + cmd_ptr->ByteCount =3D cmd_ptr->Threshold =3D cmd_ptr->TBDCount =3D 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 =3D (UINT16 *) AdapterInfo->CurrentNodeAddress; > + > + cmd_ptr =3D GetFreeCB (AdapterInfo); > + ASSERT (cmd_ptr !=3D NULL); > + data_ptr =3D (UINT16 *) ((UINT8 *) cmd_ptr +sizeof (struct CB_Header)= ); > + > + // > + // AVOID a bug (?!) here by marking the command already completed. > + // > + cmd_ptr->cb_header.command =3D (CmdSuspend | CmdIASetup); > + cmd_ptr->cb_header.status =3D 0; > + data_ptr[0] =3D eaddrs[0]; > + data_ptr[1] =3D eaddrs[1]; > + data_ptr[2] =3D 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 =3D cmd_ptr->PhysArrayAddr; > + cmd_ptr->ByteCount =3D cmd_ptr->Threshold =3D cmd_ptr->TBDCount =3D 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 struct= ure > + information which the UNDI dri= ver 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 =3D FALSE; > + } > + > + return ; > +} > + > + > +/** > + Instructs the NIC to start receiving packets. > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver 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 =3D 0; > + AdapterInfo->Int_Status =3D 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 =3D 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 struct= ure > + information which the UNDI dri= ver 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 =3D MapIt ( > + AdapterInfo, > + AdapterInfo->MemoryPtr, > + AdapterInfo->MemoryLength, > + TO_AND_FROM_DEVICE, > + (UINT64)(UINTN) &AdapterInfo->Mapped_MemoryPtr > + ); > + > + if (stat !=3D 0) { > + return stat; > + } > + > + CfgHdr =3D (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]); > + > + // > + // fill in the ioaddr, int... from the config space > + // > + AdapterInfo->int_num =3D CfgHdr->int_line; > + > + // > + // we don't need to validate integer number, what if they don't want t= o > assign one? > + // if (AdapterInfo->int_num =3D=3D 0 || AdapterInfo->int_num =3D=3D 0x= ff) > + // return PXE_STATCODE_DEVICE_FAILURE; > + // > + AdapterInfo->ioaddr =3D 0; > + AdapterInfo->VendorID =3D CfgHdr->VendorID; > + AdapterInfo->DeviceID =3D CfgHdr->DeviceID; > + AdapterInfo->RevID =3D CfgHdr->RevID; > + AdapterInfo->SubVendorID =3D CfgHdr->SubVendorID; > + AdapterInfo->SubSystemID =3D CfgHdr->SubSystemID; > + AdapterInfo->flash_addr =3D 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) !=3D 0) { > + return PXE_STATCODE_DEVICE_FAILURE; > + > + } > + // > + // ## calculate the buffer #s depending on memory given > + // ## calculate the rx and tx ring pointers > + // > + > + AdapterInfo->TxBufCnt =3D TX_BUFFER_COUNT; > + AdapterInfo->RxBufCnt =3D RX_BUFFER_COUNT; > + rx_size =3D (AdapterInfo->RxBufCnt * sizeof (RxFD)= ); > + tx_size =3D (AdapterInfo->TxBufCnt * sizeof (TxCB)= ); > + AdapterInfo->rx_ring =3D (RxFD *) (UINTN) (AdapterInfo->MemoryP= tr); > + AdapterInfo->tx_ring =3D (TxCB *) (UINTN) (AdapterInfo->MemoryP= tr + > rx_size); > + AdapterInfo->statistics =3D (struct speedo_stats *) (UINTN) (Adapt= erInfo- > >MemoryPtr + rx_size + tx_size); > + > + AdapterInfo->rx_phy_addr =3D AdapterInfo->Mapped_MemoryPtr; > + AdapterInfo->tx_phy_addr =3D AdapterInfo->Mapped_MemoryPtr + > rx_size; > + AdapterInfo->stat_phy_addr =3D AdapterInfo->tx_phy_addr + tx_size; > + > + // > + // auto detect. > + // > + AdapterInfo->PhyAddress =3D 0xFF; > + AdapterInfo->Rx_Filter =3D > PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; > + AdapterInfo->Receive_Started =3D FALSE; > + AdapterInfo->mcast_list.list_len =3D 0; > + return InitializeChip (AdapterInfo); > +} > + > + > +/** > + Sets the interrupt state for the NIC. > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver 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) !=3D 0) { > + cmd_word =3D InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd); > + cmd_word &=3D ~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) !=3D 0) > { > + // > + // reset the bit in our mask, it is only one time!! > + // > + AdapterInfo->int_mask &=3D ~(PXE_OPFLAGS_INTERRUPT_SOFTWARE); > + cmd_word =3D InWord (AdapterInfo, AdapterInfo->ioaddr + SCBCmd); > + cmd_word |=3D 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 struct= ure > + information which the UNDI dri= ver 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 =3D (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 =3D AdapterInfo->Rx_Filter; > + > + // > + // only these bits need a change in the configuration > + // actually change in bcast requires configure but we ignore that chan= ge > + // > + cfg_flt =3D PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS | > + PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; > + > + if ((old_filter & cfg_flt) !=3D (new_filter & cfg_flt)) { > + XmitWaitForCompletion (AdapterInfo); > + > + if (AdapterInfo->Receive_Started) { > + StopRU (AdapterInfo); > + } > + > + AdapterInfo->Rx_Filter =3D (UINT8) (new_filter | > PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST); > + Configure (AdapterInfo); > + } > + > + // > + // check if mcast setting changed > + // > + if ( ((new_filter & > PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=3D > + (old_filter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) ) > || > + (mc_list !=3D NULL) ) { > + > + > + if (mc_list !=3D NULL) { > + mc_count =3D AdapterInfo->mcast_list.list_len =3D (UINT16) (cpbsiz= e / > PXE_MAC_LENGTH); > + > + for (Index =3D 0; (Index < mc_count && Index < > MAX_MCAST_ADDRESS_CNT); Index++) { > + for (Index2 =3D 0; Index2 < PXE_MAC_LENGTH; Index2++) { > + AdapterInfo->mcast_list.mc_list[Index][Index2] =3D mc_list- > >MCastList[Index][Index2]; > + } > + } > + } > + > + // > + // are we setting the list or resetting?? > + // > + if ((new_filter & > PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) !=3D 0) { > + // > + // we are setting a new list! > + // > + mc_count =3D AdapterInfo->mcast_list.list_len; > + // > + // count should be the actual # of bytes in the list > + // so multiply this with 6 > + // > + mc_byte_cnt =3D (UINT16) ((mc_count << 2) + (mc_count << 1)); > + AdapterInfo->Rx_Filter |=3D > PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST; > + } else { > + // > + // disabling the list in the NIC. > + // > + mc_byte_cnt =3D mc_count =3D 0; > + AdapterInfo->Rx_Filter &=3D > (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST); > + } > + > + // > + // before issuing any new command! > + // > + XmitWaitForCompletion (AdapterInfo); > + > + if (AdapterInfo->Receive_Started) { > + StopRU (AdapterInfo); > + > + } > + > + cmd_ptr =3D GetFreeCB (AdapterInfo); > + if (cmd_ptr =3D=3D NULL) { > + return PXE_STATCODE_QUEUE_FULL; > + } > + // > + // fill the command structure and issue > + // > + data_ptr =3D (struct MC_CB_STRUCT *) (&cmd_ptr->PhysTBDArrayAddres); > + // > + // first 2 bytes are the count; > + // > + data_ptr->count =3D mc_byte_cnt; > + for (Index =3D 0; Index < mc_count; Index++) { > + for (Index2 =3D 0; Index2 < PXE_HWADDR_LEN_ETHER; Index2++) { > + data_ptr->m_list[Index][Index2] =3D AdapterInfo- > >mcast_list.mc_list[Index][Index2]; > + } > + } > + > + cmd_ptr->cb_header.command =3D CmdSuspend | CmdMulticastList; > + cmd_ptr->cb_header.status =3D 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 =3D cmd_ptr->PhysArrayAddr; > + cmd_ptr->ByteCount =3D cmd_ptr->Threshold =3D cmd_ptr->TBDCount =3D = 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 !=3D 0) { > + // > + // enable unicast and start the RU > + // > + AdapterInfo->Rx_Filter =3D (UINT8) (AdapterInfo->Rx_Filter | (new_fi= lter | > PXE_OPFLAGS_RECEIVE_FILTER_UNICAST)); > + StartRU (AdapterInfo); > + } else { > + // > + // may be disabling everything! > + // > + if (AdapterInfo->Receive_Started) { > + StopRU (AdapterInfo); > + } > + > + AdapterInfo->Rx_Filter |=3D (~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 =3D (PXE_CPB_TRANSMIT *) (UINTN) cpb; > + tx_ptr_f =3D (PXE_CPB_TRANSMIT_FRAGMENTS *) (UINTN) cpb; > + Tmp_ptr =3D 0; > + > + // > + // stop reentrancy here > + // > + if (AdapterInfo->in_transmit) { > + return PXE_STATCODE_BUSY; > + > + } > + > + AdapterInfo->in_transmit =3D TRUE; > + > + // > + // Prevent interrupts from changing the Tx ring from underneath us. > + // > + // Calculate the Tx descriptor entry. > + // > + if ((tcb_ptr =3D GetFreeCB (AdapterInfo)) =3D=3D NULL) { > + AdapterInfo->in_transmit =3D FALSE; > + return PXE_STATCODE_QUEUE_FULL; > + } > + > + AdapterInfo->TxTotals++; > + > + tcb_ptr->cb_header.command =3D (CmdSuspend | CmdTx | CmdTxFlex); > + tcb_ptr->cb_header.status =3D 0; > + > + // > + // no immediate data, set EOF in the ByteCount > + // > + tcb_ptr->ByteCount =3D 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 =3D 32; > + if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) !=3D 0) { > + > + if (tx_ptr_f->FragCnt > MAX_XMIT_FRAGMENTS) { > + SetFreeCB (AdapterInfo, tcb_ptr); > + AdapterInfo->in_transmit =3D FALSE; > + return PXE_STATCODE_INVALID_PARAMETER; > + } > + > + tcb_ptr->TBDCount =3D (UINT8) tx_ptr_f->FragCnt; > + > + for (Index =3D 0; Index < tx_ptr_f->FragCnt; Index++) { > + stat =3D MapIt ( > + AdapterInfo, > + tx_ptr_f->FragDesc[Index].FragAddr, > + tx_ptr_f->FragDesc[Index].FragLen, > + TO_DEVICE, > + (UINT64)(UINTN) &Tmp_ptr > + ); > + if (stat !=3D 0) { > + SetFreeCB (AdapterInfo, tcb_ptr); > + AdapterInfo->in_transmit =3D FALSE; > + return PXE_STATCODE_INVALID_PARAMETER; > + } > + > + tcb_ptr->TBDArray[Index].phys_buf_addr =3D (UINT32) Tmp_ptr; > + tcb_ptr->TBDArray[Index].buf_len =3D tx_ptr_f- > >FragDesc[Index].FragLen; > + } > + > + tcb_ptr->free_data_ptr =3D tx_ptr_f->FragDesc[0].FragAddr; > + > + } else { > + // > + // non fragmented case > + // > + tcb_ptr->TBDCount =3D 1; > + stat =3D MapIt ( > + AdapterInfo, > + tx_ptr_1->FrameAddr, > + tx_ptr_1->DataLen + tx_ptr_1->MediaheaderLen, > + TO_DEVICE, > + (UINT64)(UINTN) &Tmp_ptr > + ); > + if (stat !=3D 0) { > + SetFreeCB (AdapterInfo, tcb_ptr); > + AdapterInfo->in_transmit =3D FALSE; > + return PXE_STATCODE_INVALID_PARAMETER; > + } > + > + tcb_ptr->TBDArray[0].phys_buf_addr =3D (UINT32) (Tmp_ptr); > + tcb_ptr->TBDArray[0].buf_len =3D tx_ptr_1->DataLen + tx_ptr_1= - > >MediaheaderLen; > + tcb_ptr->free_data_ptr =3D 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) !=3D 0) { > + // > + // don't wait for more than 1 second!!! > + // > + wait_sec =3D 1000; > + while (tcb_ptr->cb_header.status =3D=3D 0) { > + DelayIt (AdapterInfo, 10); > + wait_sec--; > + if (wait_sec =3D=3D 0) { > + break; > + } > + } > + // > + // we need to un-map any mapped buffers here > + // > + if ((opflags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) !=3D 0) { > + > + for (Index =3D 0; Index < tx_ptr_f->FragCnt; Index++) { > + Tmp_ptr =3D 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 =3D 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 =3D=3D 0) { > + SetFreeCB (AdapterInfo, tcb_ptr); > + AdapterInfo->in_transmit =3D 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 =3D 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 =3D PXE_STATCODE_NO_DATA; > + pkt_type =3D PXE_FRAME_TYPE_NONE; > + status =3D InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); > + AdapterInfo->Int_Status =3D (UINT16) (AdapterInfo->Int_Status | status= ); > + // > + // acknoledge the interrupts > + // > + OutWord (AdapterInfo, (UINT16) (status & 0xfc00), (UINT32) (AdapterInf= o- > >ioaddr + SCBStatus)); > + > + // > + // include the prev ints as well > + // > + status =3D AdapterInfo->Int_Status; > + rx_cpbptr =3D (PXE_CPB_RECEIVE *) (UINTN) cpb; > + rx_dbptr =3D (PXE_DB_RECEIVE *) (UINTN) db; > + > + rx_ptr =3D &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; > + > + // > + // be in a loop just in case (we may drop a pkt) > + // > + while ((status =3D 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) !=3D 0) { > + goto FreeRFD; > + > + } > + > + // > + // make sure the status is OK > + // > + if ((status & 0x02000) =3D=3D 0) { > + goto FreeRFD; > + } > + > + pkt_len =3D (UINT16) (rx_ptr->ActualCount & 0x3fff); > + > + if (pkt_len !=3D 0) { > + > + Tmp_len =3D pkt_len; > + if (pkt_len > rx_cpbptr->BufferLen) { > + Tmp_len =3D (UINT16) rx_cpbptr->BufferLen; > + } > + > + CopyMem ((INT8 *) (UINTN) rx_cpbptr->BufferAddr, (INT8 *) &rx_ptr- > >RFDBuffer, Tmp_len); > + > + hdr_ptr =3D (EtherHeader *) &rx_ptr->RFDBuffer; > + // > + // fill the CDB and break the loop > + // > + > + // > + // includes header > + // > + rx_dbptr->FrameLen =3D pkt_len; > + rx_dbptr->MediaHeaderLen =3D PXE_MAC_HEADER_LEN_ETHER; > + > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + if (hdr_ptr->dest_addr[Index] !=3D AdapterInfo- > >CurrentNodeAddress[Index]) { > + break; > + } > + } > + > + if (Index >=3D PXE_HWADDR_LEN_ETHER) { > + pkt_type =3D PXE_FRAME_TYPE_UNICAST; > + } else { > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + if (hdr_ptr->dest_addr[Index] !=3D AdapterInfo- > >BroadcastNodeAddress[Index]) { > + break; > + } > + } > + > + if (Index >=3D PXE_HWADDR_LEN_ETHER) { > + pkt_type =3D PXE_FRAME_TYPE_BROADCAST; > + } else { > + if ((hdr_ptr->dest_addr[0] & 1) =3D=3D 1) { > + // > + // mcast > + // > + > + pkt_type =3D PXE_FRAME_TYPE_FILTERED_MULTICAST; > + } else { > + pkt_type =3D PXE_FRAME_TYPE_PROMISCUOUS; > + } > + } > + } > + > + rx_dbptr->Type =3D pkt_type; > + rx_dbptr->Protocol =3D hdr_ptr->type; > + > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + rx_dbptr->SrcAddr[Index] =3D hdr_ptr->src_addr[Index]; > + rx_dbptr->DestAddr[Index] =3D hdr_ptr->dest_addr[Index]; > + } > + > + rx_ptr->forwarded =3D TRUE; > + // > + // success > + // > + ret_code =3D 0; > + Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind); > + AdapterInfo->cur_rx_ind++; > + if (AdapterInfo->cur_rx_ind =3D=3D AdapterInfo->RxBufCnt) { > + AdapterInfo->cur_rx_ind =3D 0; > + } > + break; > + } > + > +FreeRFD: > + Recycle_RFD (AdapterInfo, AdapterInfo->cur_rx_ind); > + AdapterInfo->cur_rx_ind++; > + if (AdapterInfo->cur_rx_ind =3D=3D AdapterInfo->RxBufCnt) { > + AdapterInfo->cur_rx_ind =3D 0; > + } > + > + rx_ptr =3D &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind]; > + } > + > + if (pkt_type =3D=3D PXE_FRAME_TYPE_NONE) { > + AdapterInfo->Int_Status &=3D (~SCB_STATUS_FR); > + } > + > + status =3D InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus); > + if ((status & SCB_RUS_NO_RESOURCES) !=3D 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 =3D 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 =3D (UINT16 *) (&AdapterInfo->NVData[0]); > + > + sum =3D 0; > + addr_len =3D E100bGetEepromAddrLen (AdapterInfo); > + > + // > + // in words > + // > + AdapterInfo->NVData_Len =3D eeprom_len =3D (UINT16) (1 << addr_len); > + for (Index2 =3D 0, Index =3D 0; ((Index2 < PXE_MAC_LENGTH - 1) && (Ind= ex < > eeprom_len)); Index++) { > + UINT16 value; > + value =3D E100bReadEeprom (AdapterInfo, Index, addr_len); > + eedata[Index] =3D value; > + sum =3D (UINT16) (sum + value); > + if (Index < 3) { > + AdapterInfo->PermNodeAddress[Index2++] =3D (UINT8) value; > + AdapterInfo->PermNodeAddress[Index2++] =3D (UINT8) (value >> 8); > + } > + } > + > + if (sum !=3D 0xBABA) { > + return -1; > + } > + > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + AdapterInfo->CurrentNodeAddress[Index] =3D AdapterInfo- > >PermNodeAddress[Index]; > + } > + > + for (Index =3D 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { > + AdapterInfo->BroadcastNodeAddress[Index] =3D 0xff; > + } > + > + for (Index =3D PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; > Index++) { > + AdapterInfo->CurrentNodeAddress[Index] =3D 0; > + AdapterInfo->PermNodeAddress[Index] =3D 0; > + AdapterInfo->BroadcastNodeAddress[Index] =3D 0; > + } > + > + return 0; > +} > + > +// > +// CBList is a circular linked list > +// 1) When all are free, Tail->next =3D=3D Head and FreeCount =3D=3D # = allocated > +// 2) When none are free, Tail =3D=3D Head and FreeCount =3D=3D 0 > +// 3) when one is free, Tail =3D=3D Head and Freecount =3D=3D 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 =3D &(AdapterInfo->tx_ring[0]); > + array_off =3D (UINTN) (&cur_ptr->TBDArray) - (UINTN) cur_ptr; > + for (Index =3D 0; Index < AdapterInfo->TxBufCnt; Index++) { > + cur_ptr[Index].cb_header.status =3D 0; > + cur_ptr[Index].cb_header.command =3D 0; > + > + cur_ptr[Index].PhysTCBAddress =3D > + (UINT32) AdapterInfo->tx_phy_addr + (Index * sizeof (TxCB)); > + > + cur_ptr[Index].PhysArrayAddr =3D > (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off); > + cur_ptr[Index].PhysTBDArrayAddres =3D > (UINT32)(cur_ptr[Index].PhysTCBAddress + array_off); > + > + cur_ptr->free_data_ptr =3D (UINT64) 0; > + > + if (Index < AdapterInfo->TxBufCnt - 1) { > + cur_ptr[Index].cb_header.link =3D cur_ptr[Index].PhysT= CBAddress + > sizeof (TxCB); > + cur_ptr[Index].NextTCBVirtualLinkPtr =3D &cur_ptr[Index + 1]; > + cur_ptr[Index + 1].PrevTCBVirtualLinkPtr =3D &cur_ptr[Index]; > + } > + } > + > + head_ptr =3D &cur_ptr[0]; > + tail_ptr =3D &cur_ptr[AdapterInfo->TxBufCnt - 1= ]; > + tail_ptr->cb_header.link =3D head_ptr->PhysTCBAddress; > + tail_ptr->NextTCBVirtualLinkPtr =3D head_ptr; > + head_ptr->PrevTCBVirtualLinkPtr =3D tail_ptr; > + > + AdapterInfo->FreeCBCount =3D AdapterInfo->TxBufCnt; > + AdapterInfo->FreeTxHeadPtr =3D head_ptr; > + // > + // set tail of the free list, next to this would be either in use > + // or the head itself > + // > + AdapterInfo->FreeTxTailPtr =3D tail_ptr; > + > + AdapterInfo->xmit_done_head =3D AdapterInfo->xmit_done_tail =3D 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 <=3D 1) { > + CheckCBList (AdapterInfo); > + } > + > + // > + // don't use up the last CB problem if the previous CB that the CU use= d > + // becomes the last CB we submit because of the SUSPEND bit we set. > + // the CU thinks it was never cleared. > + // > + > + if (AdapterInfo->FreeCBCount <=3D 1) { > + return NULL; > + } > + > + BlockIt (AdapterInfo, TRUE); > + free_cb_ptr =3D AdapterInfo->FreeTxHeadPtr; > + AdapterInfo->FreeTxHeadPtr =3D 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 =3D 0; > + cb_ptr->free_data_ptr =3D (UINT64) 0; > + > + AdapterInfo->FreeTxTailPtr =3D 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 =3D (UINT16) (ind + 1); > + if (Tmp >=3D (TX_BUFFER_COUNT << 1)) { > + Tmp =3D 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 =3D 0; > + while (1) { > + Tmp_ptr =3D AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr; > + if ((Tmp_ptr->cb_header.status & CMD_STATUS_MASK) !=3D 0) { > + // > + // check if Q is full > + // > + if (next (AdapterInfo->xmit_done_tail) !=3D AdapterInfo->xmit_done= _head) > { > + ASSERT (AdapterInfo->xmit_done_tail < TX_BUFFER_COUNT << 1); > + AdapterInfo->xmit_done[AdapterInfo->xmit_done_tail] =3D 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 =3D next (AdapterInfo->xmit_done_tai= l); > + } > + > + SetFreeCB (AdapterInfo, Tmp_ptr); > + } else { > + break; > + } > + } > + > + return cnt; > +} > +// > +// Description : Initialize the RFD list list by linking each element to= gether > +// in a circular list. The simplified memory model is use= d. > +// All data is in the RFD. The RFDs are linked together a= nd the > +// last one points back to the first one. When the curren= t RFD > +// is processed (frame received), its EL bit is set and th= e 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 =3D 0; > + rx_ptr =3D (&AdapterInfo->rx_ring[0]); > + > + for (Index =3D 0; Index < AdapterInfo->RxBufCnt; Index++) { > + rx_ptr[Index].cb_header.status =3D 0; > + rx_ptr[Index].cb_header.command =3D 0; > + rx_ptr[Index].RFDSize =3D RX_BUFFER_SIZE; > + rx_ptr[Index].ActualCount =3D 0; > + // > + // RBDs not used, simple memory model > + // > + rx_ptr[Index].rx_buf_addr =3D (UINT32) (-1); > + > + // > + // RBDs not used, simple memory model > + // > + rx_ptr[Index].forwarded =3D FALSE; > + > + // > + // don't use Tmp_ptr if it is beyond the last one > + // > + if (Index < AdapterInfo->RxBufCnt - 1) { > + rx_ptr[Index].cb_header.link =3D (UINT32) AdapterInfo->rx_phy_addr= + > ((Index + 1) * sizeof (RxFD)); > + } > + } > + > + tail_ptr =3D (&AdapterInfo->rx_ring[AdapterInfo->Rx= BufCnt - 1]); > + tail_ptr->cb_header.link =3D (UINT32) AdapterInfo->rx_phy_addr; > + > + // > + // set the EL bit > + // > + tail_ptr->cb_header.command =3D 0xC000; > + AdapterInfo->RFDTailPtr =3D 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] =3D FALSE; > + // > + rx_ptr =3D &AdapterInfo->rx_ring[rx_index]; > + tail_ptr =3D AdapterInfo->RFDTailPtr; > + // > + // set el_bit and suspend bit > + // > + rx_ptr->cb_header.command =3D 0xc000; > + rx_ptr->cb_header.status =3D 0; > + rx_ptr->ActualCount =3D 0; > + rx_ptr->forwarded =3D FALSE; > + AdapterInfo->RFDTailPtr =3D rx_ptr; > + // > + // resetting the el_bit. > + // > + tail_ptr->cb_header.command =3D 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 =3D AdapterInfo->ioaddr + SCBeeprom; > + > + for (Index =3D num_bits; Index >=3D 0; Index--) { > + INT16 dataval; > + > + // > + // will be 0 or 4 > + // > + dataval =3D (INT16) ((val & (1 << Index)) ? EE_DI : 0); > + > + // > + // mask off the data_in bit > + // > + Tmp =3D (UINT8) (InByte (AdapterInfo, EEAddr) &~EE_DI); > + Tmp =3D (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 =3D AdapterInfo->ioaddr + SCBeeprom; > + > + retval =3D 0; > + for (Index =3D 15; Index >=3D 0; Index--) { > + // > + // raise the clock > + // > + > + // > + // mask off the data_in bit > + // > + Tmp =3D InByte (AdapterInfo, EEAddr); > + OutByte (AdapterInfo, (UINT8) (Tmp | EE_SHIFT_CLK), EEAddr); > + eeprom_delay (100); > + Tmp =3D InByte (AdapterInfo, EEAddr); > + retval =3D (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 t= he > + eeprom. the access bit is the most significant bit in the General Cont= rol > + Register 2 in the SCB space. > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver is > + layering on.. > + > + @retval TRUE if it got the access > + @retval FALSE if it fails to get the exclusi= ve access > + > +**/ > +BOOLEAN > +E100bSetEepromLockOut ( > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + UINTN wait; > + UINT8 tmp; > + > + if ((AdapterInfo->DeviceID =3D=3D D102_DEVICE_ID) || > + (AdapterInfo->RevID >=3D D102_REVID)) { > + > + wait =3D 500; > + > + while (wait--) { > + > + tmp =3D InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2); > + tmp |=3D GCR2_EEPROM_ACCESS_SEMAPHORE; > + OutByte (AdapterInfo, tmp, AdapterInfo->ioaddr + SCBGenCtrl2); > + > + DelayIt (AdapterInfo, 50); > + tmp =3D 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 Cont= rol > + Register 2 in the SCB space. > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver is > + layering on.. > + > + @return None > + > +**/ > +VOID > +E100bReSetEepromLockOut ( > + IN NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + UINT8 tmp; > + > + if ((AdapterInfo->DeviceID =3D=3D D102_DEVICE_ID) || > + (AdapterInfo->RevID >=3D D102_REVID)) { > + > + tmp =3D InByte (AdapterInfo, AdapterInfo->ioaddr + SCBGenCtrl2); > + tmp &=3D ~(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 Wor= d > of data for the MAC address. > + > + @param AdapterInfo Pointer to the NIC data struct= ure > + information which the UNDI dri= ver is > + layering on.. > + @param Location Word offset into the MAC addre= ss to read. > + @param AddrLen Number of bits of address leng= th. > + > + @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 =3D AdapterInfo->ioaddr + SCBeeprom; > + ReadCmd =3D (UINT16) (Location | (EE_READ_CMD << AddrLen)); > + > + RetVal =3D 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 =3D (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 =3D shift_bits_in (AdapterInfo); > + > + // > + // Terminate the EEPROM access and leave eeprom in a clean state. > + // > + Tmp =3D InByte (AdapterInfo, EEAddr); > + Tmp &=3D ~(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 struct= ure > + information which the UNDI dri= ver 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 =3D AdapterInfo->ioaddr + SCBeeprom; > + ReadCmd =3D (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 =3D (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 ze= ro" > + // > + > + // > + // assume the smallest > + // > + AddrLen =3D 6; > + Tmp =3D InByte (AdapterInfo, EEAddr); > + while ((AddrLen < 8) && ((Tmp & EE_DO) !=3D 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 =3D InByte (AdapterInfo, EEAddr); > + AddrLen++; > + } > + > + // > + // read the eeprom word, even though we don't need this > + // > + shift_bits_in (AdapterInfo); > + > + // > + // Terminate the EEPROM access. > + // > + Tmp =3D InByte (AdapterInfo, EEAddr); > + Tmp &=3D ~(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 =3D 10000; > + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); > + > + // > + // Clear statistics done marker. > + // > + AdapterInfo->statistics->done_marker =3D 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 !=3D 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 =3D=3D 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 =3D 01 0000 0100 1101 0001 0111; > + // > + db.Supported =3D 0x104D17; > + > + // > + // Statistics from the NIC > + // > + > + db.Data[0x01] =3D AdapterInfo->statistics->rx_good_frames; > + > + db.Data[0x02] =3D AdapterInfo->statistics->rx_runt_errs; > + > + db.Data[0x08] =3D AdapterInfo->statistics->rx_crc_errs + > + AdapterInfo->statistics->rx_align_errs; > + > + db.Data[0x04] =3D db.Data[0x02] + > + db.Data[0x08] + > + AdapterInfo->statistics->rx_resource_errs + > + AdapterInfo->statistics->rx_overrun_errs; > + > + db.Data[0x00] =3D db.Data[0x01] + db.Data[0x04]; > + > + db.Data[0x0B] =3D AdapterInfo->statistics->tx_good_frames; > + > + db.Data[0x0E] =3D 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] =3D AdapterInfo->statistics->tx_total_colls; > + > + db.Data[0x0A] =3D db.Data[0x0B] + > + db.Data[0x0E] + > + AdapterInfo->statistics->tx_lost_carrier; > + > + if (DBsize > sizeof db) { > + DBsize =3D (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) =3D=3D 0) { > + > + save_filter =3D AdapterInfo->Rx_Filter; > + // > + // if we give the filter same as Rx_Filter, > + // this routine will not set mcast list (it thinks there is no chang= e) > + // to force it, we will reset that flag in the Rx_Filter > + // > + AdapterInfo->Rx_Filter &=3D > (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST); > + E100bSetfilter (AdapterInfo, save_filter, (UINT64) 0, (UINT32) 0); > + } > + > + if ((OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) !=3D 0) { > + // > + // disable the interrupts > + // > + AdapterInfo->int_mask =3D 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 !=3D AdapterInfo->TxBufCnt) { > + wait_for_cmd_done (AdapterInfo->ioaddr + SCBCmd); > + } > + > + // > + // we do not want to reset the phy, it takes a long time to renegotiat= e 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 w= riting to > + @param PhyAddress The MDI address of the Phy com= ponent. > + @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 =3D ((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) =3D=3D 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 r= eading > from > + @param PhyAddress The MDI address of the Phy com= ponent. > + @param DataValue pointer to the value that we r= ead from > + the MII register. > + > + > +**/ > +VOID > +MdiRead ( > + IN NIC_DATA_INSTANCE *AdapterInfo, > + IN UINT8 RegAddress, > + IN UINT8 PhyAddress, > + IN OUT UINT16 *DataValue > + ) > +{ > + UINT32 ReadCommand; > + > + ReadCommand =3D ((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) =3D=3D 0) { > + DelayIt (AdapterInfo, 20); > + > + } > + > + *DataValue =3D 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 =3D (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 con= figured > + correctly. > + @retval FALSE If a valid phy could not be de= tected and > + configured. > + > +**/ > +BOOLEAN > +PhyDetect ( > + NIC_DATA_INSTANCE *AdapterInfo > + ) > +{ > + UINT16 *eedata; > + UINT16 MdiControlReg; > + UINT16 MdiStatusReg; > + BOOLEAN FoundPhy1; > + UINT8 ReNegotiateTime; > + > + eedata =3D (UINT16 *) (&AdapterInfo->NVData[0]); > + > + FoundPhy1 =3D FALSE; > + ReNegotiateTime =3D 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] =3D eedata[6]; > + AdapterInfo->PhyRecord[1] =3D eedata[7]; > + AdapterInfo->PhyAddress =3D (UINT8) (AdapterInfo->PhyRecord[0] & 7); > + > + // > + // Check for a phy address over-ride of 32 which indicates force use o= f > 82503 > + // not detecting the link in this case > + // > + if (AdapterInfo->PhyAddress =3D=3D 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 =3D 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 =3D=3D 0xffff) || > + ((MdiStatusReg =3D=3D 0) && (MdiControlReg =3D=3D 0)))) { > + > + // > + // we have a valid phy1 > + // Read the status register again because of sticky bits > + // > + FoundPhy1 =3D 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 =3D=3D 0xffff) || > + ((MdiStatusReg =3D=3D 0) && (MdiControlReg =3D=3D 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 =3D=3D 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 !=3D 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 =3D 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 =3D 10; > + return (TRUE); > + } > + } > + } else { > + // > + // We have a valid phy at address 0. If phy 0 has a link then we us= e > + // 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) =3D=3D 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 !=3D 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 =3D 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 configu= red > + correctly, because an unsuppor= ted > + 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 =3D 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 =3D=3D 10) { > + // > + // If half duplex is forced > + // > + if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) !=3D 0) { > + if (MdiStatusReg & MDI_SR_10T_HALF_DPX) { > + > + MdiControlReg &=3D ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | > MDI_CR_FULL_HALF); > + ForcePhySetting =3D TRUE; > + } > + } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) !=3D 0= ) { > + > + // > + // If full duplex is forced > + // > + if (MdiStatusReg & MDI_SR_10T_FULL_DPX) { > + > + MdiControlReg &=3D ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT); > + MdiControlReg |=3D MDI_CR_FULL_HALF; > + ForcePhySetting =3D 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 &=3D ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | > MDI_CR_FULL_HALF); > + ForcePhySetting =3D TRUE; > + } > + } > + } > + > + // > + // If speed is forced to 100mb > + // > + else if (AdapterInfo->LinkSpeedReq =3D=3D 100) { > + // > + // If half duplex is forced > + // > + if ((AdapterInfo->DuplexReq & PXE_FORCE_HALF_DUPLEX) !=3D 0) { > + if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) { > + > + MdiControlReg &=3D ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); > + MdiControlReg |=3D MDI_CR_10_100; > + ForcePhySetting =3D TRUE; > + } > + } else if ((AdapterInfo->DuplexReq & PXE_FORCE_FULL_DUPLEX) !=3D 0= ) { > + // > + // If full duplex is forced > + // > + if (MdiStatusReg & MDI_SR_TX_FULL_DPX) { > + MdiControlReg &=3D ~MDI_CR_AUTO_SELECT; > + MdiControlReg |=3D (MDI_CR_10_100 | MDI_CR_FULL_HALF); > + ForcePhySetting =3D TRUE; > + } > + } else { > + // > + // If auto duplex (we set phy to 1/2) > + // > + if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) { > + > + MdiControlReg &=3D ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); > + MdiControlReg |=3D MDI_CR_10_100; > + ForcePhySetting =3D 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 cer= tain > + // phys there are specific bits that must be set so that the phy and t= he > + // 82557 work together properly. > + // > + > + MdiRead ( > + AdapterInfo, > + PHY_ID_REG_1, > + AdapterInfo->PhyAddress, > + &MdiIdLowReg > + ); > + MdiRead ( > + AdapterInfo, > + PHY_ID_REG_2, > + AdapterInfo->PhyAddress, > + &MdiIdHighReg > + ); > + > + PhyId =3D ((UINT32) MdiIdLowReg | ((UINT32) MdiIdHighReg << 16)); > + > + // > + // And out the revsion field of the Phy ID so that we'll be able to de= tect > + // future revs of the same Phy. > + // > + PhyId &=3D PHY_MODEL_REV_ID_MASK; > + > + // > + // Handle the National TX > + // > + if (PhyId =3D=3D PHY_NSC_TX) { > + > + MdiRead ( > + AdapterInfo, > + NSC_CONG_CONTROL_REG, > + AdapterInfo->PhyAddress, > + &MdiMiscReg > + ); > + > + MdiMiscReg |=3D (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 wan= ted > + // 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 =3D AdapterInfo->LinkSpeedReq; > + AdapterInfo->Duplex =3D (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 s= et > + // 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 =3D 10; > + AdapterInfo->Duplex =3D HALF_DUPLEX; > + return ; > + } > + > + // > + // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bi= ts > + // 1 and 0 of extended register 0, to get the current speed and duplex > + // settings. > + // > + if ((PhyId =3D=3D PHY_100_A) || (PhyId =3D=3D PHY_100_C) || (PhyId =3D= =3D > 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 =3D 100; > + } else { > + AdapterInfo->LinkSpeed =3D 10; > + } > + > + // > + // Get current duplex setting -- if bit is set then FDX is enabled > + // > + if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) { > + AdapterInfo->Duplex =3D FULL_DUPLEX; > + } else { > + AdapterInfo->Duplex =3D 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 =3D (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 =3D 100; > + } else { > + AdapterInfo->LinkSpeed =3D 10; > + } > + > + // > + // Get duplex setting -- use priority resolution algorithm > + // > + if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) { > + AdapterInfo->Duplex =3D HALF_DUPLEX; > + return ; > + } else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) { > + AdapterInfo->Duplex =3D FULL_DUPLEX; > + return ; > + } else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) { > + AdapterInfo->Duplex =3D HALF_DUPLEX; > + return ; > + } else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) { > + AdapterInfo->Duplex =3D FULL_DUPLEX; > + return ; > + } else { > + AdapterInfo->Duplex =3D 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 esta= blish > + // the connection, the duplex setting should HALF duplex. > + // > + AdapterInfo->Duplex =3D HALF_DUPLEX; > + > + if (PhyId =3D=3D 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 =3D 10; > + } else { > + AdapterInfo->LinkSpeed =3D 100; > + } > + } > + > + // > + // If we don't know what line speed we are set at, then we'll default = to > + // 10mbs > + // > + else { > + AdapterInfo->LinkSpeed =3D 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 =3D=3D AdapterInfo->TxBufCnt) { > + return ; > + } > + > + // > + // used xmit cb list starts right after the free tail (ends before the > + // free head ptr) > + // > + TxPtr =3D AdapterInfo->FreeTxTailPtr->NextTCBVirtualLinkPtr; > + while (TxPtr !=3D AdapterInfo->FreeTxHeadPtr) { > + CommandWaitForCompletion (TxPtr, AdapterInfo); > + SetFreeCB (AdapterInfo, TxPtr); > + TxPtr =3D 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 =3D 5000; > + while ((cmd_ptr->cb_header.status =3D=3D 0) && (--wait > 0)) { > + DelayIt (AdapterInfo, 10); > + } > + > + if (cmd_ptr->cb_header.status =3D=3D 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 =3D 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 =3D=3D D102_DEVICE_ID || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_1 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_2 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_3 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_4 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_5 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_6 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_7 || > + AdapterInfo->VendorID =3D=3D ICH3_DEVICE_ID_8 || > + AdapterInfo->RevID >=3D 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 =3D 5000; > + while (wait) { > + tco_stat =3D InByte (AdapterInfo, AdapterInfo->ioaddr + 0x1b); > + if ((tco_stat & 2) =3D=3D 0) { > + // > + // is the activity bit clear?? > + // > + break; > + } > + > + wait--; > + DelayIt (AdapterInfo, 1); > + } > + > + if ((tco_stat & 2) !=3D 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 =3D 10; > + stat =3D 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 =3D InLong (AdapterInfo, AdapterInfo->ioaddr + SCBPort); > + if (stat =3D=3D 0) { > + break; > + } > + > + // > + // wait for 1 milli second > + // > + DelayIt (AdapterInfo, 1000); > + } > + > + if (stat !=3D 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) !=3D 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 =3D Load_Base_Regs (AdapterInfo)) !=3D 0) { > + return ret_val; > + } > + > + if ((ret_val =3D SetupCBlink (AdapterInfo)) !=3D 0) { > + return ret_val; > + } > + > + if ((ret_val =3D SetupReceiveQueues (AdapterInfo)) !=3D 0) { > + return ret_val; > + } > + > + // > + // detect the PHY only if we need to detect the cable as requested by = the > + // initialize parameters > + // > + AdapterInfo->PhyAddress =3D 0xFF; > + > + if (AdapterInfo->CableDetect !=3D 0) { > + if (!PhyDetect (AdapterInfo)) { > + return PXE_STATCODE_DEVICE_FAILURE; > + } > + } > + > + if ((ret_val =3D E100bSetupIAAddr (AdapterInfo)) !=3D 0) { > + return ret_val; > + } > + > + if ((ret_val =3D Configure (AdapterInfo)) !=3D 0) { > + return ret_val; > + } > + > + return 0; > +} > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.h > b/Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.h > new file mode 100644 > index 0000000000..18ff7aa94d > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/E100b.h > @@ -0,0 +1,665 @@ > +/** @file > + Definitions for network adapter card. > + > +Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#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 =3D 0, SCBCmd =3D 2, // Rx/Command Unit command and stat= us. > + SCBPointer =3D 4, // General purpose pointer. > + SCBPort =3D 8, // Misc. commands and operands. > + SCBflash =3D 12, SCBeeprom =3D 14, // EEPROM and flash memory control. > + SCBCtrlMDI =3D 16, // MDI interface control. > + SCBEarlyRx =3D 20, // Early receive byte count. > + SCBEarlyRxInt =3D 24, SCBFlowCtrlReg =3D 25, SCBPmdr =3D 27, > + // offsets for general control registers (GCRs) > + SCBGenCtrl =3D 28, SCBGenStatus =3D 29, SCBGenCtrl2 =3D 30, SCBRsvd = =3D 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 =3D 0, CmdIASetup =3D 1, CmdConfigure =3D 2, CmdMulticastList = =3D 3, > + CmdTx =3D 4, CmdTDR =3D 5, CmdDump =3D 6, CmdDiagnose =3D 7, > + CmdSuspend =3D 0x4000, /* Suspend after completion. */ > + CmdIntr =3D 0x2000, /* Interrupt after completion. */ > + CmdTxFlex =3D 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 Interrup= t > +#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/wri= te > +#define MDI_PHY_OPCODE BIT_26_27 // which PHY to read/wri= te > +#define MDI_PHY_READY BIT_28 // PHY is ready for anot= her MDI > cycle > +#define MDI_PHY_INT_ENABLE BIT_29 // Assert INT at MDI cyc= le > 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 r= eg (word 1) > +#define PHY_ID_REG_2 0x03 // Phy indentification r= eg (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 1= 00 > modes) > +#define EXTENDED_REG_1 0x14 // Extended reg 1 (Phy 1= 00 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 =3D1, half duplex= =3D0 > +#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 ena= ble > +#define MDI_CR_10_100 BIT_13 // 0 =3D 10Mbs, 1 =3D 10= 0Mbs > +#define MDI_CR_LOOPBACK BIT_14 // 0 =3D normal, 1 =3D l= oopback > +#define MDI_CR_RESET BIT_15 // 0 =3D normal, 1 =3D P= HY 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 =3D = 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 capabl= e > +#define MDI_SR_TX_FULL_DPX BIT_14 // TX full duplex capabl= e > +#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 capabl= e > +#define NWAY_AD_TX_FULL_DPX BIT_8 // TX full duplex capabl= e > +#define NWAY_AD_T4_CAPABLE BIT_9 // T4 capable > +#define NWAY_AD_REMOTE_FAULT BIT_13 // indicates local remot= e > 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 suppor= ted) > + > +// 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 receiv= ed > +#define NWAY_EX_NEXT_PAGE_ABLE BIT_2 // local is next page ab= le > +#define NWAY_EX_LP_NEXT_PAGE_ABLE BIT_3 // partner is next page > able > +#define NWAY_EX_PARALLEL_DET_FLT BIT_4 // parallel detection fa= ult > +#define NWAY_EX_RESERVED BIT_5_15 // reserved > + > + > +// PHY 100 Extended Register 0 bit definitions > +#define PHY_100_ER0_FDX_INDIC BIT_0 // 1 =3D FDX, 0 =3D half= duplex > +#define PHY_100_ER0_SPEED_INDIC BIT_1 // 1 =3D 100mbs, 0=3D 10= mbs > +#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 st= ep > =3D 000) > +#define PHY_100_ER0_FORCE_FAIL BIT_8 // Force Fail is enabled > +#define PHY_100_ER0_TEST BIT_9_13 // Revsion control (A st= ep =3D > 000) > +#define PHY_100_ER0_LINKDIS BIT_14 // Link integrity test i= s > disabled > +#define PHY_100_ER0_JABDIS BIT_15 // Jabber function is di= sabled > + > + > +// 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 inpu= t > +#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 definitio= ns > +#define NSC_TX_SPD_INDC_SPEED BIT_6 // 0 =3D 100mb, 1=3D10mb > + > +//----------------------------------------------------------------------= --- > +// 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 =3D 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 xmi= t > 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 align= ed. > */ > +#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 =3D 16h) > +#define CFIG_BYTE_COUNT 0x16 // 22 Configuration Bytes > + > +//- Byte 1 (Default Value =3D 88h) > +#define CFIG_TXRX_FIFO_LIMIT 0x88 > + > +//- Byte 2 (Default Value =3D 0) > +#define CFIG_ADAPTIVE_IFS 0 > + > +//- Byte 3 (Default Value =3D 0, ALWAYS. This byte is RESERVED) > +#define CFIG_RESERVED 0 > + > +//- Byte 4 (Default Value =3D 0. Default implies that Rx DMA cannot be > +//- preempted). > +#define CFIG_RXDMA_BYTE_COUNT 0 > + > +//- Byte 5 (Default Value =3D 80h. Default implies that Tx DMA cannot b= e > +//- preempted. However, setting these counters is enabled.) > +#define CFIG_DMBC_ENABLE 0x80 > + > +//- Byte 6 (Default Value =3D 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 =3D 7h. Discard short frames automatically an= d > +//- attempt upto 3 retries on transmit.) > +#define CFIG_DISCARD_SHORTRX 0x00001 > +#define CFIG_URUN_RETRY BIT_1 OR BIT_2 > + > +//- Byte 8 (Default Value =3D 1. Enable MII mode.) > +#define CFIG_503_MII BIT_0 > + > +//- Byte 9 (Default Value =3D 0, ALWAYS) > + > +//- Byte 10 (Default Value =3D 2Eh) > +#define CFIG_NSAI BIT_3 > +#define CFIG_PREAMBLE_LENGTH BIT_5 ;- Bit 5-4 =3D 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 =3D 0) > +#define CFIG_LINEAR_PRIORITY 0 > + > +//- Byte 12 (Default Value =3D 60h) > +#define CFIG_LPRIORITY_MODE 0 > +#define CFIG_IFS 6 ;- 6 * 16 =3D 96 > + > +//- Byte 13 (Default Value =3D 0, ALWAYS) > + > +//- Byte 14 (Default Value =3D 0F2h, ALWAYS) > + > +//- Byte 15 (Default Value =3D E8h) > +#define CFIG_PROMISCUOUS_MODE BIT_0 > +#define CFIG_BROADCAST_DISABLE BIT_1 > +#define CFIG_CRS_CDT BIT_7 > + > +//- Byte 16 (Default Value =3D 0, ALWAYS) > + > +//- Byte 17 (Default Value =3D 40h, ALWAYS) > + > +//- Byte 18 (Default Value =3D F2h) > +#define CFIG_STRIPPING BIT_0 > +#define CFIG_PADDING BIT_1 > +#define CFIG_RX_CRC_TRANSFER BIT_2 > + > +//- Byte 19 (Default Value =3D 80h) > +#define CFIG_FORCE_FDX BIT_6 > +#define CFIG_FDX_PIN_ENABLE BIT_7 > + > +//- Byte 20 (Default Value =3D 3Fh) > +#define CFIG_MULTI_IA BIT_6 > + > +//- Byte 21 (Default Value =3D 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 fr= om > 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_d= one) > + 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); // ca= ll > 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/Drivers/OptionRomPkg/UndiRuntimeDxe/Init.c > b/Drivers/OptionRomPkg/UndiRuntimeDxe/Init.c > new file mode 100644 > index 0000000000..2625a6cc5c > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/Init.c > @@ -0,0 +1,1051 @@ > +/** @file > + Initialization functions for EFI UNDI32 driver. > + > +Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "Undi32.h" > +// > +// Global Variables > +// > + > +PXE_SW_UNDI *pxe_31 =3D NULL; // 3.1 entry > +UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES]; > +UNDI_CONFIG_TABLE *UndiDataPointer =3D NULL; > + > +// > +// UNDI Class Driver Global Variables > +// > +EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding =3D { > + 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 !=3D NULL) { > + Pxe31Pointer =3D (VOID *) pxe_31; > + > + EfiConvertPointer ( > + EFI_OPTIONAL_PTR, > + (VOID **) &Pxe31Pointer > + ); > + > + // > + // UNDI32DeviceList is an array of pointers > + // > + for (Index =3D 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); I= ndex++) { > + UNDI32DeviceList[Index]->NIIProtocol_31.Id =3D (UINT64) (UINTN) > Pxe31Pointer; > + EfiConvertPointer ( > + EFI_OPTIONAL_PTR, > + (VOID **) &(UNDI32DeviceList[Index]) > + ); > + } > + > + EfiConvertPointer ( > + EFI_OPTIONAL_PTR, > + (VOID **) &(pxe_31->EntryPoint) > + ); > + pxe_31 =3D Pxe31Pointer; > + } > + > + for (Index =3D 0; Index <=3D 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 > +UndiNotifyReadyToBoot ( > + EFI_EVENT Event, > + VOID *Context > + ) > +{ > + InstallConfigTable (); > +} > + > + > +/** > + Test to see if this driver supports ControllerHandle. Any ControllerHa= ndle > + than contains a DevicePath, PciIo protocol, Class code of 2, Vendor I= D 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 =3D gBS->OpenProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + NULL, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_TEST_PROTOCOL > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D gBS->OpenProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + (VOID **) &PciIo, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D PciIo->Pci.Read ( > + PciIo, > + EfiPciIoWidthUint8, > + 0, > + sizeof (PCI_CONFIG_HEADER), > + &Pci > + ); > + > + if (!EFI_ERROR (Status)) { > + Status =3D EFI_UNSUPPORTED; > + > + if (Pci.Hdr.ClassCode[2] =3D=3D 0x02 && Pci.Hdr.VendorId =3D=3D > 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 =3D EFI_SUCCESS; > + } > + } > + } > + > + gBS->CloseProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + return Status; > +} > + > + > +/** > + Start this driver on Controller by opening PciIo and DevicePath protoc= ol. > + Initialize PXE structures, create a copy of the Controller Device Path= with > the > + NIC's MAC address appended to it, install the NetworkInterfaceIdentifi= er > 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 =3D gBS->OpenProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + (VOID **) &PciIoFncs, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status =3D 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 =3D FALSE; > + > + Status =3D 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 =3D PciIoFncs->Attributes ( > + PciIoFncs, > + EfiPciIoAttributeOperationGet, > + 0, > + &UNDI32Device->NicInfo.OriginalPciAttributes > + ); > + > + if (EFI_ERROR (Status)) { > + goto UndiErrorDeleteDevice; > + } > + PciAttributesSaved =3D 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) a= nd a > + // 32 bytes padding for alignment adjustment (in case) > + // > + TmpPxePointer =3D NULL; > + if (pxe_31 =3D=3D NULL) { > + Status =3D 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) !=3D 0) { > + pxe_31 =3D (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8)); > + } else { > + pxe_31 =3D (PXE_SW_UNDI *) TmpPxePointer; > + } > + > + PxeStructInit (pxe_31); > + } > + > + UNDI32Device->NIIProtocol_31.Id =3D (UINT64) (UINTN) (pxe_31); > + > + Status =3D PciIoFncs->Attributes ( > + PciIoFncs, > + EfiPciIoAttributeOperationSupported, > + 0, > + &Supports > + ); > + if (!EFI_ERROR (Status)) { > + Supports &=3D EFI_PCI_DEVICE_ENABLE; > + Status =3D PciIoFncs->Attributes ( > + PciIoFncs, > + EfiPciIoAttributeOperationEnable, > + Supports, > + NULL > + ); > + } > + // > + // Read all the registers from device's PCI Configuration space > + // > + Status =3D PciIoFncs->Pci.Read ( > + PciIoFncs, > + EfiPciIoWidthUint32, > + 0, > + MAX_PCI_CONFIG_LEN, > + &UNDI32Device->NicInfo.Config > + ); > + > + CfgHdr =3D (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]); > + > + // > + // make sure that this device is a PCI bus master > + // > + > + NewCommand =3D (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER > | PCI_COMMAND_IO); > + if (CfgHdr->Command !=3D NewCommand) { > + PciIoFncs->Pci.Write ( > + PciIoFncs, > + EfiPciIoWidthUint16, > + PCI_COMMAND, > + 1, > + &NewCommand > + ); > + CfgHdr->Command =3D NewCommand; > + } > + > + // > + // make sure that the latency timer is at least 32 > + // > + if (CfgHdr->LatencyTimer < 32) { > + CfgHdr->LatencyTimer =3D 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 =3D pxe_31->IFcnt | pxe_31- > >IFcntExt << 8; > + > + PxeUpdate (&UNDI32Device->NicInfo, pxe_31); > + > + UNDI32Device->NicInfo.Io_Function =3D PciIoFncs; > + UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] =3D UNDI32Device; > + UNDI32Device->Undi32BaseDevPath =3D UndiDevicePat= h; > + > + Status =3D AppendMac2DevPath ( > + &UNDI32Device->Undi32DevPath, > + UNDI32Device->Undi32BaseDevPath, > + &UNDI32Device->NicInfo > + ); > + > + if (Status !=3D 0) { > + goto UndiErrorDeletePxe; > + } > + > + UNDI32Device->Signature =3D UNDI_DEV_SIGNATURE; > + > + UNDI32Device->NIIProtocol_31.Revision =3D > EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31; > + UNDI32Device->NIIProtocol_31.Type =3D EfiNetworkInterfaceUnd= i; > + UNDI32Device->NIIProtocol_31.MajorVer =3D PXE_ROMID_MAJORVER; > + UNDI32Device->NIIProtocol_31.MinorVer =3D > PXE_ROMID_MINORVER_31; > + UNDI32Device->NIIProtocol_31.ImageSize =3D 0; > + UNDI32Device->NIIProtocol_31.ImageAddr =3D 0; > + UNDI32Device->NIIProtocol_31.Ipv6Supported =3D TRUE; > + > + UNDI32Device->NIIProtocol_31.StringId[0] =3D 'U'; > + UNDI32Device->NIIProtocol_31.StringId[1] =3D 'N'; > + UNDI32Device->NIIProtocol_31.StringId[2] =3D 'D'; > + UNDI32Device->NIIProtocol_31.StringId[3] =3D 'I'; > + > + UNDI32Device->DeviceHandle =3D NULL; > + > + UNDI32Device->Aip.GetInformation =3D UndiAipGetInfo; > + UNDI32Device->Aip.SetInformation =3D UndiAipSetInfo; > + UNDI32Device->Aip.GetSupportedTypes =3D > UndiAipGetSupportedTypes; > + > + // > + // install both the 3.0 and 3.1 NII protocols. > + // > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &UNDI32Device->DeviceHandle, > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, > + &UNDI32Device->NIIProtocol_31, > + &gEfiDevicePathProtocolGuid, > + UNDI32Device->Undi32DevPath, > + &gEfiAdapterInformationProtocolGuid, > + &UNDI32Device->Aip, > + NULL > + ); > + > + if (EFI_ERROR (Status)) { > + goto UndiErrorDeleteDevicePath; > + } > + > + // > + // if the table exists, free it and alloc again, or alloc it directly > + // > + if (UndiDataPointer !=3D NULL) { > + Status =3D gBS->FreePool(UndiDataPointer); > + } > + if (EFI_ERROR (Status)) { > + goto UndiErrorDeleteDevicePath; > + } > + > + Len =3D ((pxe_31->IFcnt|pxe_31->IFcntExt << 8)* sizeof (UndiDataPointe= r- > >NII_entry)) + sizeof (UndiDataPointer); > + Status =3D gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) > &UndiDataPointer); > + > + if (EFI_ERROR (Status)) { > + goto UndiErrorAllocDataPointer; > + } > + > + // > + // Open For Child Device > + // > + Status =3D 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, > + &gEfiAdapterInformationProtocolGuid, > + &UNDI32Device->Aip, > + NULL > + ); > + > +UndiErrorDeleteDevicePath: > + UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] =3D NULL; > + gBS->FreePool (UNDI32Device->Undi32DevPath); > + > +UndiErrorDeletePxe: > + PxeUpdate (NULL, pxe_31); > + if (TmpPxePointer !=3D 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 dev= ice. > + > +**/ > +// 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 =3D=3D 0) { > + > + // > + // Close the bus driver > + // > + Status =3D gBS->CloseProtocol ( > + Controller, > + &gEfiDevicePathProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + Status =3D gBS->CloseProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + This->DriverBindingHandle, > + Controller > + ); > + > + return Status; > + } > + > + AllChildrenStopped =3D TRUE; > + > + for (Index =3D 0; Index < NumberOfChildren; Index++) { > + > + Status =3D gBS->OpenProtocol ( > + ChildHandleBuffer[Index], > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, > + (VOID **) &NIIProtocol, > + This->DriverBindingHandle, > + Controller, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL > + ); > + if (!EFI_ERROR (Status)) { > + > + UNDI32Device =3D UNDI_DEV_FROM_THIS (NIIProtocol); > + > + Status =3D gBS->CloseProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + This->DriverBindingHandle, > + ChildHandleBuffer[Index] > + ); > + if (!EFI_ERROR (Status)) { > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > + ChildHandleBuffer[Index], > + &gEfiDevicePathProtocolGuid, > + UNDI32Device->Undi32DevPath, > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, > + &UNDI32Device->NIIProtocol_31, > + NULL > + ); > + if (!EFI_ERROR (Status)) { > + // > + // Restore original PCI attributes > + // > + Status =3D UNDI32Device->NicInfo.Io_Function->Attributes ( > + UNDI32Device->Ni= cInfo.Io_Function, > + EfiPciIoAttribut= eOperationSet, > + UNDI32Device- > >NicInfo.OriginalPciAttributes, > + NULL > + ); > + > + ASSERT_EFI_ERROR (Status); > + > + gBS->FreePool (UNDI32Device->Undi32DevPath); > + gBS->FreePool (UNDI32Device); > + > + } > + } > + } > + > + if (EFI_ERROR (Status)) { > + AllChildrenStopped =3D 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. T= his 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, t= his 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 operatio= n. > + @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 =3D (EFI_PCI_IO_PROTOCOL_WIDTH) 0; > + AdapterInfo =3D (NIC_DATA_INSTANCE *) (UINTN) UnqId; > + switch (Len) { > + case 2: > + Width =3D (EFI_PCI_IO_PROTOCOL_WIDTH) 1; > + break; > + > + case 4: > + Width =3D (EFI_PCI_IO_PROTOCOL_WIDTH) 2; > + break; > + > + case 8: > + Width =3D (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 cre= ated > 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 informa= tion > which > + the UNDI driver is layering on.. > + > + @retval EFI_SUCCESS A MAC address was successfully appended t= o > 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 c= an > + // execute the other UNDI_ calls to get the mac address > + // we are using undi 3.1 style > + // > + AdapterInfo->Delay =3D TmpDelay; > + AdapterInfo->Virt2Phys =3D (VOID *) 0; > + AdapterInfo->Block =3D (VOID *) 0; > + AdapterInfo->Map_Mem =3D (VOID *) 0; > + AdapterInfo->UnMap_Mem =3D (VOID *) 0; > + AdapterInfo->Sync_Mem =3D (VOID *) 0; > + AdapterInfo->Mem_Io =3D TmpMemIo; > + // > + // these tmp call-backs follow 3.1 undi style > + // i.e. they have the unique_id parameter. > + // > + AdapterInfo->VersionFlag =3D 0x31; > + AdapterInfo->Unique_ID =3D (UINT64) (UINTN) AdapterInfo; > + > + // > + // undi init portion > + // > + CfgHdr =3D (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]= ); > + AdapterInfo->ioaddr =3D 0; > + AdapterInfo->RevID =3D CfgHdr->RevID; > + > + AddrLen =3D E100bGetEepromAddrLen (AdapterInfo); > + > + for (Index =3D 0, Index2 =3D 0; Index < 3; Index++) { > + Val =3D E100bReadEeprom (AdapterInfo, Index, A= ddrLen); > + MACAddress.Addr[Index2++] =3D (UINT8) Val; > + MACAddress.Addr[Index2++] =3D (UINT8) (Val >> 8); > + } > + > + SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, > 0); > + //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) { > + // MACAddress.Addr[Index2] =3D 0; > + //} > + // > + // stop undi > + // > + AdapterInfo->Delay =3D (VOID *) 0; > + AdapterInfo->Mem_Io =3D (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 =3D MESSAGING_DEVICE_PATH; > + MacAddrNode.Header.SubType =3D MSG_MAC_ADDR_DP; > + MacAddrNode.Header.Length[0] =3D (UINT8) sizeof (MacAddrNode); > + MacAddrNode.Header.Length[1] =3D 0; > + > + // > + // find the size of the base dev path. > + // > + EndNode =3D BaseDevPtr; > + > + while (!IsDevicePathEnd (EndNode)) { > + EndNode =3D NextDevicePathNode (EndNode); > + } > + > + BasePathLen =3D (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr)); > + > + // > + // create space for full dev path > + // > + TotalPathLen =3D (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof > (EFI_DEVICE_PATH_PROTOCOL)); > + > + Status =3D gBS->AllocatePool ( > + EfiRuntimeServicesData, > + TotalPathLen, > + (VOID **) &DevicePtr > + ); > + > + if (Status !=3D EFI_SUCCESS) { > + return Status; > + } > + // > + // copy the base path, mac addr and end_dev_path nodes > + // > + *DevPtr =3D (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr; > + CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen); > + DevicePtr +=3D BasePathLen; > + CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode)); > + DevicePtr +=3D 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 syst= em's > + configuration table. > + @retval other Did not successfully install the GUID/Poi= nter 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 =3D=3D NULL) { > + return EFI_SUCCESS; > + } > + > + if(UndiDataPointer =3D=3D NULL) { > + return EFI_SUCCESS; > + } > + > + UndiData =3D (UNDI_CONFIG_TABLE *)UndiDataPointer; > + > + UndiData->NumberOfInterfaces =3D (pxe_31->IFcnt | pxe_31->IFcntExt <<= 8); > + UndiData->nextlink =3D NULL; > + > + for (Index =3D 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Ind= ex++) { > + UndiData->NII_entry[Index].NII_InterfacePointer =3D > &UNDI32DeviceList[Index]->NIIProtocol_31; > + UndiData->NII_entry[Index].DevicePathPointer =3D > UNDI32DeviceList[Index]->Undi32DevPath; > + } > + > + // > + // see if there is an entry in the config table already > + // > + CfgPtr =3D gST->ConfigurationTable; > + > + for (Index =3D 0; Index < gST->NumberOfTableEntries; Index++) { > + Status =3D CompareGuid ( > + &CfgPtr->VendorGuid, > + &gEfiNetworkInterfaceIdentifierProtocolGuid_31 > + ); > + if (Status !=3D EFI_SUCCESS) { > + break; > + } > + > + CfgPtr++; > + } > + > + if (Index < gST->NumberOfTableEntries) { > + TmpData =3D (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable; > + > + // > + // go to the last link > + // > + while (TmpData->nextlink !=3D NULL) { > + TmpData =3D TmpData->nextlink; > + } > + > + TmpData->nextlink =3D UndiData; > + > + // > + // 1st one in chain > + // > + UndiData =3D (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable; > + } > + > + // > + // create an entry in the configuration table for our GUID > + // > + Status =3D 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 =3D EfiLibInstallDriverBindingComponentName2 ( > + ImageHandle, > + SystemTable, > + &gUndiDriverBinding, > + ImageHandle, > + &gUndiComponentName, > + &gUndiComponentName2 > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + UndiNotifyReadyToBoot, > + NULL, > + &gEfiEventReadyToBootGuid, > + &Event > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + UndiNotifyVirtual, > + NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &Event > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/Undi32.h > b/Drivers/OptionRomPkg/UndiRuntimeDxe/Undi32.h > new file mode 100644 > index 0000000000..31c55a8e11 > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/Undi32.h > @@ -0,0 +1,439 @@ > +/** @file > + EFI internal structures for the EFI UNDI driver. > + > +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef _UNDI_32_H_ > +#define _UNDI_32_H_ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > + > +#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) > +#define UNDI_DEV_FROM_AIP(a) CR(a, UNDI32_DEV, Aip, > UNDI_DEV_SIGNATURE) > + > +typedef struct { > + UINTN Signature; > + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL NIIProtocol_31; > + EFI_ADAPTER_INFORMATION_PROTOCOL Aip; > + 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 > + ); > + > +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 EFIAPI 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); > + > +// > +// functions defined in UndiAipImpl.c > +// > + > +/** > + Returns the current state information for the adapter. > + > + This function returns information of type InformationType from the > adapter. > + If an adapter does not support the requested informational type, then > + EFI_UNSUPPORTED is returned. > + > + @param[in] This A pointer to the > EFI_ADAPTER_INFORMATION_PROTOCOL instance. > + @param[in] InformationType A pointer to an EFI_GUID that defin= es > the contents of InformationBlock. > + @param[out] InforamtionBlock The service returns a pointer to th= e > buffer with the InformationBlock > + structure which contains details ab= out the data > specific to InformationType. > + @param[out] InforamtionBlockSize The driver returns the size of the > InformationBlock in bytes. > + > + @retval EFI_SUCCESS The InformationType information was > retrieved. > + @retval EFI_UNSUPPORTED The InformationType is not known. > + @retval EFI_DEVICE_ERROR The device reported an error. > + @retval EFI_OUT_OF_RESOURCES The request could not be completed > due to a lack of resources. > + @retval EFI_INVALID_PARAMETER This is NULL. > + @retval EFI_INVALID_PARAMETER InformationBlock is NULL. > + @retval EFI_INVALID_PARAMETER InformationBlockSize is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +UndiAipGetInfo ( > + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, > + IN EFI_GUID *InformationType, > + OUT VOID **InformationBlock, > + OUT UINTN *InformationBlockSize > + ); > + > +/** > + Sets state information for an adapter. > + > + This function sends information of type InformationType for an adapter= . > + If an adapter does not support the requested information type, then > EFI_UNSUPPORTED > + is returned. > + > + @param[in] This A pointer to the > EFI_ADAPTER_INFORMATION_PROTOCOL instance. > + @param[in] InformationType A pointer to an EFI_GUID that defin= es > the contents of InformationBlock. > + @param[in] InforamtionBlock A pointer to the InformationBlock > structure which contains details > + about the data specific to Informat= ionType. > + @param[in] InforamtionBlockSize The size of the InformationBlock in > bytes. > + > + @retval EFI_SUCCESS The information was received and > interpreted successfully. > + @retval EFI_UNSUPPORTED The InformationType is not known. > + @retval EFI_DEVICE_ERROR The device reported an error. > + @retval EFI_INVALID_PARAMETER This is NULL. > + @retval EFI_INVALID_PARAMETER InformationBlock is NULL. > + @retval EFI_WRITE_PROTECTED The InformationType cannot be > modified using EFI_ADAPTER_INFO_SET_INFO(). > + > +**/ > +EFI_STATUS > +EFIAPI > +UndiAipSetInfo ( > + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, > + IN EFI_GUID *InformationType, > + IN VOID *InformationBlock, > + IN UINTN InformationBlockSize > + ); > + > +/** > + Get a list of supported information types for this instance of the pro= tocol. > + > + This function returns a list of InformationType GUIDs that are support= ed > on an > + adapter with this instance of EFI_ADAPTER_INFORMATION_PROTOCOL. > The list is returned > + in InfoTypesBuffer, and the number of GUID pointers in InfoTypesBuffer= is > returned in > + InfoTypesBufferCount. > + > + @param[in] This A pointer to the > EFI_ADAPTER_INFORMATION_PROTOCOL instance. > + @param[out] InfoTypesBuffer A pointer to the list of Information= Type > GUID pointers that are supported > + by This. > + @param[out] InfoTypesBufferCount A pointer to the number of GUID > pointers present in InfoTypesBuffer. > + > + @retval EFI_SUCCESS The list of information type GUIDs t= hat are > supported on this adapter was > + returned in InfoTypesBuffer. The num= ber of > information type GUIDs was > + returned in InfoTypesBufferCount. > + @retval EFI_INVALID_PARAMETER This is NULL. > + @retval EFI_INVALID_PARAMETER InfoTypesBuffer is NULL. > + @retval EFI_INVALID_PARAMETER InfoTypesBufferCount is NULL. > + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to > store the results. > + > +**/ > +EFI_STATUS > +EFIAPI > +UndiAipGetSupportedTypes ( > + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, > + OUT EFI_GUID **InfoTypesBuffer, > + OUT UINTN *InfoTypesBufferCount > + ); > + > +#endif > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/UndiAipImpl.c > b/Drivers/OptionRomPkg/UndiRuntimeDxe/UndiAipImpl.c > new file mode 100644 > index 0000000000..21151a076f > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/UndiAipImpl.c > @@ -0,0 +1,145 @@ > +/** @file > + > +Copyright (c) 2015, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > + > +#include "Undi32.h" > + > + > +UINTN mSupportedInfoTypesCount =3D 1; > +EFI_GUID mSupportedInfoTypes[] =3D { > + EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT_GUID > +}; > + > +/** > + Returns the current state information for the adapter. > + > + This function returns information of type InformationType from the > adapter. > + If an adapter does not support the requested informational type, then > + EFI_UNSUPPORTED is returned. > + > + @param[in] This A pointer to the > EFI_ADAPTER_INFORMATION_PROTOCOL instance. > + @param[in] InformationType A pointer to an EFI_GUID that defin= es > the contents of InformationBlock. > + @param[out] InforamtionBlock The service returns a pointer to th= e > buffer with the InformationBlock > + structure which contains details ab= out the data > specific to InformationType. > + @param[out] InforamtionBlockSize The driver returns the size of the > InformationBlock in bytes. > + > + @retval EFI_SUCCESS The InformationType information was > retrieved. > + @retval EFI_UNSUPPORTED The InformationType is not known. > + @retval EFI_DEVICE_ERROR The device reported an error. > + @retval EFI_OUT_OF_RESOURCES The request could not be completed > due to a lack of resources. > + @retval EFI_INVALID_PARAMETER This is NULL. > + @retval EFI_INVALID_PARAMETER InformationBlock is NULL. > + @retval EFI_INVALID_PARAMETER InformationBlockSize is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +UndiAipGetInfo ( > + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, > + IN EFI_GUID *InformationType, > + OUT VOID **InformationBlock, > + OUT UINTN *InformationBlockSize > + ) > +{ > + UNDI32_DEV *UNDI32Device; > + EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *UndiIpv6Support; > + > + if (This =3D=3D NULL || InformationBlock =3D=3D NULL || InformationBlo= ckSize =3D=3D > NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!CompareGuid (InformationType, > &gEfiAdapterInfoUndiIpv6SupportGuid)) { > + return EFI_UNSUPPORTED; > + } > + > + UNDI32Device =3D UNDI_DEV_FROM_AIP (This); > + *InformationBlockSize =3D sizeof > (EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT); > + *InformationBlock =3D AllocateZeroPool (*InformationBlockSize); > + if (*InformationBlock =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + UndiIpv6Support =3D (EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *) > (*InformationBlock); > + UndiIpv6Support->Ipv6Support =3D UNDI32Device- > >NIIProtocol_31.Ipv6Supported; > + > + return EFI_SUCCESS; > +} > + > +/** > + Sets state information for an adapter. > + > + This function sends information of type InformationType for an adapter= . > + If an adapter does not support the requested information type, then > EFI_UNSUPPORTED > + is returned. > + > + @param[in] This A pointer to the > EFI_ADAPTER_INFORMATION_PROTOCOL instance. > + @param[in] InformationType A pointer to an EFI_GUID that defin= es > the contents of InformationBlock. > + @param[in] InforamtionBlock A pointer to the InformationBlock > structure which contains details > + about the data specific to Informat= ionType. > + @param[in] InforamtionBlockSize The size of the InformationBlock in > bytes. > + > + @retval EFI_SUCCESS The information was received and > interpreted successfully. > + @retval EFI_UNSUPPORTED The InformationType is not known. > + @retval EFI_DEVICE_ERROR The device reported an error. > + @retval EFI_INVALID_PARAMETER This is NULL. > + @retval EFI_INVALID_PARAMETER InformationBlock is NULL. > + @retval EFI_WRITE_PROTECTED The InformationType cannot be > modified using EFI_ADAPTER_INFO_SET_INFO(). > + > +**/ > +EFI_STATUS > +EFIAPI > +UndiAipSetInfo ( > + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, > + IN EFI_GUID *InformationType, > + IN VOID *InformationBlock, > + IN UINTN InformationBlockSize > + ) > +{ > + return EFI_WRITE_PROTECTED; > +} > + > +/** > + Get a list of supported information types for this instance of the pro= tocol. > + > + This function returns a list of InformationType GUIDs that are support= ed > on an > + adapter with this instance of EFI_ADAPTER_INFORMATION_PROTOCOL. > The list is returned > + in InfoTypesBuffer, and the number of GUID pointers in InfoTypesBuffer= is > returned in > + InfoTypesBufferCount. > + > + @param[in] This A pointer to the > EFI_ADAPTER_INFORMATION_PROTOCOL instance. > + @param[out] InfoTypesBuffer A pointer to the list of Information= Type > GUID pointers that are supported > + by This. > + @param[out] InfoTypesBufferCount A pointer to the number of GUID > pointers present in InfoTypesBuffer. > + > + @retval EFI_SUCCESS The list of information type GUIDs t= hat are > supported on this adapter was > + returned in InfoTypesBuffer. The num= ber of > information type GUIDs was > + returned in InfoTypesBufferCount. > + @retval EFI_INVALID_PARAMETER This is NULL. > + @retval EFI_INVALID_PARAMETER InfoTypesBuffer is NULL. > + @retval EFI_INVALID_PARAMETER InfoTypesBufferCount is NULL. > + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to > store the results. > + > +**/ > +EFI_STATUS > +EFIAPI > +UndiAipGetSupportedTypes ( > + IN EFI_ADAPTER_INFORMATION_PROTOCOL *This, > + OUT EFI_GUID **InfoTypesBuffer, > + OUT UINTN *InfoTypesBufferCount > + ) > +{ > + if (This =3D=3D NULL || InfoTypesBuffer =3D=3D NULL || InfoTypesBuffer= Count =3D=3D > NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + *InfoTypesBufferCount =3D 1; > + *InfoTypesBuffer =3D AllocateCopyPool (sizeof (EFI_GUID), > &gEfiAdapterInfoUndiIpv6SupportGuid); > + if (InfoTypesBuffer =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + return EFI_SUCCESS; > +} > diff --git a/Drivers/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf > b/Drivers/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf > new file mode 100644 > index 0000000000..96666dc88a > --- /dev/null > +++ b/Drivers/OptionRomPkg/UndiRuntimeDxe/UndiRuntimeDxe.inf > @@ -0,0 +1,72 @@ > +## @file > +# Component description file for Undi module. > +# > +# This module provides support for Universal Network Driver Interface. > +# Notes: this module is no longer regular maintained/validated. > +# > +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
> +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010005 > + BASE_NAME =3D UndiRuntimeDxe > + FILE_GUID =3D A1f436EA-A127-4EF8-957C-8048606FF67= 0 > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 1.0 > + > + ENTRY_POINT =3D InitializeUndi > + > +# > +# VALID_ARCHITECTURES =3D IA32 X64 EBC > +# > + > +[Sources] > + Undi32.h > + E100b.h > + E100b.c > + Decode.c > + Init.c > + ComponentName.c > + UndiAipImpl.c > + > +[Packages] > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + UefiLib > + UefiBootServicesTableLib > + BaseMemoryLib > + DebugLib > + UefiRuntimeLib > + UefiDriverEntryPoint > + BaseLib > + MemoryAllocationLib > + > +[Protocols] > + gEfiNetworkInterfaceIdentifierProtocolGuid_31 > + gEfiPciIoProtocolGuid > + gEfiDevicePathProtocolGuid > + gEfiAdapterInformationProtocolGuid > + > +[Guids] > + gEfiEventExitBootServicesGuid ## PRODUCES ## Event > + gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event > + gEfiAdapterInfoUndiIpv6SupportGuid ## PRODUCES > + > +[Depex] > + gEfiBdsArchProtocolGuid AND > + gEfiCpuArchProtocolGuid AND > + gEfiMetronomeArchProtocolGuid AND > + gEfiMonotonicCounterArchProtocolGuid AND > + gEfiRealTimeClockArchProtocolGuid AND > + gEfiResetArchProtocolGuid AND > + gEfiRuntimeArchProtocolGuid AND > + gEfiSecurityArchProtocolGuid AND > + gEfiTimerArchProtocolGuid AND > + gEfiVariableWriteArchProtocolGuid AND > + gEfiVariableArchProtocolGuid AND > + gEfiWatchdogTimerArchProtocolGuid > -- > 2.21.0.windows.1