+/** @file\r
+ The implementation for EFI_ISA_IO_PROTOCOL. \r
+ \r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IsaIo.h"\r
+\r
+//\r
+// Module Variables\r
+//\r
+EFI_ISA_IO_PROTOCOL mIsaIoInterface = {\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
+EFI_ISA_DMA_REGISTERS mDmaRegisters[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
+/**\r
+ Verifies access to an ISA device\r
+\r
+ @param[in] IsaIoDevice The ISA device to be verified.\r
+ @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.\r
+ @param[in] Width The width of the memory operation.\r
+ @param[in] Count The number of memory operations to perform. \r
+ @param[in] Offset The offset in ISA memory space to start the memory operation. \r
+ \r
+ @retval EFI_SUCCESS Verify success.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
+ @retval EFI_UNSUPPORTED The device ont support the access type.\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 UINT32 Offset\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
+ 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
+/**\r
+ Convert the IO Information in ACPI descriptor to IO ISA Attribute.\r
+\r
+ @param[in] Information The IO Information in ACPI descriptor\r
+\r
+ @return UINT32 The IO ISA Attribute\r
+**/\r
+UINT32\r
+IsaIoAttribute (\r
+ IN UINT8 Information\r
+ )\r
+{\r
+ UINT32 Attribute;\r
+\r
+ Attribute = 0;\r
+\r
+ switch (Information & EFI_ACPI_IO_DECODE_MASK) {\r
+ case EFI_ACPI_IO_DECODE_16_BIT:\r
+ Attribute |= EFI_ISA_ACPI_IO_DECODE_16_BITS;\r
+ break;\r
+ \r
+ case EFI_ACPI_IO_DECODE_10_BIT:\r
+ Attribute |= EFI_ISA_ACPI_IO_DECODE_10_BITS;\r
+ break;\r
+ }\r
+\r
+ return Attribute;\r
+}\r
+\r
+/**\r
+ Convert the IRQ Information in ACPI descriptor to IRQ ISA Attribute.\r
+\r
+ @param[in] Information The IRQ Information in ACPI descriptor\r
+\r
+ @return UINT32 The IRQ ISA Attribute\r
+**/\r
+UINT32\r
+IsaIrqAttribute (\r
+ IN UINT8 Information\r
+ )\r
+{\r
+ UINT32 Attribute;\r
+\r
+ Attribute = 0;\r
+\r
+ if ((Information & EFI_ACPI_IRQ_POLARITY_MASK) == EFI_ACPI_IRQ_HIGH_TRUE) {\r
+ if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {\r
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE;\r
+ } else {\r
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;\r
+ }\r
+ } else {\r
+ if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {\r
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE;\r
+ } else {\r
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE;\r
+ }\r
+ }\r
+ return Attribute;\r
+}\r
+\r
+/**\r
+ Convert the Memory Information in ACPI descriptor to Memory ISA Attribute.\r
+\r
+ @param[in] Information The Memory Information in ACPI descriptor\r
+\r
+ @return UINT32 The Memory ISA Attribute\r
+**/\r
+UINT32\r
+IsaMemoryAttribute (\r
+ IN UINT8 Information\r
+ )\r
+{\r
+ UINT32 Attribute;\r
+\r
+ Attribute = 0;\r
+\r
+ switch (Information & EFI_ACPI_MEMORY_WRITE_STATUS_MASK) {\r
+ case EFI_ACPI_MEMORY_WRITABLE:\r
+ Attribute |= EFI_ISA_ACPI_MEMORY_WRITEABLE;\r
+ break;\r
+ }\r
+\r
+ return Attribute;\r
+}\r
+\r
+/**\r
+ Convert the DMA Information in ACPI descriptor to DMA ISA Attribute.\r
+\r
+ @param[in] Information The DMA Information in ACPI descriptor\r
+\r
+ @return UINT32 The DMA ISA Attribute\r
+**/\r
+UINT32\r
+IsaDmaAttribute (\r
+ IN UINT8 Information\r
+ )\r
+{\r
+ UINT32 Attribute;\r
+\r
+ Attribute = EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE;\r
+ \r
+ switch (Information & EFI_ACPI_DMA_SPEED_TYPE_MASK) {\r
+ case EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY:\r
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE;\r
+ break;\r
+ case EFI_ACPI_DMA_SPEED_TYPE_A:\r
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A;\r
+ break;\r
+ case EFI_ACPI_DMA_SPEED_TYPE_B:\r
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B;\r
+ break;\r
+ case EFI_ACPI_DMA_SPEED_TYPE_F:\r
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C;\r
+ break;\r
+ }\r
+\r
+ switch (Information & EFI_ACPI_DMA_TRANSFER_TYPE_MASK) {\r
+ case EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT:\r
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8;\r
+ break;\r
+ case EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT:\r
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16;\r
+ break;\r
+ }\r
+\r
+ return Attribute;\r
+}\r
+\r
+/**\r
+ Convert the ACPI resource descriptor to ISA resource descriptor.\r
+\r
+ @param[in] AcpiResource Pointer to the ACPI resource descriptor\r
+ @param[out] IsaResource The optional pointer to the buffer to\r
+ store the converted ISA resource descriptor\r
+\r
+ @return UINTN Number of ISA resource descriptor needed\r
+**/\r
+UINTN\r
+AcpiResourceToIsaResource (\r
+ IN ACPI_RESOURCE_HEADER_PTR AcpiResource,\r
+ OUT EFI_ISA_ACPI_RESOURCE *IsaResource OPTIONAL\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINTN Count;\r
+ UINT32 LastIndex;\r
+ EFI_ACPI_IO_PORT_DESCRIPTOR *Io;\r
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;\r
+ EFI_ACPI_IRQ_DESCRIPTOR *Irq;\r
+ EFI_ACPI_DMA_DESCRIPTOR *Dma;\r
+ EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *Memory;\r
+ EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *FixedMemory;\r
+\r
+ Count = 0;\r
+ LastIndex = 0;\r
+\r
+ switch (AcpiResource.SmallHeader->Byte) {\r
+ case ACPI_DMA_DESCRIPTOR:\r
+ Dma = (EFI_ACPI_DMA_DESCRIPTOR *) AcpiResource.SmallHeader;\r
+ for (Index = 0; Index < sizeof (Dma->ChannelMask) * 8; Index++) {\r
+ if (Dma->ChannelMask & (1 << Index)) {\r
+ if ((Count > 0) && (LastIndex + 1 == Index)) {\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count - 1].EndRange ++;\r
+ }\r
+ } else {\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceDma;\r
+ IsaResource[Count].Attribute = IsaDmaAttribute (Dma->Information);\r
+ IsaResource[Count].StartRange = Index;\r
+ IsaResource[Count].EndRange = Index;\r
+ }\r
+ Count ++;\r
+ }\r
+\r
+ LastIndex = Index;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case ACPI_IO_PORT_DESCRIPTOR:\r
+ Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceIo;\r
+ IsaResource[Count].Attribute = IsaIoAttribute (Io->Information);\r
+ IsaResource[Count].StartRange = Io->BaseAddressMin;\r
+ IsaResource[Count].EndRange = Io->BaseAddressMin + Io->Length - 1;\r
+ }\r
+ Count ++;\r
+ break;\r
+\r
+ case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:\r
+ FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceIo;\r
+ IsaResource[Count].Attribute = EFI_ISA_ACPI_IO_DECODE_10_BITS;\r
+ IsaResource[Count].StartRange = FixedIo->BaseAddress;\r
+ IsaResource[Count].EndRange = FixedIo->BaseAddress + FixedIo->Length - 1;\r
+ }\r
+ Count ++;\r
+ break;\r
+\r
+ case ACPI_IRQ_DESCRIPTOR:\r
+ case ACPI_IRQ_NOFLAG_DESCRIPTOR:\r
+ Irq = (EFI_ACPI_IRQ_DESCRIPTOR *) AcpiResource.SmallHeader;\r
+ for (Index = 0; Index < sizeof (Irq->Mask) * 8; Index++) {\r
+ if (Irq->Mask & (1 << Index)) {\r
+ if ((Count > 0) && (LastIndex + 1 == Index)) {\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count - 1].EndRange ++;\r
+ }\r
+ } else {\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceInterrupt;\r
+ if (AcpiResource.SmallHeader->Byte == ACPI_IRQ_DESCRIPTOR) {\r
+ IsaResource[Count].Attribute = IsaIrqAttribute (Irq->Information);\r
+ } else {\r
+ IsaResource[Count].Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;\r
+ }\r
+ IsaResource[Count].StartRange = Index;\r
+ IsaResource[Count].EndRange = Index;\r
+ }\r
+ Count++;\r
+ }\r
+\r
+ LastIndex = Index;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR:\r
+ Memory = (EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceMemory;\r
+ IsaResource[Count].Attribute = IsaMemoryAttribute (Memory->Information);\r
+ IsaResource[Count].StartRange = Memory->BaseAddressMin;\r
+ IsaResource[Count].EndRange = Memory->BaseAddressMin + Memory->Length - 1;\r
+ }\r
+ Count ++;\r
+ break;\r
+\r
+ case ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR:\r
+ FixedMemory = (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceMemory;\r
+ IsaResource[Count].Attribute = IsaMemoryAttribute (FixedMemory->Information);\r
+ IsaResource[Count].StartRange = FixedMemory->BaseAddress;\r
+ IsaResource[Count].EndRange = FixedMemory->BaseAddress + FixedMemory->Length - 1;\r
+ }\r
+ Count ++;\r
+ break;\r
+\r
+ case ACPI_END_TAG_DESCRIPTOR:\r
+ if (IsaResource != NULL) {\r
+ IsaResource[Count].Type = EfiIsaAcpiResourceEndOfList;\r
+ IsaResource[Count].Attribute = 0;\r
+ IsaResource[Count].StartRange = 0;\r
+ IsaResource[Count].EndRange = 0;\r
+ }\r
+ Count ++;\r
+ break;\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+/**\r
+ Initializes an ISA I/O Instance\r
+\r
+ @param[in] IsaIoDevice The isa device to be initialized.\r
+ @param[in] DevicePath The device path of the isa device.\r
+ @param[in] Resources The ACPI resource list.\r
+ \r
+**/\r
+VOID\r
+InitializeIsaIoInstance (\r
+ IN ISA_IO_DEVICE *IsaIoDevice,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN ACPI_RESOURCE_HEADER_PTR Resources\r
+ )\r
+{\r
+ UINTN Index;\r
+ ACPI_HID_DEVICE_PATH *AcpiNode;\r
+ ACPI_RESOURCE_HEADER_PTR ResourcePtr;\r
+\r
+ //\r
+ // Use the ISA IO Protocol structure template to initialize the ISA IO instance\r
+ //\r
+ CopyMem (\r
+ &IsaIoDevice->IsaIo,\r
+ &mIsaIoInterface,\r
+ sizeof (EFI_ISA_IO_PROTOCOL)\r
+ );\r
+\r
+ //\r
+ // Count the resources including the ACPI End Tag\r
+ //\r
+ ResourcePtr = Resources;\r
+ Index = 0;\r
+ while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {\r
+ \r
+ Index += AcpiResourceToIsaResource (ResourcePtr, NULL);\r
+\r
+ if (ResourcePtr.SmallHeader->Bits.Type == 0) {\r
+ ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader\r
+ + ResourcePtr.SmallHeader->Bits.Length\r
+ + sizeof (*ResourcePtr.SmallHeader));\r
+ } else {\r
+ ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader\r
+ + ResourcePtr.LargeHeader->Length\r
+ + sizeof (*ResourcePtr.LargeHeader));\r
+ }\r
+\r
+ }\r
+ //\r
+ // Get the Isa Resource count for ACPI End Tag\r
+ //\r
+ Index += AcpiResourceToIsaResource (ResourcePtr, NULL);\r
+\r
+ //\r
+ // Initialize the ResourceList\r
+ //\r
+ IsaIoDevice->IsaIo.ResourceList = AllocatePool (sizeof (EFI_ISA_ACPI_RESOURCE_LIST) + Index * sizeof (EFI_ISA_ACPI_RESOURCE));\r
+ ASSERT (IsaIoDevice->IsaIo.ResourceList != NULL);\r
+ IsaIoDevice->IsaIo.ResourceList->ResourceItem = (EFI_ISA_ACPI_RESOURCE *) (IsaIoDevice->IsaIo.ResourceList + 1);\r
+\r
+ AcpiNode = (ACPI_HID_DEVICE_PATH *) ((UINT8 *) DevicePath + GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH - sizeof (ACPI_HID_DEVICE_PATH));\r
+ IsaIoDevice->IsaIo.ResourceList->Device.HID = AcpiNode->HID;\r
+ IsaIoDevice->IsaIo.ResourceList->Device.UID = AcpiNode->UID;\r
+\r
+ ResourcePtr = Resources;\r
+ Index = 0;\r
+ while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {\r
+\r
+ Index += AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);\r
+\r
+ if (ResourcePtr.SmallHeader->Bits.Type == 0) {\r
+ ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader\r
+ + ResourcePtr.SmallHeader->Bits.Length\r
+ + sizeof (*ResourcePtr.SmallHeader));\r
+ } else {\r
+ ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader\r
+ + ResourcePtr.LargeHeader->Length\r
+ + sizeof (*ResourcePtr.LargeHeader));\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Convert the ACPI End Tag\r
+ //\r
+ AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);\r
+}\r
+\r
+/**\r
+ Performs an ISA I/O Read Cycle\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Width Specifies the width of the I/O operation.\r
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation. \r
+ @param[in] Count The number of I/O operations to perform. \r
+ @param[out] Buffer The destination buffer to store the results\r
+\r
+ @retval EFI_SUCCESS The data was read from the device sucessfully.\r
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\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
+ OUT VOID *Buffer\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
+ 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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Performs an ISA I/O Write Cycle\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Width Specifies the width of the I/O operation.\r
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation. \r
+ @param[in] Count The number of I/O operations to perform. \r
+ @param[in] Buffer The source buffer to write data from\r
+\r
+ @retval EFI_SUCCESS The data was writen to the device sucessfully.\r
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\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 VOID *Buffer\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
+ 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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Writes an 8-bit I/O Port\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Offset The offset in ISA IO space to start the IO operation. \r
+ @param[in] Value The data to write port.\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.\r
+ @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+**/\r
+EFI_STATUS\r
+WritePort (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Wait for 50 microseconds to take affect.\r
+ //\r
+ gBS->Stall (50);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Writes I/O operation base address and count number to a 8 bit I/O Port.\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] AddrOffset The address' offset.\r
+ @param[in] PageOffset The page's offest.\r
+ @param[in] CountOffset The count's offset.\r
+ @param[in] BaseAddress The base address.\r
+ @param[in] Count The number of I/O operations to perform. \r
+ \r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.\r
+ @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\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
+ 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
+ return Status;\r
+}\r
+\r
+/**\r
+ Unmaps a memory region for DMA\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoUnmap (\r
+ IN EFI_ISA_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ ISA_MAP_INFO *IsaMapInfo;\r
+\r
+ //\r
+ // Check if DMA is supported.\r
+ //\r
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {\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
+ FreePool (IsaMapInfo);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Flushes any posted write data to the system memory.\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS The buffers were flushed.\r
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IsaIoFlush (\r
+ IN EFI_ISA_IO_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
+\r
+ Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Performs an ISA Memory Read Cycle\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Width Specifies the width of the memory operation.\r
+ @param[in] Offset The offset in ISA memory space to start the memory operation. \r
+ @param[in] Count The number of memory operations to perform. \r
+ @param[out] Buffer The destination buffer to store the results\r
+ \r
+ @retval EFI_SUCCESS The data was read from the device successfully.\r
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\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
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ //\r
+ // Check if ISA memory is supported.\r
+ //\r
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\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
+ 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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Performs an ISA Memory Write Cycle\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. \r
+ @param[in] Width Specifies the width of the memory operation.\r
+ @param[in] Offset The offset in ISA memory space to start the memory operation. \r
+ @param[in] Count The number of memory operations to perform. \r
+ @param[in] Buffer The source buffer to write data from\r
+\r
+ @retval EFI_SUCCESS The data was written to the device sucessfully.\r
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\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 VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ //\r
+ // Check if ISA memory is supported.\r
+ //\r
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\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
+ 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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Width Specifies the width of the memory copy operation.\r
+ @param[in] DestOffset The offset of the destination \r
+ @param[in] SrcOffset The offset of the source\r
+ @param[in] Count The number of memory copy operations to perform\r
+\r
+ @retval EFI_SUCCESS The data was copied sucessfully.\r
+ @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.\r
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\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
+ EFI_STATUS Status;\r
+ ISA_IO_DEVICE *IsaIoDevice;\r
+\r
+ //\r
+ // Check if ISA memory is supported.\r
+ //\r
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\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
+ 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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Maps a memory region for DMA, note this implementation\r
+ only supports slave read/write operation to save code size.\r
+\r
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param 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
+ @param 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
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
+ @param HostAddress The system memory address to map to the device. \r
+ @param NumberOfBytes On input the number of bytes to map. On output the number \r
+ of bytes that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master device to use \r
+ to access the hosts HostAddress. \r
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.\r
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+**/\r
+EFI_STATUS\r
+IsaIoMapOnlySupportSlaveReadWrite (\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
+ 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
+ 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
+ // 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) > BASE_16MB) {\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 = BASE_16MB - 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
+ 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
+ mDmaRegisters[ChannelNumber].Address,\r
+ mDmaRegisters[ChannelNumber].Page,\r
+ mDmaRegisters[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
+/**\r
+ Maps a memory region for DMA. This implementation implement the \r
+ the full mapping support.\r
+\r
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param 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
+ @param 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
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
+ @param HostAddress The system memory address to map to the device. \r
+ @param NumberOfBytes On input the number of bytes to map. On output the number \r
+ of bytes that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master device to use \r
+ to access the hosts HostAddress. \r
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
+\r
+ @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.\r
+ @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.\r
+ @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.\r
+ @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.\r
+ @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.\r
+**/\r
+EFI_STATUS\r
+IsaIoMapFullSupport (\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
+ 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
+ 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
+ // 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
+ if (ChannelNumber >= 8) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\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) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((ChannelAttributes &\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)) != 0) {\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) == 0) ||\r
+ ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)\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) != 0) ||\r
+ ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {\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) != 0) {\r
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {\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) > BASE_16MB) {\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 = BASE_16MB - 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
+ 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) != 0) {\r
+ DmaMode |= B_8237_DMA_CHMODE_AE;\r
+ }\r
+\r
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {\r
+ DmaMode |= V_8237_DMA_CHMODE_DEMAND;\r
+ }\r
+\r
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {\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
+ mDmaRegisters[ChannelNumber].Address,\r
+ mDmaRegisters[ChannelNumber].Page,\r
+ mDmaRegisters[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
+/**\r
+ Maps a memory region for DMA\r
+\r
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param 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
+ @param 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
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
+ @param HostAddress The system memory address to map to the device. \r
+ @param NumberOfBytes On input the number of bytes to map. On output the number \r
+ of bytes that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master device to use \r
+ to access the hosts HostAddress. \r
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.\r
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\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
+ // Check if DMA is supported.\r
+ //\r
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {\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 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {\r
+ return IsaIoMapOnlySupportSlaveReadWrite (\r
+ This,\r
+ Operation,\r
+ ChannelNumber,\r
+ ChannelAttributes,\r
+ HostAddress,\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+\r
+ } else {\r
+ return IsaIoMapFullSupport (\r
+ This,\r
+ Operation,\r
+ ChannelNumber,\r
+ ChannelAttributes,\r
+ HostAddress,\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.\r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Type The type allocation to perform.\r
+ @param[in] MemoryType The type of memory to allocate.\r
+ @param[in] Pages The number of pages to allocate.\r
+ @param[out] HostAddress A pointer to store the base address of the allocated range.\r
+ @param[in] Attributes The requested bit mask of attributes for the allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified \r
+ by HostAddress, Pages, and Type is not available for common buffer use.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\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
+ 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 (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||\r
+ ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {\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)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (BASE_16MB - 1);\r
+ if (Type == AllocateAddress) {\r
+ if ((UINTN) (*HostAddress) >= BASE_16MB) {\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
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer(). \r
+\r
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
+ @param[in] Pages The number of pages to free.\r
+ @param[in] HostAddress The base address of the allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().\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
+ EFI_STATUS Status;\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 (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||\r
+ ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = gBS->FreePages (\r
+ (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,\r
+ Pages\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r