+/*++\r
+ \r
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR> \r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+\r
+Module Name:\r
+\r
+ IsaIo.c\r
+ \r
+Abstract:\r
+\r
+ The implementation for EFI_ISA_IO_PROTOCOL. \r
+\r
+--*/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "InternalIsaIo.h"\r
+\r
+#include <IndustryStandard/Pcat.h>\r
+\r
+//\r
+// Driver Support Global Variables\r
+//\r
+EFI_ISA_IO_PROTOCOL IsaIoInterface = {\r
+ { \r
+ IsaIoMemRead,\r
+ IsaIoMemWrite\r
+ },\r
+ { \r
+ IsaIoIoRead,\r
+ IsaIoIoWrite\r
+ },\r
+ IsaIoCopyMem,\r
+ IsaIoMap,\r
+ IsaIoUnmap,\r
+ IsaIoAllocateBuffer,\r
+ IsaIoFreeBuffer,\r
+ IsaIoFlush,\r
+ NULL,\r
+ 0,\r
+ NULL\r
+};\r
+\r
+static EFI_ISA_DMA_REGISTERS DmaRegisters[8] = {\r
+ {\r
+ 0x00,\r
+ 0x87,\r
+ 0x01\r
+ },\r
+ {\r
+ 0x02,\r
+ 0x83,\r
+ 0x03\r
+ },\r
+ {\r
+ 0x04,\r
+ 0x81,\r
+ 0x05\r
+ },\r
+ {\r
+ 0x06,\r
+ 0x82,\r
+ 0x07\r
+ },\r
+ {\r
+ 0x00,\r
+ 0x00,\r
+ 0x00\r
+ }, // Channel 4 is invalid\r
+ {\r
+ 0xC4,\r
+ 0x8B,\r
+ 0xC6\r
+ },\r
+ {\r
+ 0xC8,\r
+ 0x89,\r
+ 0xCA\r
+ },\r
+ {\r
+ 0xCC,\r
+ 0x8A,\r
+ 0xCE\r
+ },\r
+};\r
+\r
+EFI_STATUS\r
+ReportErrorStatusCode (\r
+ EFI_STATUS_CODE_VALUE Code\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ report a error Status code of PCI bus driver controller\r
+\r
+Arguments:\r
+\r
+ Code - The error status code.\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Success to report status code.\r
+ \r
+\r
+--*/\r
+{\r
+ return REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ Code\r
+ );\r
+}\r
+\r
+//\r
+// Driver Support Functions\r
+//\r
+\r
+EFI_STATUS\r
+InitializeIsaIoInstance (\r
+ IN ISA_IO_DEVICE *IsaIoDevice,\r
+ IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initializes an ISA I/O Instance\r
+\r
+Arguments:\r
+\r
+ IsaIoDevice - The iso device to be initialized.\r
+ IsaDeviceResourceList - The resource list.\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Initial success.\r
+ \r
+--*/\r
+{\r
+ //\r
+ // Initializes an ISA I/O Instance\r
+ //\r
+ CopyMem (\r
+ &IsaIoDevice->IsaIo,\r
+ &IsaIoInterface,\r
+ sizeof (EFI_ISA_IO_PROTOCOL)\r
+ );\r
+\r
+ IsaIoDevice->IsaIo.ResourceList = IsaDeviceResourceList;\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoIoRead (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Performs an ISA I/O Read Cycle\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Width - Signifies the width of the I/O operation.\r
+ Offset - The offset in ISA I/O space to start the I/O operation. \r
+ Count - The number of I/O operations to perform. \r
+ Buffer - The destination buffer to store the results\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was read from the device sucessfully.\r
+ EFI_UNSUPPORTED - The Offset is not valid for this device.\r
+ EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Verify Isa IO Access\r
+ //\r
+ Status = IsaIoVerifyAccess (\r
+ IsaIoDevice,\r
+ IsaAccessTypeIo,\r
+ Width,\r
+ Count,\r
+ &Offset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Call PciIo->Io.Read\r
+ //\r
+ Status = IsaIoDevice->PciIo->Io.Read (\r
+ IsaIoDevice->PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Offset,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoIoWrite (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Performs an ISA I/O Write Cycle\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Width - Signifies the width of the I/O operation.\r
+ Offset - The offset in ISA I/O space to start the I/O operation. \r
+ Count - The number of I/O operations to perform. \r
+ Buffer - The source buffer to write data from\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was writen to the device sucessfully.\r
+ EFI_UNSUPPORTED - The Offset is not valid for this device.\r
+ EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Verify Isa IO Access\r
+ //\r
+ Status = IsaIoVerifyAccess (\r
+ IsaIoDevice,\r
+ IsaAccessTypeIo,\r
+ Width,\r
+ Count,\r
+ &Offset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Call PciIo->Io.Write\r
+ //\r
+ Status = IsaIoDevice->PciIo->Io.Write (\r
+ IsaIoDevice->PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Offset,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+WritePort (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Value\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Writes an 8 bit I/O Port\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Offset - The offset in ISA IO space to start the IO operation. \r
+ Value - The data to write port.\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Success.\r
+ EFI_INVALID_PARAMETER - Parameter is invalid.\r
+ EFI_UNSUPPORTED - The address range specified by Offset is not valid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+ \r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Call PciIo->Io.Write\r
+ //\r
+ Status = IsaIoDevice->PciIo->Io.Write (\r
+ IsaIoDevice->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Offset,\r
+ 1,\r
+ &Value\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ return Status;\r
+ }\r
+\r
+ gBS->Stall (50);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+WriteDmaPort (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN UINT32 AddrOffset,\r
+ IN UINT32 PageOffset,\r
+ IN UINT32 CountOffset,\r
+ IN UINT32 BaseAddress,\r
+ IN UINT16 Count\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Writes I/O operation base address and count number to a 8 bit I/O Port.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ AddrOffset - The address' offset.\r
+ PageOffset - The page's offest.\r
+ CountOffset - The count's offset.\r
+ BaseAddress - The base address.\r
+ Count - The number of I/O operations to perform. \r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Success.\r
+ EFI_INVALID_PARAMETER - Parameter is invalid.\r
+ EFI_UNSUPPORTED - The address range specified by these Offsets and Count is not valid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoUnmap (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Unmaps a memory region for DMA\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Mapping - The mapping value returned from EFI_ISA_IO.Map().\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The range was unmapped.\r
+ EFI_DEVICE_ERROR - The data was not committed to the target system memory.\r
+\r
+--*/\r
+{\r
+ ISA_MAP_INFO *IsaMapInfo;\r
+\r
+ //\r
+ // Unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportDma)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // See if the Map() operation associated with this Unmap() required a mapping\r
+ // buffer.If a mapping buffer was not required, then this function simply\r
+ // returns EFI_SUCCESS.\r
+ //\r
+ if (Mapping != NULL) {\r
+ //\r
+ // Get the MAP_INFO structure from Mapping\r
+ //\r
+ IsaMapInfo = (ISA_MAP_INFO *) Mapping;\r
+\r
+ //\r
+ // If this is a write operation from the Agent's point of view,\r
+ // then copy the contents of the mapped buffer into the real buffer\r
+ // so the processor can read the contents of the real buffer.\r
+ //\r
+ if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {\r
+ CopyMem (\r
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,\r
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,\r
+ IsaMapInfo->NumberOfBytes\r
+ );\r
+ }\r
+ //\r
+ // Free the mapped buffer and the MAP_INFO structure.\r
+ //\r
+ gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);\r
+ gBS->FreePool (IsaMapInfo);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoFlush (\r
+ IN EFI_ISA_IO_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes a DMA buffer\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The buffers were flushed.\r
+ EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Call PciIo->Flush\r
+ //\r
+ Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IsaIoVerifyAccess (\r
+ IN ISA_IO_DEVICE *IsaIoDevice,\r
+ IN ISA_ACCESS_TYPE Type,\r
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
+ IN UINTN Count,\r
+ IN OUT UINT32 *Offset\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Verifies access to an ISA device\r
+\r
+Arguments:\r
+\r
+ IsaIoDevice - The ISA device to be verified.\r
+ Type - The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.\r
+ Width - Signifies the width of the memory operation.\r
+ Count - The number of memory operations to perform. \r
+ Offset - The offset in ISA memory space to start the memory operation. \r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Verify success.\r
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.\r
+ EFI_UNSUPPORTED - The device ont support the access type.\r
+\r
+--*/\r
+{\r
+ EFI_ISA_ACPI_RESOURCE *Item;\r
+ EFI_STATUS Status;\r
+\r
+ if (Width < EfiIsaIoWidthUint8 ||\r
+ Width >= EfiIsaIoWidthMaximum ||\r
+ Width == EfiIsaIoWidthReserved ||\r
+ Width == EfiIsaIoWidthFifoReserved ||\r
+ Width == EfiIsaIoWidthFillReserved\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX\r
+ // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX\r
+ //\r
+ if (Width >= EfiIsaIoWidthFifoUint8 && Width <= EfiIsaIoWidthFifoReserved) {\r
+ Count = 1;\r
+ }\r
+\r
+ Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ Item = IsaIoDevice->IsaIo.ResourceList->ResourceItem;\r
+ while (Item->Type != EfiIsaAcpiResourceEndOfList) {\r
+ if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||\r
+ (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)\r
+ ) {\r
+ if (*Offset >= Item->StartRange && (*Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (*Offset >= Item->StartRange && *Offset <= Item->EndRange) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ Item++;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoMemRead (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Performs an ISA Memory Read Cycle\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Width - Signifies the width of the memory operation.\r
+ Offset - The offset in ISA memory space to start the memory operation. \r
+ Count - The number of memory operations to perform. \r
+ Buffer - The destination buffer to store the results\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was read from the device successfully.\r
+ EFI_UNSUPPORTED - The Offset is not valid for this device.\r
+ EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ //\r
+ // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for \r
+ // ISA Bus Master.\r
+ //\r
+ // So we just return EFI_UNSUPPORTED for these functions.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Verify the Isa Io Access\r
+ //\r
+ Status = IsaIoVerifyAccess (\r
+ IsaIoDevice,\r
+ IsaAccessTypeMem,\r
+ Width,\r
+ Count,\r
+ &Offset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Call PciIo->Mem.Read\r
+ //\r
+ Status = IsaIoDevice->PciIo->Mem.Read (\r
+ IsaIoDevice->PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Offset,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoMemWrite (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Offset,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Performs an ISA Memory Write Cycle\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance. \r
+ Width - Signifies the width of the memory operation.\r
+ Offset - The offset in ISA memory space to start the memory operation. \r
+ Count - The number of memory operations to perform. \r
+ Buffer - The source buffer to write data from\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was written to the device sucessfully.\r
+ EFI_UNSUPPORTED - The Offset is not valid for this device.\r
+ EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ //\r
+ // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for \r
+ // ISA Bus Master.\r
+ //\r
+ // So we just return EFI_UNSUPPORTED for these functions.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Verify Isa IO Access\r
+ //\r
+ Status = IsaIoVerifyAccess (\r
+ IsaIoDevice,\r
+ IsaAccessTypeMem,\r
+ Width,\r
+ Count,\r
+ &Offset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Call PciIo->Mem.Write\r
+ //\r
+ Status = IsaIoDevice->PciIo->Mem.Write (\r
+ IsaIoDevice->PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ Offset,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoCopyMem (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 DestOffset,\r
+ IN UINT32 SrcOffset,\r
+ IN UINTN Count\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Performs an ISA I/O Copy Memory \r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Width - Signifies the width of the memory copy operation.\r
+ DestOffset - The offset of the destination \r
+ SrcOffset - The offset of the source\r
+ Count - The number of memory copy operations to perform\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was copied sucessfully.\r
+ EFI_UNSUPPORTED - The DestOffset or SrcOffset is not valid for this device.\r
+ EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.\r
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ //\r
+ // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for \r
+ // ISA Bus Master.\r
+ //\r
+ // So we just return EFI_UNSUPPORTED for these functions.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ //\r
+ // Verify Isa IO Access for destination and source\r
+ //\r
+ Status = IsaIoVerifyAccess (\r
+ IsaIoDevice,\r
+ IsaAccessTypeMem,\r
+ Width,\r
+ Count,\r
+ &DestOffset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = IsaIoVerifyAccess (\r
+ IsaIoDevice,\r
+ IsaAccessTypeMem,\r
+ Width,\r
+ Count,\r
+ &SrcOffset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Call PciIo->CopyMem\r
+ //\r
+ Status = IsaIoDevice->PciIo->CopyMem (\r
+ IsaIoDevice->PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ DestOffset,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ SrcOffset,\r
+ Count\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+IsaIoMap_OnlySupportSlaveReadWrite (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,\r
+ IN UINT8 ChannelNumber OPTIONAL,\r
+ IN UINT32 ChannelAttributes,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Maps a memory region for DMA, note this implementation\r
+ only supports slave read/write operation to save code size.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Operation - Indicates the type of DMA (slave or bus master), and if \r
+ the DMA operation is going to read or write to system memory. \r
+ ChannelNumber - The slave channel number to use for this DMA operation. \r
+ If Operation and ChannelAttributes shows that this device \r
+ performs bus mastering DMA, then this field is ignored. \r
+ The legal range for this field is 0..7. \r
+ ChannelAttributes - The attributes of the DMA channel to use for this DMA operation\r
+ HostAddress - The system memory address to map to the device. \r
+ NumberOfBytes - On input the number of bytes to map. On output the number \r
+ of bytes that were mapped.\r
+ DeviceAddress - The resulting map address for the bus master device to use \r
+ to access the hosts HostAddress. \r
+ Mapping - A resulting value to pass to EFI_ISA_IO.Unmap().\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.\r
+ EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.\r
+ EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.\r
+ EFI_DEVICE_ERROR - The system hardware could not map the requested address.\r
+ EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ ISA_MAP_INFO *IsaMapInfo;\r
+ UINT8 DmaMode;\r
+ UINTN MaxNumberOfBytes;\r
+ UINT32 BaseAddress;\r
+ UINT16 Count;\r
+\r
+ UINT8 DmaMask;\r
+ UINT8 DmaClear;\r
+ UINT8 DmaChannelMode;\r
+ \r
+ if ((NULL == This) ||\r
+ (NULL == HostAddress) ||\r
+ (NULL == NumberOfBytes) ||\r
+ (NULL == DeviceAddress) ||\r
+ (NULL == Mapping)\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+\r
+ //\r
+ // Initialize the return values to their defaults\r
+ //\r
+ *Mapping = NULL;\r
+\r
+ //\r
+ // Make sure the Operation parameter is valid.\r
+ // Light IsaIo only supports two operations.\r
+ //\r
+ if (!(Operation == EfiIsaIoOperationSlaveRead || \r
+ Operation == EfiIsaIoOperationSlaveWrite)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (ChannelNumber >= 4) {\r
+ //\r
+ // The Light IsaIo doesn't support channelNumber larger than 4.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Map the HostAddress to a DeviceAddress.\r
+ //\r
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
+ if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {\r
+ //\r
+ // Common Buffer operations can not be remapped. If the common buffer\r
+ // is above 16MB, then it is not possible to generate a mapping, so return\r
+ // an error.\r
+ //\r
+ if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()\r
+ // is called later.\r
+ //\r
+ IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));\r
+ if (IsaMapInfo == NULL) {\r
+ *NumberOfBytes = 0;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Return a pointer to the MAP_INFO structure in Mapping\r
+ //\r
+ *Mapping = IsaMapInfo;\r
+\r
+ //\r
+ // Initialize the MAP_INFO structure\r
+ //\r
+ IsaMapInfo->Operation = Operation;\r
+ IsaMapInfo->NumberOfBytes = *NumberOfBytes;\r
+ IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);\r
+ IsaMapInfo->HostAddress = PhysicalAddress;\r
+ IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;\r
+\r
+ //\r
+ // Allocate a buffer below 16MB to map the transfer to.\r
+ //\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiBootServicesData,\r
+ IsaMapInfo->NumberOfPages,\r
+ &IsaMapInfo->MappedHostAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (IsaMapInfo);\r
+ *NumberOfBytes = 0;\r
+ *Mapping = NULL;\r
+ return Status;\r
+ }\r
+ //\r
+ // If this is a read operation from the DMA agents's point of view,\r
+ // then copy the contents of the real buffer into the mapped buffer\r
+ // so the DMA agent can read the contents of the real buffer.\r
+ //\r
+ if (Operation == EfiIsaIoOperationSlaveRead) {\r
+ CopyMem (\r
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,\r
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,\r
+ IsaMapInfo->NumberOfBytes\r
+ );\r
+ }\r
+ //\r
+ // The DeviceAddress is the address of the maped buffer below 16 MB\r
+ //\r
+ *DeviceAddress = IsaMapInfo->MappedHostAddress;\r
+ } else {\r
+ //\r
+ // The transfer is below 16 MB, so the DeviceAddress is simply the\r
+ // HostAddress\r
+ //\r
+ *DeviceAddress = PhysicalAddress;\r
+ }\r
+ \r
+ //\r
+ // Figure out what to program into the DMA Channel Mode Register\r
+ //\r
+ DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));\r
+ if (Operation == EfiIsaIoOperationSlaveRead) {\r
+ DmaMode |= V_8237_DMA_CHMODE_MEM2IO;\r
+ } else {\r
+ DmaMode |= V_8237_DMA_CHMODE_IO2MEM;\r
+ }\r
+ //\r
+ // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo\r
+ //\r
+ DmaMode |= V_8237_DMA_CHMODE_SINGLE;\r
+\r
+ //\r
+ // A Slave DMA transfer can not cross a 64K boundary.\r
+ // Compute *NumberOfBytes based on this restriction.\r
+ //\r
+ MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);\r
+ if (*NumberOfBytes > MaxNumberOfBytes) {\r
+ *NumberOfBytes = MaxNumberOfBytes;\r
+ }\r
+ //\r
+ // Compute the values to program into the BaseAddress and Count registers\r
+ // of the Slave DMA controller\r
+ //\r
+ BaseAddress = (UINT32) (*DeviceAddress);\r
+ Count = (UINT16) (*NumberOfBytes - 1);\r
+ //\r
+ // Program the DMA Write Single Mask Register for ChannelNumber\r
+ // Clear the DMA Byte Pointer Register\r
+ //\r
+ DmaMask = R_8237_DMA_WRSMSK_CH0_3;\r
+ DmaClear = R_8237_DMA_CBPR_CH0_3;\r
+ DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;\r
+\r
+ Status = WritePort (\r
+ This,\r
+ DmaMask,\r
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (\r
+ This,\r
+ DmaClear,\r
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (This, DmaChannelMode, DmaMode);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WriteDmaPort (\r
+ This,\r
+ DmaRegisters[ChannelNumber].Address,\r
+ DmaRegisters[ChannelNumber].Page,\r
+ DmaRegisters[ChannelNumber].Count,\r
+ BaseAddress,\r
+ Count\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (\r
+ This,\r
+ DmaMask,\r
+ (UINT8) (ChannelNumber & 0x03)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+IsaIoMap_FullSupport (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,\r
+ IN UINT8 ChannelNumber OPTIONAL,\r
+ IN UINT32 ChannelAttributes,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Maps a memory region for DMA. This implementation implement the \r
+ the full mapping support.\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Operation - Indicates the type of DMA (slave or bus master), and if \r
+ the DMA operation is going to read or write to system memory. \r
+ ChannelNumber - The slave channel number to use for this DMA operation. \r
+ If Operation and ChannelAttributes shows that this device \r
+ performs bus mastering DMA, then this field is ignored. \r
+ The legal range for this field is 0..7. \r
+ ChannelAttributes - The attributes of the DMA channel to use for this DMA operation\r
+ HostAddress - The system memory address to map to the device. \r
+ NumberOfBytes - On input the number of bytes to map. On output the number \r
+ of bytes that were mapped.\r
+ DeviceAddress - The resulting map address for the bus master device to use \r
+ - to access the hosts HostAddress. \r
+ Mapping - A resulting value to pass to EFI_ISA_IO.Unmap().\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.\r
+ EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.\r
+ EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.\r
+ EFI_DEVICE_ERROR - The system hardware could not map the requested address.\r
+ EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN Master;\r
+ BOOLEAN Read;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ ISA_MAP_INFO *IsaMapInfo;\r
+ UINT8 DmaMode;\r
+ UINTN MaxNumberOfBytes;\r
+ UINT32 BaseAddress;\r
+ UINT16 Count;\r
+\r
+ UINT8 DmaMask;\r
+ UINT8 DmaClear;\r
+ UINT8 DmaChannelMode;\r
+\r
+ if ((NULL == This) ||\r
+ (NULL == HostAddress) ||\r
+ (NULL == NumberOfBytes) ||\r
+ (NULL == DeviceAddress) ||\r
+ (NULL == Mapping)\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+\r
+ //\r
+ // Initialize the return values to their defaults\r
+ //\r
+ *Mapping = NULL;\r
+\r
+ //\r
+ // Make sure the Operation parameter is valid\r
+ //\r
+ if (Operation < 0 || Operation >= EfiIsaIoOperationMaximum) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // See if this is a Slave DMA Operation\r
+ //\r
+ Master = TRUE;\r
+ Read = FALSE;\r
+ if (Operation == EfiIsaIoOperationSlaveRead) {\r
+ Operation = EfiIsaIoOperationBusMasterRead;\r
+ Master = FALSE;\r
+ Read = TRUE;\r
+ }\r
+\r
+ if (Operation == EfiIsaIoOperationSlaveWrite) {\r
+ Operation = EfiIsaIoOperationBusMasterWrite;\r
+ Master = FALSE;\r
+ Read = FALSE;\r
+ }\r
+\r
+ if (!Master) {\r
+ //\r
+ // Make sure that ChannelNumber is a valid channel number\r
+ // Channel 4 is used to cascade, so it is illegal.\r
+ //\r
+ if (ChannelNumber == 4 || ChannelNumber > 7) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // This implementation only support COMPATIBLE DMA Transfers\r
+ //\r
+ if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (ChannelAttributes &\r
+ (\r
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |\r
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |\r
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C\r
+ )\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (ChannelNumber < 4) {\r
+ //\r
+ // If this is Channel 0..3, then the width must be 8 bit\r
+ //\r
+ if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) ||\r
+ (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16)\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ //\r
+ // If this is Channel 4..7, then the width must be 16 bit\r
+ //\r
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) ||\r
+ (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16))\r
+ ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ //\r
+ // Either Demand Mode or Single Mode must be selected, but not both\r
+ //\r
+ if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) {\r
+ if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Map the HostAddress to a DeviceAddress.\r
+ //\r
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
+ if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {\r
+ //\r
+ // Common Buffer operations can not be remapped. If the common buffer\r
+ // is above 16MB, then it is not possible to generate a mapping, so return\r
+ // an error.\r
+ //\r
+ if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()\r
+ // is called later.\r
+ //\r
+ IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));\r
+ if (IsaMapInfo == NULL) {\r
+ *NumberOfBytes = 0;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Return a pointer to the MAP_INFO structure in Mapping\r
+ //\r
+ *Mapping = IsaMapInfo;\r
+\r
+ //\r
+ // Initialize the MAP_INFO structure\r
+ //\r
+ IsaMapInfo->Operation = Operation;\r
+ IsaMapInfo->NumberOfBytes = *NumberOfBytes;\r
+ IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);\r
+ IsaMapInfo->HostAddress = PhysicalAddress;\r
+ IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;\r
+\r
+ //\r
+ // Allocate a buffer below 16MB to map the transfer to.\r
+ //\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiBootServicesData,\r
+ IsaMapInfo->NumberOfPages,\r
+ &IsaMapInfo->MappedHostAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (IsaMapInfo);\r
+ *NumberOfBytes = 0;\r
+ *Mapping = NULL;\r
+ return Status;\r
+ }\r
+ //\r
+ // If this is a read operation from the DMA agents's point of view,\r
+ // then copy the contents of the real buffer into the mapped buffer\r
+ // so the DMA agent can read the contents of the real buffer.\r
+ //\r
+ if (Operation == EfiIsaIoOperationBusMasterRead) {\r
+ CopyMem (\r
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,\r
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,\r
+ IsaMapInfo->NumberOfBytes\r
+ );\r
+ }\r
+ //\r
+ // The DeviceAddress is the address of the maped buffer below 16 MB\r
+ //\r
+ *DeviceAddress = IsaMapInfo->MappedHostAddress;\r
+ } else {\r
+ //\r
+ // The transfer is below 16 MB, so the DeviceAddress is simply the\r
+ // HostAddress\r
+ //\r
+ *DeviceAddress = PhysicalAddress;\r
+ }\r
+ //\r
+ // If this is a Bus Master operation then return\r
+ //\r
+ if (Master) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Figure out what to program into the DMA Channel Mode Register\r
+ //\r
+ DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));\r
+ if (Read) {\r
+ DmaMode |= V_8237_DMA_CHMODE_MEM2IO;\r
+ } else {\r
+ DmaMode |= V_8237_DMA_CHMODE_IO2MEM;\r
+ }\r
+\r
+ if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) {\r
+ DmaMode |= B_8237_DMA_CHMODE_AE;\r
+ }\r
+\r
+ if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) {\r
+ DmaMode |= V_8237_DMA_CHMODE_DEMAND;\r
+ }\r
+\r
+ if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) {\r
+ DmaMode |= V_8237_DMA_CHMODE_SINGLE;\r
+ }\r
+ //\r
+ // A Slave DMA transfer can not cross a 64K boundary.\r
+ // Compute *NumberOfBytes based on this restriction.\r
+ //\r
+ MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);\r
+ if (*NumberOfBytes > MaxNumberOfBytes) {\r
+ *NumberOfBytes = MaxNumberOfBytes;\r
+ }\r
+ //\r
+ // Compute the values to program into the BaseAddress and Count registers\r
+ // of the Slave DMA controller\r
+ //\r
+ if (ChannelNumber < 4) {\r
+ BaseAddress = (UINT32) (*DeviceAddress);\r
+ Count = (UINT16) (*NumberOfBytes - 1);\r
+ } else {\r
+ BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));\r
+ Count = (UINT16) ((*NumberOfBytes - 1) >> 1);\r
+ }\r
+ //\r
+ // Program the DMA Write Single Mask Register for ChannelNumber\r
+ // Clear the DMA Byte Pointer Register\r
+ //\r
+ if (ChannelNumber < 4) {\r
+ DmaMask = R_8237_DMA_WRSMSK_CH0_3;\r
+ DmaClear = R_8237_DMA_CBPR_CH0_3;\r
+ DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;\r
+ } else {\r
+ DmaMask = R_8237_DMA_WRSMSK_CH4_7;\r
+ DmaClear = R_8237_DMA_CBPR_CH4_7;\r
+ DmaChannelMode = R_8237_DMA_CHMODE_CH4_7;\r
+ }\r
+\r
+ Status = WritePort (\r
+ This,\r
+ DmaMask,\r
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (\r
+ This,\r
+ DmaClear,\r
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (This, DmaChannelMode, DmaMode);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WriteDmaPort (\r
+ This,\r
+ DmaRegisters[ChannelNumber].Address,\r
+ DmaRegisters[ChannelNumber].Page,\r
+ DmaRegisters[ChannelNumber].Count,\r
+ BaseAddress,\r
+ Count\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = WritePort (\r
+ This,\r
+ DmaMask,\r
+ (UINT8) (ChannelNumber & 0x03)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoMap (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,\r
+ IN UINT8 ChannelNumber OPTIONAL,\r
+ IN UINT32 ChannelAttributes,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Maps a memory region for DMA\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Operation - Indicates the type of DMA (slave or bus master), and if \r
+ the DMA operation is going to read or write to system memory. \r
+ ChannelNumber - The slave channel number to use for this DMA operation. \r
+ If Operation and ChannelAttributes shows that this device \r
+ performs bus mastering DMA, then this field is ignored. \r
+ The legal range for this field is 0..7. \r
+ ChannelAttributes - The attributes of the DMA channel to use for this DMA operation\r
+ HostAddress - The system memory address to map to the device. \r
+ NumberOfBytes - On input the number of bytes to map. On output the number \r
+ of bytes that were mapped.\r
+ DeviceAddress - The resulting map address for the bus master device to use \r
+ - to access the hosts HostAddress. \r
+ Mapping - A resulting value to pass to EFI_ISA_IO.Unmap().\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.\r
+ EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.\r
+ EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.\r
+ EFI_DEVICE_ERROR - The system hardware could not map the requested address.\r
+ EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.\r
+\r
+--*/\r
+{\r
+ //\r
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportDma)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for \r
+ // ISA Bus Master.\r
+ //\r
+ // So we just return EFI_UNSUPPORTED for these functions.\r
+ //\r
+ if (FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma)) {\r
+ return IsaIoMap_OnlySupportSlaveReadWrite (\r
+ This,\r
+ Operation,\r
+ ChannelNumber,\r
+ ChannelAttributes,\r
+ HostAddress,\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+\r
+ } else {\r
+ return IsaIoMap_FullSupport (\r
+ This,\r
+ Operation,\r
+ ChannelNumber,\r
+ ChannelAttributes,\r
+ HostAddress,\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ }\r
+}\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoAllocateBuffer (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ IN UINT64 Attributes\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Allocates a common buffer for DMA\r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Type - The type allocation to perform.\r
+ MemoryType - The type of memory to allocate.\r
+ Pages - The number of pages to allocate.\r
+ HostAddress - A pointer to store the base address of the allocated range.\r
+ Attributes - The requested bit mask of attributes for the allocated range.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The requested memory pages were allocated.\r
+ EFI_INVALID_PARAMETER - Type is invalid or MemoryType is invalid or HostAddress is NULL\r
+ EFI_UNSUPPORTED - Attributes is unsupported or the memory range specified \r
+ by HostAddress, Pages, and Type is not available for common buffer use.\r
+ EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+\r
+ //\r
+ // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for \r
+ // ISA Bus Master.\r
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportDma) || FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (HostAddress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Type < AllocateAnyPages || Type >= MaxAllocateType) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData\r
+ //\r
+ if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Attributes &~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (ISA_MAX_MEMORY_ADDRESS - 1);\r
+ if (Type == AllocateAddress) {\r
+ if ((UINTN) (*HostAddress) >= ISA_MAX_MEMORY_ADDRESS) {\r
+ return EFI_UNSUPPORTED;\r
+ } else {\r
+ PhysicalAddress = (UINTN) (*HostAddress);\r
+ }\r
+ }\r
+\r
+ if (Type == AllocateAnyPages) {\r
+ Type = AllocateMaxAddress;\r
+ }\r
+\r
+ Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ return Status;\r
+ }\r
+\r
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoFreeBuffer (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Frees a common buffer \r
+\r
+Arguments:\r
+\r
+ This - A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ Pages - The number of pages to free.\r
+ HostAddress - The base address of the allocated range.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The requested memory pages were freed.\r
+ EFI_INVALID_PARAMETER - The memory was not allocated with EFI_ISA_IO.AllocateBufer().\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+\r
+ //\r
+ // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for \r
+ // ISA Bus Master.\r
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
+ //\r
+ if (!FeaturePcdGet (PcdIsaBusSupportDma) || FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
+ Status = gBS->FreePages (\r
+ PhysicalAddress,\r
+ Pages\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r