Home | History | Annotate | Download | only in IsaIoDxe
      1 /** @file
      2   The implementation for EFI_ISA_IO_PROTOCOL.
      3 
      4 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "IsaIo.h"
     16 
     17 //
     18 // Module Variables
     19 //
     20 EFI_ISA_IO_PROTOCOL mIsaIoInterface = {
     21   {
     22     IsaIoMemRead,
     23     IsaIoMemWrite
     24   },
     25   {
     26     IsaIoIoRead,
     27     IsaIoIoWrite
     28   },
     29   IsaIoCopyMem,
     30   IsaIoMap,
     31   IsaIoUnmap,
     32   IsaIoAllocateBuffer,
     33   IsaIoFreeBuffer,
     34   IsaIoFlush,
     35   NULL,
     36   0,
     37   NULL
     38 };
     39 
     40 EFI_ISA_DMA_REGISTERS  mDmaRegisters[8] = {
     41   {
     42     0x00,
     43     0x87,
     44     0x01
     45   },
     46   {
     47     0x02,
     48     0x83,
     49     0x03
     50   },
     51   {
     52     0x04,
     53     0x81,
     54     0x05
     55   },
     56   {
     57     0x06,
     58     0x82,
     59     0x07
     60   },
     61   {
     62     0x00,
     63     0x00,
     64     0x00
     65   },  // Channel 4 is invalid
     66   {
     67     0xC4,
     68     0x8B,
     69     0xC6
     70   },
     71   {
     72     0xC8,
     73     0x89,
     74     0xCA
     75   },
     76   {
     77     0xCC,
     78     0x8A,
     79     0xCE
     80   },
     81 };
     82 
     83 /**
     84   Verifies access to an ISA device
     85 
     86   @param[in] IsaIoDevice         The ISA device to be verified.
     87   @param[in] Type                The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
     88   @param[in] Width               The width of the memory operation.
     89   @param[in] Count               The number of memory operations to perform.
     90   @param[in] Offset              The offset in ISA memory space to start the memory operation.
     91 
     92   @retval EFI_SUCCESS            Verify success.
     93   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
     94   @retval EFI_UNSUPPORTED        The device ont support the access type.
     95 **/
     96 EFI_STATUS
     97 IsaIoVerifyAccess (
     98   IN ISA_IO_DEVICE              *IsaIoDevice,
     99   IN ISA_ACCESS_TYPE            Type,
    100   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    101   IN UINTN                      Count,
    102   IN UINT32                     Offset
    103   )
    104 {
    105   EFI_ISA_ACPI_RESOURCE *Item;
    106   EFI_STATUS            Status;
    107 
    108   if ((UINT32)Width >= EfiIsaIoWidthMaximum ||
    109       Width == EfiIsaIoWidthReserved ||
    110       Width == EfiIsaIoWidthFifoReserved ||
    111       Width == EfiIsaIoWidthFillReserved
    112       ) {
    113     return EFI_INVALID_PARAMETER;
    114   }
    115 
    116   //
    117   // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
    118   // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
    119   //
    120   if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {
    121     Count = 1;
    122   }
    123 
    124   Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);
    125 
    126   Status  = EFI_UNSUPPORTED;
    127   Item    = IsaIoDevice->IsaIo.ResourceList->ResourceItem;
    128   while (Item->Type != EfiIsaAcpiResourceEndOfList) {
    129     if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||
    130         (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {
    131       if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {
    132         return EFI_SUCCESS;
    133       }
    134 
    135       if (Offset >= Item->StartRange && Offset <= Item->EndRange) {
    136         Status = EFI_INVALID_PARAMETER;
    137       }
    138     }
    139 
    140     Item++;
    141   }
    142 
    143   return Status;
    144 }
    145 
    146 /**
    147   Convert the IO Information in ACPI descriptor to IO ISA Attribute.
    148 
    149   @param[in] Information   The IO Information in ACPI descriptor
    150 
    151   @return UINT32           The IO ISA Attribute
    152 **/
    153 UINT32
    154 IsaIoAttribute (
    155   IN UINT8                            Information
    156   )
    157 {
    158   UINT32             Attribute;
    159 
    160   Attribute = 0;
    161 
    162   switch (Information & EFI_ACPI_IO_DECODE_MASK) {
    163     case EFI_ACPI_IO_DECODE_16_BIT:
    164       Attribute |= EFI_ISA_ACPI_IO_DECODE_16_BITS;
    165       break;
    166 
    167     case EFI_ACPI_IO_DECODE_10_BIT:
    168       Attribute |= EFI_ISA_ACPI_IO_DECODE_10_BITS;
    169       break;
    170   }
    171 
    172   return Attribute;
    173 }
    174 
    175 /**
    176   Convert the IRQ Information in ACPI descriptor to IRQ ISA Attribute.
    177 
    178   @param[in] Information   The IRQ Information in ACPI descriptor
    179 
    180   @return UINT32           The IRQ ISA Attribute
    181 **/
    182 UINT32
    183 IsaIrqAttribute (
    184   IN UINT8                            Information
    185   )
    186 {
    187   UINT32             Attribute;
    188 
    189   Attribute = 0;
    190 
    191   if ((Information & EFI_ACPI_IRQ_POLARITY_MASK) == EFI_ACPI_IRQ_HIGH_TRUE) {
    192     if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
    193       Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE;
    194     } else {
    195       Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
    196     }
    197   } else {
    198     if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
    199       Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE;
    200     } else {
    201       Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE;
    202     }
    203   }
    204   return Attribute;
    205 }
    206 
    207 /**
    208   Convert the Memory Information in ACPI descriptor to Memory ISA Attribute.
    209 
    210   @param[in] Information   The Memory Information in ACPI descriptor
    211 
    212   @return UINT32           The Memory ISA Attribute
    213 **/
    214 UINT32
    215 IsaMemoryAttribute (
    216   IN UINT8                            Information
    217   )
    218 {
    219   UINT32             Attribute;
    220 
    221   Attribute = 0;
    222 
    223   switch (Information & EFI_ACPI_MEMORY_WRITE_STATUS_MASK) {
    224     case EFI_ACPI_MEMORY_WRITABLE:
    225       Attribute |= EFI_ISA_ACPI_MEMORY_WRITEABLE;
    226       break;
    227   }
    228 
    229   return Attribute;
    230 }
    231 
    232 /**
    233   Convert the DMA Information in ACPI descriptor to DMA ISA Attribute.
    234 
    235   @param[in] Information   The DMA Information in ACPI descriptor
    236 
    237   @return UINT32           The DMA ISA Attribute
    238 **/
    239 UINT32
    240 IsaDmaAttribute (
    241   IN UINT8                            Information
    242   )
    243 {
    244   UINT32             Attribute;
    245 
    246   Attribute = EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE;
    247 
    248   switch (Information & EFI_ACPI_DMA_SPEED_TYPE_MASK) {
    249     case EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY:
    250       Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE;
    251       break;
    252     case EFI_ACPI_DMA_SPEED_TYPE_A:
    253       Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A;
    254       break;
    255     case EFI_ACPI_DMA_SPEED_TYPE_B:
    256       Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B;
    257       break;
    258     case EFI_ACPI_DMA_SPEED_TYPE_F:
    259       Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C;
    260       break;
    261   }
    262 
    263   switch (Information & EFI_ACPI_DMA_TRANSFER_TYPE_MASK) {
    264     case EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT:
    265       Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8;
    266       break;
    267     case EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT:
    268       Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16;
    269       break;
    270   }
    271 
    272   return Attribute;
    273 }
    274 
    275 /**
    276   Convert the ACPI resource descriptor to ISA resource descriptor.
    277 
    278   @param[in]  AcpiResource          Pointer to the ACPI resource descriptor
    279   @param[out] IsaResource           The optional pointer to the buffer to
    280                                     store the converted ISA resource descriptor
    281 
    282   @return     UINTN                 Number of ISA resource descriptor needed
    283 **/
    284 UINTN
    285 AcpiResourceToIsaResource (
    286   IN  ACPI_RESOURCE_HEADER_PTR        AcpiResource,
    287   OUT EFI_ISA_ACPI_RESOURCE           *IsaResource   OPTIONAL
    288   )
    289 {
    290   UINT32                                        Index;
    291   UINTN                                         Count;
    292   UINT32                                        LastIndex;
    293   EFI_ACPI_IO_PORT_DESCRIPTOR                   *Io;
    294   EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR    *FixedIo;
    295   EFI_ACPI_IRQ_DESCRIPTOR                       *Irq;
    296   EFI_ACPI_DMA_DESCRIPTOR                       *Dma;
    297   EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR       *Memory;
    298   EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *FixedMemory;
    299 
    300   Count     = 0;
    301   LastIndex = 0;
    302 
    303   switch (AcpiResource.SmallHeader->Byte) {
    304     case ACPI_DMA_DESCRIPTOR:
    305       Dma = (EFI_ACPI_DMA_DESCRIPTOR *) AcpiResource.SmallHeader;
    306       for (Index = 0; Index < sizeof (Dma->ChannelMask) * 8; Index++) {
    307         if (Dma->ChannelMask & (1 << Index)) {
    308           if ((Count > 0) && (LastIndex + 1 == Index)) {
    309             if (IsaResource != NULL) {
    310               IsaResource[Count - 1].EndRange ++;
    311             }
    312           } else {
    313             if (IsaResource != NULL) {
    314               IsaResource[Count].Type       = EfiIsaAcpiResourceDma;
    315               IsaResource[Count].Attribute  = IsaDmaAttribute (Dma->Information);
    316               IsaResource[Count].StartRange = Index;
    317               IsaResource[Count].EndRange   = Index;
    318             }
    319             Count ++;
    320           }
    321 
    322           LastIndex = Index;
    323         }
    324       }
    325       break;
    326 
    327     case ACPI_IO_PORT_DESCRIPTOR:
    328       Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
    329       if (Io->Length != 0) {
    330         if (IsaResource != NULL) {
    331           IsaResource[Count].Type       = EfiIsaAcpiResourceIo;
    332           IsaResource[Count].Attribute  = IsaIoAttribute (Io->Information);
    333           IsaResource[Count].StartRange = Io->BaseAddressMin;
    334           IsaResource[Count].EndRange   = Io->BaseAddressMin + Io->Length - 1;
    335         }
    336         Count ++;
    337       }
    338       break;
    339 
    340     case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
    341       FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
    342       if (FixedIo->Length != 0) {
    343         if (IsaResource != NULL) {
    344           IsaResource[Count].Type       = EfiIsaAcpiResourceIo;
    345           IsaResource[Count].Attribute  = EFI_ISA_ACPI_IO_DECODE_10_BITS;
    346           IsaResource[Count].StartRange = FixedIo->BaseAddress;
    347           IsaResource[Count].EndRange   = FixedIo->BaseAddress + FixedIo->Length - 1;
    348         }
    349         Count ++;
    350       }
    351       break;
    352 
    353     case ACPI_IRQ_DESCRIPTOR:
    354     case ACPI_IRQ_NOFLAG_DESCRIPTOR:
    355       Irq = (EFI_ACPI_IRQ_DESCRIPTOR *) AcpiResource.SmallHeader;
    356       for (Index = 0; Index < sizeof (Irq->Mask) * 8; Index++) {
    357         if (Irq->Mask & (1 << Index)) {
    358           if ((Count > 0) && (LastIndex + 1 == Index)) {
    359             if (IsaResource != NULL) {
    360               IsaResource[Count - 1].EndRange ++;
    361             }
    362           } else {
    363             if (IsaResource != NULL) {
    364               IsaResource[Count].Type       = EfiIsaAcpiResourceInterrupt;
    365               if (AcpiResource.SmallHeader->Byte == ACPI_IRQ_DESCRIPTOR) {
    366                 IsaResource[Count].Attribute = IsaIrqAttribute (Irq->Information);
    367               } else {
    368                 IsaResource[Count].Attribute  = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
    369               }
    370               IsaResource[Count].StartRange = Index;
    371               IsaResource[Count].EndRange   = Index;
    372             }
    373             Count++;
    374           }
    375 
    376           LastIndex = Index;
    377         }
    378       }
    379       break;
    380 
    381     case ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR:
    382       Memory = (EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
    383       if (Memory->Length != 0) {
    384         if (IsaResource != NULL) {
    385           IsaResource[Count].Type       = EfiIsaAcpiResourceMemory;
    386           IsaResource[Count].Attribute  = IsaMemoryAttribute (Memory->Information);
    387           IsaResource[Count].StartRange = Memory->BaseAddressMin;
    388           IsaResource[Count].EndRange   = Memory->BaseAddressMin + Memory->Length - 1;
    389         }
    390         Count ++;
    391       }
    392       break;
    393 
    394     case ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR:
    395       FixedMemory = (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
    396       if (FixedMemory->Length != 0) {
    397         if (IsaResource != NULL) {
    398           IsaResource[Count].Type       = EfiIsaAcpiResourceMemory;
    399           IsaResource[Count].Attribute  = IsaMemoryAttribute (FixedMemory->Information);
    400           IsaResource[Count].StartRange = FixedMemory->BaseAddress;
    401           IsaResource[Count].EndRange   = FixedMemory->BaseAddress + FixedMemory->Length - 1;
    402         }
    403         Count ++;
    404       }
    405       break;
    406 
    407     case ACPI_END_TAG_DESCRIPTOR:
    408       if (IsaResource != NULL) {
    409         IsaResource[Count].Type       = EfiIsaAcpiResourceEndOfList;
    410         IsaResource[Count].Attribute  = 0;
    411         IsaResource[Count].StartRange = 0;
    412         IsaResource[Count].EndRange   = 0;
    413       }
    414       Count ++;
    415       break;
    416   }
    417 
    418   return Count;
    419 }
    420 
    421 /**
    422   Initializes an ISA I/O Instance
    423 
    424   @param[in] IsaIoDevice            The isa device to be initialized.
    425   @param[in] DevicePath             The device path of the isa device.
    426   @param[in] Resources              The ACPI resource list.
    427 
    428 **/
    429 VOID
    430 InitializeIsaIoInstance (
    431   IN ISA_IO_DEVICE               *IsaIoDevice,
    432   IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
    433   IN ACPI_RESOURCE_HEADER_PTR    Resources
    434   )
    435 {
    436   UINTN                                       Index;
    437   ACPI_HID_DEVICE_PATH                        *AcpiNode;
    438   ACPI_RESOURCE_HEADER_PTR                    ResourcePtr;
    439 
    440   //
    441   // Use the ISA IO Protocol structure template to initialize the ISA IO instance
    442   //
    443   CopyMem (
    444     &IsaIoDevice->IsaIo,
    445     &mIsaIoInterface,
    446     sizeof (EFI_ISA_IO_PROTOCOL)
    447     );
    448 
    449   //
    450   // Count the resources including the ACPI End Tag
    451   //
    452   ResourcePtr = Resources;
    453   Index       = 0;
    454   while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
    455 
    456     Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
    457 
    458     if (ResourcePtr.SmallHeader->Bits.Type == 0) {
    459       ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
    460                               + ResourcePtr.SmallHeader->Bits.Length
    461                               + sizeof (*ResourcePtr.SmallHeader));
    462     } else {
    463       ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
    464                               + ResourcePtr.LargeHeader->Length
    465                               + sizeof (*ResourcePtr.LargeHeader));
    466     }
    467 
    468   }
    469   //
    470   // Get the Isa Resource count for ACPI End Tag
    471   //
    472   Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
    473 
    474   //
    475   // Initialize the ResourceList
    476   //
    477   IsaIoDevice->IsaIo.ResourceList = AllocatePool (sizeof (EFI_ISA_ACPI_RESOURCE_LIST) + Index * sizeof (EFI_ISA_ACPI_RESOURCE));
    478   ASSERT (IsaIoDevice->IsaIo.ResourceList != NULL);
    479   IsaIoDevice->IsaIo.ResourceList->ResourceItem = (EFI_ISA_ACPI_RESOURCE *) (IsaIoDevice->IsaIo.ResourceList + 1);
    480 
    481   AcpiNode = (ACPI_HID_DEVICE_PATH *) ((UINT8 *) DevicePath + GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH - sizeof (ACPI_HID_DEVICE_PATH));
    482   IsaIoDevice->IsaIo.ResourceList->Device.HID = AcpiNode->HID;
    483   IsaIoDevice->IsaIo.ResourceList->Device.UID = AcpiNode->UID;
    484 
    485   ResourcePtr = Resources;
    486   Index       = 0;
    487   while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
    488 
    489     Index += AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
    490 
    491     if (ResourcePtr.SmallHeader->Bits.Type == 0) {
    492       ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
    493                               + ResourcePtr.SmallHeader->Bits.Length
    494                               + sizeof (*ResourcePtr.SmallHeader));
    495     } else {
    496       ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
    497                               + ResourcePtr.LargeHeader->Length
    498                               + sizeof (*ResourcePtr.LargeHeader));
    499     }
    500   }
    501 
    502   //
    503   // Convert the ACPI End Tag
    504   //
    505   AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
    506 }
    507 
    508 /**
    509   Performs an ISA I/O Read Cycle
    510 
    511   @param[in]  This              A pointer to the EFI_ISA_IO_PROTOCOL instance.
    512   @param[in]  Width             Specifies the width of the I/O operation.
    513   @param[in]  Offset            The offset in ISA I/O space to start the I/O operation.
    514   @param[in]  Count             The number of I/O operations to perform.
    515   @param[out] Buffer            The destination buffer to store the results
    516 
    517   @retval EFI_SUCCESS           The data was read from the device sucessfully.
    518   @retval EFI_UNSUPPORTED       The Offset is not valid for this device.
    519   @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
    520   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    521 **/
    522 EFI_STATUS
    523 EFIAPI
    524 IsaIoIoRead (
    525   IN  EFI_ISA_IO_PROTOCOL        *This,
    526   IN  EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    527   IN  UINT32                     Offset,
    528   IN  UINTN                      Count,
    529   OUT VOID                       *Buffer
    530   )
    531 {
    532   EFI_STATUS    Status;
    533   ISA_IO_DEVICE *IsaIoDevice;
    534 
    535   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    536 
    537   //
    538   // Verify Isa IO Access
    539   //
    540   Status = IsaIoVerifyAccess (
    541              IsaIoDevice,
    542              IsaAccessTypeIo,
    543              Width,
    544              Count,
    545              Offset
    546              );
    547   if (EFI_ERROR (Status)) {
    548     return Status;
    549   }
    550 
    551   Status = IsaIoDevice->PciIo->Io.Read (
    552                                     IsaIoDevice->PciIo,
    553                                     (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    554                                     EFI_PCI_IO_PASS_THROUGH_BAR,
    555                                     Offset,
    556                                     Count,
    557                                     Buffer
    558                                     );
    559 
    560   if (EFI_ERROR (Status)) {
    561     REPORT_STATUS_CODE (
    562       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    563       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    564       );
    565   }
    566 
    567   return Status;
    568 }
    569 
    570 /**
    571   Performs an ISA I/O Write Cycle
    572 
    573   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    574   @param[in] Width               Specifies the width of the I/O operation.
    575   @param[in] Offset              The offset in ISA I/O space to start the I/O operation.
    576   @param[in] Count               The number of I/O operations to perform.
    577   @param[in] Buffer              The source buffer to write data from
    578 
    579   @retval EFI_SUCCESS            The data was writen to the device sucessfully.
    580   @retval EFI_UNSUPPORTED        The Offset is not valid for this device.
    581   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    582   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    583 **/
    584 EFI_STATUS
    585 EFIAPI
    586 IsaIoIoWrite (
    587   IN EFI_ISA_IO_PROTOCOL        *This,
    588   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    589   IN UINT32                     Offset,
    590   IN UINTN                      Count,
    591   IN VOID                       *Buffer
    592   )
    593 {
    594   EFI_STATUS    Status;
    595   ISA_IO_DEVICE *IsaIoDevice;
    596 
    597   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    598 
    599   //
    600   // Verify Isa IO Access
    601   //
    602   Status = IsaIoVerifyAccess (
    603              IsaIoDevice,
    604              IsaAccessTypeIo,
    605              Width,
    606              Count,
    607              Offset
    608              );
    609   if (EFI_ERROR (Status)) {
    610     return Status;
    611   }
    612 
    613   Status = IsaIoDevice->PciIo->Io.Write (
    614                                     IsaIoDevice->PciIo,
    615                                     (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    616                                     EFI_PCI_IO_PASS_THROUGH_BAR,
    617                                     Offset,
    618                                     Count,
    619                                     Buffer
    620                                     );
    621 
    622   if (EFI_ERROR (Status)) {
    623     REPORT_STATUS_CODE (
    624       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    625       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    626       );
    627   }
    628 
    629   return Status;
    630 }
    631 
    632 /**
    633   Writes an 8-bit I/O Port
    634 
    635   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    636   @param[in] Offset              The offset in ISA IO space to start the IO operation.
    637   @param[in] Value               The data to write port.
    638 
    639   @retval EFI_SUCCESS            Success.
    640   @retval EFI_INVALID_PARAMETER  Parameter is invalid.
    641   @retval EFI_UNSUPPORTED        The address range specified by Offset is not valid.
    642   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    643 **/
    644 EFI_STATUS
    645 WritePort (
    646   IN EFI_ISA_IO_PROTOCOL  *This,
    647   IN UINT32               Offset,
    648   IN UINT8                Value
    649   )
    650 {
    651   EFI_STATUS    Status;
    652   ISA_IO_DEVICE *IsaIoDevice;
    653 
    654   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    655 
    656   Status = IsaIoDevice->PciIo->Io.Write (
    657                                     IsaIoDevice->PciIo,
    658                                     EfiPciIoWidthUint8,
    659                                     EFI_PCI_IO_PASS_THROUGH_BAR,
    660                                     Offset,
    661                                     1,
    662                                     &Value
    663                                     );
    664   if (EFI_ERROR (Status)) {
    665     REPORT_STATUS_CODE (
    666       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    667       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    668       );
    669     return Status;
    670   }
    671 
    672   //
    673   // Wait for 50 microseconds to take affect.
    674   //
    675   gBS->Stall (50);
    676 
    677   return EFI_SUCCESS;
    678 }
    679 
    680 /**
    681   Writes I/O operation base address and count number to a 8 bit I/O Port.
    682 
    683   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    684   @param[in] AddrOffset          The address' offset.
    685   @param[in] PageOffset          The page's offest.
    686   @param[in] CountOffset         The count's offset.
    687   @param[in] BaseAddress         The base address.
    688   @param[in] Count               The number of I/O operations to perform.
    689 
    690   @retval EFI_SUCCESS            Success.
    691   @retval EFI_INVALID_PARAMETER  Parameter is invalid.
    692   @retval EFI_UNSUPPORTED        The address range specified by these Offsets and Count is not valid.
    693   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    694 **/
    695 EFI_STATUS
    696 WriteDmaPort (
    697   IN EFI_ISA_IO_PROTOCOL  *This,
    698   IN UINT32               AddrOffset,
    699   IN UINT32               PageOffset,
    700   IN UINT32               CountOffset,
    701   IN UINT32               BaseAddress,
    702   IN UINT16               Count
    703   )
    704 {
    705   EFI_STATUS  Status;
    706 
    707   Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));
    708   if (EFI_ERROR (Status)) {
    709     return Status;
    710   }
    711 
    712   Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));
    713   if (EFI_ERROR (Status)) {
    714     return Status;
    715   }
    716 
    717   Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));
    718   if (EFI_ERROR (Status)) {
    719     return Status;
    720   }
    721 
    722   Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));
    723   if (EFI_ERROR (Status)) {
    724     return Status;
    725   }
    726 
    727   Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));
    728   return Status;
    729 }
    730 
    731 /**
    732   Unmaps a memory region for DMA
    733 
    734   @param[in] This           A pointer to the EFI_ISA_IO_PROTOCOL instance.
    735   @param[in] Mapping        The mapping value returned from EFI_ISA_IO.Map().
    736 
    737   @retval EFI_SUCCESS       The range was unmapped.
    738   @retval EFI_DEVICE_ERROR  The data was not committed to the target system memory.
    739 **/
    740 EFI_STATUS
    741 EFIAPI
    742 IsaIoUnmap (
    743   IN EFI_ISA_IO_PROTOCOL  *This,
    744   IN VOID                 *Mapping
    745   )
    746 {
    747   ISA_MAP_INFO  *IsaMapInfo;
    748 
    749   //
    750   // Check if DMA is supported.
    751   //
    752   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
    753     return EFI_UNSUPPORTED;
    754   }
    755 
    756   //
    757   // See if the Map() operation associated with this Unmap() required a mapping
    758   // buffer.If a mapping buffer was not required, then this function simply
    759   // returns EFI_SUCCESS.
    760   //
    761   if (Mapping != NULL) {
    762     //
    763     // Get the MAP_INFO structure from Mapping
    764     //
    765     IsaMapInfo = (ISA_MAP_INFO *) Mapping;
    766 
    767     //
    768     // If this is a write operation from the Agent's point of view,
    769     // then copy the contents of the mapped buffer into the real buffer
    770     // so the processor can read the contents of the real buffer.
    771     //
    772     if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {
    773       CopyMem (
    774         (VOID *) (UINTN) IsaMapInfo->HostAddress,
    775         (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
    776         IsaMapInfo->NumberOfBytes
    777         );
    778     }
    779     //
    780     // Free the mapped buffer and the MAP_INFO structure.
    781     //
    782     gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);
    783     FreePool (IsaMapInfo);
    784   }
    785 
    786   return EFI_SUCCESS;
    787 }
    788 
    789 /**
    790   Flushes any posted write data to the system memory.
    791 
    792   @param[in] This             A pointer to the EFI_ISA_IO_PROTOCOL instance.
    793 
    794   @retval  EFI_SUCCESS        The buffers were flushed.
    795   @retval  EFI_DEVICE_ERROR   The buffers were not flushed due to a hardware error.
    796 **/
    797 EFI_STATUS
    798 EFIAPI
    799 IsaIoFlush (
    800   IN EFI_ISA_IO_PROTOCOL  *This
    801   )
    802 {
    803   EFI_STATUS    Status;
    804   ISA_IO_DEVICE *IsaIoDevice;
    805 
    806   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    807 
    808   Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);
    809 
    810   if (EFI_ERROR (Status)) {
    811     REPORT_STATUS_CODE (
    812       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    813       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    814       );
    815   }
    816 
    817   return Status;
    818 }
    819 
    820 /**
    821   Performs an ISA Memory Read Cycle
    822 
    823   @param[in]  This               A pointer to the EFI_ISA_IO_PROTOCOL instance.
    824   @param[in]  Width              Specifies the width of the memory operation.
    825   @param[in]  Offset             The offset in ISA memory space to start the memory operation.
    826   @param[in]  Count              The number of memory operations to perform.
    827   @param[out] Buffer             The destination buffer to store the results
    828 
    829   @retval EFI_SUCCESS            The data was read from the device successfully.
    830   @retval EFI_UNSUPPORTED        The Offset is not valid for this device.
    831   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    832   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    833 **/
    834 EFI_STATUS
    835 EFIAPI
    836 IsaIoMemRead (
    837   IN  EFI_ISA_IO_PROTOCOL        *This,
    838   IN  EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    839   IN  UINT32                     Offset,
    840   IN  UINTN                      Count,
    841   OUT VOID                       *Buffer
    842   )
    843 {
    844   EFI_STATUS    Status;
    845   ISA_IO_DEVICE *IsaIoDevice;
    846 
    847   //
    848   // Check if ISA memory is supported.
    849   //
    850   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
    851     return EFI_UNSUPPORTED;
    852   }
    853 
    854   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    855 
    856   //
    857   // Verify the Isa Io Access
    858   //
    859   Status = IsaIoVerifyAccess (
    860              IsaIoDevice,
    861              IsaAccessTypeMem,
    862              Width,
    863              Count,
    864              Offset
    865              );
    866   if (EFI_ERROR (Status)) {
    867     return Status;
    868   }
    869 
    870   Status = IsaIoDevice->PciIo->Mem.Read (
    871                                      IsaIoDevice->PciIo,
    872                                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    873                                      EFI_PCI_IO_PASS_THROUGH_BAR,
    874                                      Offset,
    875                                      Count,
    876                                      Buffer
    877                                      );
    878 
    879   if (EFI_ERROR (Status)) {
    880     REPORT_STATUS_CODE (
    881       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    882       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    883       );
    884   }
    885 
    886   return Status;
    887 }
    888 
    889 /**
    890   Performs an ISA Memory Write Cycle
    891 
    892   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    893   @param[in] Width               Specifies the width of the memory operation.
    894   @param[in] Offset              The offset in ISA memory space to start the memory operation.
    895   @param[in] Count               The number of memory operations to perform.
    896   @param[in] Buffer              The source buffer to write data from
    897 
    898   @retval EFI_SUCCESS            The data was written to the device sucessfully.
    899   @retval EFI_UNSUPPORTED        The Offset is not valid for this device.
    900   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    901   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    902 **/
    903 EFI_STATUS
    904 EFIAPI
    905 IsaIoMemWrite (
    906   IN EFI_ISA_IO_PROTOCOL        *This,
    907   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    908   IN UINT32                     Offset,
    909   IN UINTN                      Count,
    910   IN VOID                       *Buffer
    911   )
    912 {
    913   EFI_STATUS    Status;
    914   ISA_IO_DEVICE *IsaIoDevice;
    915 
    916   //
    917   // Check if ISA memory is supported.
    918   //
    919   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
    920     return EFI_UNSUPPORTED;
    921   }
    922 
    923   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    924 
    925   //
    926   // Verify Isa IO Access
    927   //
    928   Status = IsaIoVerifyAccess (
    929              IsaIoDevice,
    930              IsaAccessTypeMem,
    931              Width,
    932              Count,
    933              Offset
    934              );
    935   if (EFI_ERROR (Status)) {
    936     return Status;
    937   }
    938 
    939   Status = IsaIoDevice->PciIo->Mem.Write (
    940                                      IsaIoDevice->PciIo,
    941                                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    942                                      EFI_PCI_IO_PASS_THROUGH_BAR,
    943                                      Offset,
    944                                      Count,
    945                                      Buffer
    946                                      );
    947 
    948   if (EFI_ERROR (Status)) {
    949     REPORT_STATUS_CODE (
    950       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    951       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    952       );
    953   }
    954 
    955   return Status;
    956 }
    957 
    958 /**
    959   Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
    960 
    961   @param[in]  This               A pointer to the EFI_ISA_IO_PROTOCOL instance.
    962   @param[in]  Width              Specifies the width of the memory copy operation.
    963   @param[in]  DestOffset         The offset of the destination
    964   @param[in]  SrcOffset          The offset of the source
    965   @param[in]  Count              The number of memory copy  operations to perform
    966 
    967   @retval EFI_SUCCESS            The data was copied sucessfully.
    968   @retval EFI_UNSUPPORTED        The DestOffset or SrcOffset is not valid for this device.
    969   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    970   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    971 **/
    972 EFI_STATUS
    973 EFIAPI
    974 IsaIoCopyMem (
    975   IN EFI_ISA_IO_PROTOCOL        *This,
    976   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    977   IN UINT32                     DestOffset,
    978   IN UINT32                     SrcOffset,
    979   IN UINTN                      Count
    980   )
    981 {
    982   EFI_STATUS    Status;
    983   ISA_IO_DEVICE *IsaIoDevice;
    984 
    985   //
    986   // Check if ISA memory is supported.
    987   //
    988   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
    989     return EFI_UNSUPPORTED;
    990   }
    991 
    992   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    993 
    994   //
    995   // Verify Isa IO Access for destination and source
    996   //
    997   Status = IsaIoVerifyAccess (
    998              IsaIoDevice,
    999              IsaAccessTypeMem,
   1000              Width,
   1001              Count,
   1002              DestOffset
   1003              );
   1004   if (EFI_ERROR (Status)) {
   1005     return Status;
   1006   }
   1007 
   1008   Status = IsaIoVerifyAccess (
   1009              IsaIoDevice,
   1010              IsaAccessTypeMem,
   1011              Width,
   1012              Count,
   1013              SrcOffset
   1014              );
   1015   if (EFI_ERROR (Status)) {
   1016     return Status;
   1017   }
   1018 
   1019   Status = IsaIoDevice->PciIo->CopyMem (
   1020                                  IsaIoDevice->PciIo,
   1021                                  (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
   1022                                  EFI_PCI_IO_PASS_THROUGH_BAR,
   1023                                  DestOffset,
   1024                                  EFI_PCI_IO_PASS_THROUGH_BAR,
   1025                                  SrcOffset,
   1026                                  Count
   1027                                  );
   1028 
   1029   if (EFI_ERROR (Status)) {
   1030     REPORT_STATUS_CODE (
   1031       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1032       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
   1033       );
   1034   }
   1035 
   1036   return Status;
   1037 }
   1038 
   1039 /**
   1040   Maps a memory region for DMA, note this implementation
   1041   only supports slave read/write operation to save code size.
   1042 
   1043   @param This                    A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1044   @param Operation               Indicates the type of DMA (slave or bus master), and if
   1045                                  the DMA operation is going to read or write to system memory.
   1046   @param ChannelNumber           The slave channel number to use for this DMA operation.
   1047                                  If Operation and ChannelAttributes shows that this device
   1048                                  performs bus mastering DMA, then this field is ignored.
   1049                                  The legal range for this field is 0..7.
   1050   @param ChannelAttributes       The attributes of the DMA channel to use for this DMA operation
   1051   @param HostAddress             The system memory address to map to the device.
   1052   @param NumberOfBytes           On input the number of bytes to map.  On output the number
   1053                                  of bytes that were mapped.
   1054   @param DeviceAddress           The resulting map address for the bus master device to use
   1055                                  to access the hosts HostAddress.
   1056   @param Mapping                 A resulting value to pass to EFI_ISA_IO.Unmap().
   1057 
   1058   @retval EFI_SUCCESS            The range was mapped for the returned NumberOfBytes.
   1059   @retval EFI_INVALID_PARAMETER  The Operation or HostAddress is undefined.
   1060   @retval EFI_UNSUPPORTED        The HostAddress can not be mapped as a common buffer.
   1061   @retval EFI_DEVICE_ERROR       The system hardware could not map the requested address.
   1062   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
   1063 **/
   1064 EFI_STATUS
   1065 IsaIoMapOnlySupportSlaveReadWrite (
   1066   IN     EFI_ISA_IO_PROTOCOL            *This,
   1067   IN     EFI_ISA_IO_PROTOCOL_OPERATION  Operation,
   1068   IN     UINT8                          ChannelNumber  OPTIONAL,
   1069   IN     UINT32                         ChannelAttributes,
   1070   IN     VOID                           *HostAddress,
   1071   IN OUT UINTN                          *NumberOfBytes,
   1072   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
   1073   OUT    VOID                           **Mapping
   1074   )
   1075 {
   1076   EFI_STATUS            Status;
   1077   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
   1078   ISA_MAP_INFO          *IsaMapInfo;
   1079   UINT8                 DmaMode;
   1080   UINTN                 MaxNumberOfBytes;
   1081   UINT32                BaseAddress;
   1082   UINT16                Count;
   1083   UINT8                 DmaMask;
   1084   UINT8                 DmaClear;
   1085   UINT8                 DmaChannelMode;
   1086 
   1087   if ((NULL == This) ||
   1088       (NULL == HostAddress) ||
   1089       (NULL == NumberOfBytes) ||
   1090       (NULL == DeviceAddress) ||
   1091       (NULL == Mapping)
   1092       ) {
   1093     return EFI_INVALID_PARAMETER;
   1094   }
   1095 
   1096   //
   1097   // Initialize the return values to their defaults
   1098   //
   1099   *Mapping = NULL;
   1100 
   1101   //
   1102   // Make sure the Operation parameter is valid.
   1103   // Light IsaIo only supports two operations.
   1104   //
   1105   if (!(Operation == EfiIsaIoOperationSlaveRead ||
   1106         Operation == EfiIsaIoOperationSlaveWrite)) {
   1107     return EFI_INVALID_PARAMETER;
   1108   }
   1109 
   1110   if (ChannelNumber >= 4) {
   1111     //
   1112     // The Light IsaIo doesn't support channelNumber larger than 4.
   1113     //
   1114     return EFI_INVALID_PARAMETER;
   1115   }
   1116 
   1117   //
   1118   // Map the HostAddress to a DeviceAddress.
   1119   //
   1120   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
   1121   if ((PhysicalAddress + *NumberOfBytes) > BASE_16MB) {
   1122     //
   1123     // Common Buffer operations can not be remapped.  If the common buffer
   1124     // is above 16MB, then it is not possible to generate a mapping, so return
   1125     // an error.
   1126     //
   1127     if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
   1128       return EFI_UNSUPPORTED;
   1129     }
   1130     //
   1131     // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
   1132     // is called later.
   1133     //
   1134     IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
   1135     if (IsaMapInfo == NULL) {
   1136       *NumberOfBytes = 0;
   1137       return EFI_OUT_OF_RESOURCES;
   1138     }
   1139     //
   1140     // Return a pointer to the MAP_INFO structure in Mapping
   1141     //
   1142     *Mapping = IsaMapInfo;
   1143 
   1144     //
   1145     // Initialize the MAP_INFO structure
   1146     //
   1147     IsaMapInfo->Operation         = Operation;
   1148     IsaMapInfo->NumberOfBytes     = *NumberOfBytes;
   1149     IsaMapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (*NumberOfBytes);
   1150     IsaMapInfo->HostAddress       = PhysicalAddress;
   1151     IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
   1152 
   1153     //
   1154     // Allocate a buffer below 16MB to map the transfer to.
   1155     //
   1156     Status = gBS->AllocatePages (
   1157                     AllocateMaxAddress,
   1158                     EfiBootServicesData,
   1159                     IsaMapInfo->NumberOfPages,
   1160                     &IsaMapInfo->MappedHostAddress
   1161                     );
   1162     if (EFI_ERROR (Status)) {
   1163       FreePool (IsaMapInfo);
   1164       *NumberOfBytes  = 0;
   1165       *Mapping        = NULL;
   1166       return Status;
   1167     }
   1168     //
   1169     // If this is a read operation from the DMA agents's point of view,
   1170     // then copy the contents of the real buffer into the mapped buffer
   1171     // so the DMA agent can read the contents of the real buffer.
   1172     //
   1173     if (Operation == EfiIsaIoOperationSlaveRead) {
   1174       CopyMem (
   1175         (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
   1176         (VOID *) (UINTN) IsaMapInfo->HostAddress,
   1177         IsaMapInfo->NumberOfBytes
   1178         );
   1179     }
   1180     //
   1181     // The DeviceAddress is the address of the maped buffer below 16 MB
   1182     //
   1183     *DeviceAddress = IsaMapInfo->MappedHostAddress;
   1184   } else {
   1185     //
   1186     // The transfer is below 16 MB, so the DeviceAddress is simply the
   1187     // HostAddress
   1188     //
   1189     *DeviceAddress = PhysicalAddress;
   1190   }
   1191 
   1192   //
   1193   // Figure out what to program into the DMA Channel Mode Register
   1194   //
   1195   DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
   1196   if (Operation == EfiIsaIoOperationSlaveRead) {
   1197     DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
   1198   } else {
   1199     DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
   1200   }
   1201   //
   1202   // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
   1203   //
   1204   DmaMode |= V_8237_DMA_CHMODE_SINGLE;
   1205 
   1206   //
   1207   // A Slave DMA transfer can not cross a 64K boundary.
   1208   // Compute *NumberOfBytes based on this restriction.
   1209   //
   1210   MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
   1211   if (*NumberOfBytes > MaxNumberOfBytes) {
   1212     *NumberOfBytes = MaxNumberOfBytes;
   1213   }
   1214   //
   1215   // Compute the values to program into the BaseAddress and Count registers
   1216   // of the Slave DMA controller
   1217   //
   1218   BaseAddress = (UINT32) (*DeviceAddress);
   1219   Count       = (UINT16) (*NumberOfBytes - 1);
   1220   //
   1221   // Program the DMA Write Single Mask Register for ChannelNumber
   1222   // Clear the DMA Byte Pointer Register
   1223   //
   1224   DmaMask         = R_8237_DMA_WRSMSK_CH0_3;
   1225   DmaClear        = R_8237_DMA_CBPR_CH0_3;
   1226   DmaChannelMode  = R_8237_DMA_CHMODE_CH0_3;
   1227 
   1228   Status = WritePort (
   1229              This,
   1230              DmaMask,
   1231              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
   1232              );
   1233   if (EFI_ERROR (Status)) {
   1234     return Status;
   1235   }
   1236 
   1237   Status = WritePort (
   1238              This,
   1239              DmaClear,
   1240              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
   1241              );
   1242   if (EFI_ERROR (Status)) {
   1243     return Status;
   1244   }
   1245 
   1246   Status = WritePort (This, DmaChannelMode, DmaMode);
   1247   if (EFI_ERROR (Status)) {
   1248     return Status;
   1249   }
   1250 
   1251   Status = WriteDmaPort (
   1252              This,
   1253              mDmaRegisters[ChannelNumber].Address,
   1254              mDmaRegisters[ChannelNumber].Page,
   1255              mDmaRegisters[ChannelNumber].Count,
   1256              BaseAddress,
   1257              Count
   1258              );
   1259   if (EFI_ERROR (Status)) {
   1260     return Status;
   1261   }
   1262 
   1263   Status = WritePort (
   1264              This,
   1265              DmaMask,
   1266              (UINT8) (ChannelNumber & 0x03)
   1267              );
   1268   if (EFI_ERROR (Status)) {
   1269     return Status;
   1270   }
   1271 
   1272   return EFI_SUCCESS;
   1273 }
   1274 
   1275 /**
   1276   Maps a memory region for DMA. This implementation implement the
   1277   the full mapping support.
   1278 
   1279   @param This                    A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1280   @param Operation               Indicates the type of DMA (slave or bus master), and if
   1281                                  the DMA operation is going to read or write to system memory.
   1282   @param ChannelNumber           The slave channel number to use for this DMA operation.
   1283                                  If Operation and ChannelAttributes shows that this device
   1284                                  performs bus mastering DMA, then this field is ignored.
   1285                                  The legal range for this field is 0..7.
   1286   @param ChannelAttributes       The attributes of the DMA channel to use for this DMA operation
   1287   @param HostAddress             The system memory address to map to the device.
   1288   @param NumberOfBytes           On input the number of bytes to map.  On output the number
   1289                                  of bytes that were mapped.
   1290   @param DeviceAddress           The resulting map address for the bus master device to use
   1291                                  to access the hosts HostAddress.
   1292   @param Mapping                 A resulting value to pass to EFI_ISA_IO.Unmap().
   1293 
   1294   @retval EFI_SUCCESS           - The range was mapped for the returned NumberOfBytes.
   1295   @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
   1296   @retval EFI_UNSUPPORTED       - The HostAddress can not be mapped as a common buffer.
   1297   @retval EFI_DEVICE_ERROR      - The system hardware could not map the requested address.
   1298   @retval EFI_OUT_OF_RESOURCES  - The memory pages could not be allocated.
   1299 **/
   1300 EFI_STATUS
   1301 IsaIoMapFullSupport (
   1302   IN     EFI_ISA_IO_PROTOCOL                                  *This,
   1303   IN     EFI_ISA_IO_PROTOCOL_OPERATION                        Operation,
   1304   IN     UINT8                                                ChannelNumber         OPTIONAL,
   1305   IN     UINT32                                               ChannelAttributes,
   1306   IN     VOID                                                 *HostAddress,
   1307   IN OUT UINTN                                                *NumberOfBytes,
   1308   OUT    EFI_PHYSICAL_ADDRESS                                 *DeviceAddress,
   1309   OUT    VOID                                                 **Mapping
   1310   )
   1311 {
   1312   EFI_STATUS            Status;
   1313   BOOLEAN               Master;
   1314   BOOLEAN               Read;
   1315   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
   1316   ISA_MAP_INFO          *IsaMapInfo;
   1317   UINT8                 DmaMode;
   1318   UINTN                 MaxNumberOfBytes;
   1319   UINT32                BaseAddress;
   1320   UINT16                Count;
   1321   UINT8                 DmaMask;
   1322   UINT8                 DmaClear;
   1323   UINT8                 DmaChannelMode;
   1324 
   1325   if ((NULL == This) ||
   1326       (NULL == HostAddress) ||
   1327       (NULL == NumberOfBytes) ||
   1328       (NULL == DeviceAddress) ||
   1329       (NULL == Mapping)
   1330       ) {
   1331     return EFI_INVALID_PARAMETER;
   1332   }
   1333 
   1334   //
   1335   // Initialize the return values to their defaults
   1336   //
   1337   *Mapping = NULL;
   1338 
   1339   //
   1340   // Make sure the Operation parameter is valid
   1341   //
   1342   if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {
   1343     return EFI_INVALID_PARAMETER;
   1344   }
   1345 
   1346   if (ChannelNumber >= 8) {
   1347     return EFI_INVALID_PARAMETER;
   1348   }
   1349 
   1350   //
   1351   // See if this is a Slave DMA Operation
   1352   //
   1353   Master  = TRUE;
   1354   Read    = FALSE;
   1355   if (Operation == EfiIsaIoOperationSlaveRead) {
   1356     Operation = EfiIsaIoOperationBusMasterRead;
   1357     Master    = FALSE;
   1358     Read      = TRUE;
   1359   }
   1360 
   1361   if (Operation == EfiIsaIoOperationSlaveWrite) {
   1362     Operation = EfiIsaIoOperationBusMasterWrite;
   1363     Master    = FALSE;
   1364     Read      = FALSE;
   1365   }
   1366 
   1367   if (!Master) {
   1368     //
   1369     // Make sure that ChannelNumber is a valid channel number
   1370     // Channel 4 is used to cascade, so it is illegal.
   1371     //
   1372     if (ChannelNumber == 4 || ChannelNumber > 7) {
   1373       return EFI_INVALID_PARAMETER;
   1374     }
   1375     //
   1376     // This implementation only support COMPATIBLE DMA Transfers
   1377     //
   1378     if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {
   1379       return EFI_INVALID_PARAMETER;
   1380     }
   1381 
   1382     if ((ChannelAttributes &
   1383          (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
   1384           EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
   1385           EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {
   1386       return EFI_INVALID_PARAMETER;
   1387     }
   1388 
   1389     if (ChannelNumber < 4) {
   1390       //
   1391       // If this is Channel 0..3, then the width must be 8 bit
   1392       //
   1393       if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||
   1394           ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)
   1395           ) {
   1396         return EFI_INVALID_PARAMETER;
   1397       }
   1398     } else {
   1399       //
   1400       // If this is Channel 4..7, then the width must be 16 bit
   1401       //
   1402       if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||
   1403           ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {
   1404         return EFI_INVALID_PARAMETER;
   1405       }
   1406     }
   1407     //
   1408     // Either Demand Mode or Single Mode must be selected, but not both
   1409     //
   1410     if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
   1411       if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
   1412         return EFI_INVALID_PARAMETER;
   1413       }
   1414     } else {
   1415       if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {
   1416         return EFI_INVALID_PARAMETER;
   1417       }
   1418     }
   1419   }
   1420   //
   1421   // Map the HostAddress to a DeviceAddress.
   1422   //
   1423   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
   1424   if ((PhysicalAddress +*NumberOfBytes) > BASE_16MB) {
   1425     //
   1426     // Common Buffer operations can not be remapped.  If the common buffer
   1427     // is above 16MB, then it is not possible to generate a mapping, so return
   1428     // an error.
   1429     //
   1430     if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
   1431       return EFI_UNSUPPORTED;
   1432     }
   1433     //
   1434     // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
   1435     // is called later.
   1436     //
   1437     IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
   1438     if (IsaMapInfo == NULL) {
   1439       *NumberOfBytes = 0;
   1440       return EFI_OUT_OF_RESOURCES;
   1441     }
   1442     //
   1443     // Return a pointer to the MAP_INFO structure in Mapping
   1444     //
   1445     *Mapping = IsaMapInfo;
   1446 
   1447     //
   1448     // Initialize the MAP_INFO structure
   1449     //
   1450     IsaMapInfo->Operation         = Operation;
   1451     IsaMapInfo->NumberOfBytes     = *NumberOfBytes;
   1452     IsaMapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (*NumberOfBytes);
   1453     IsaMapInfo->HostAddress       = PhysicalAddress;
   1454     IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
   1455 
   1456     //
   1457     // Allocate a buffer below 16MB to map the transfer to.
   1458     //
   1459     Status = gBS->AllocatePages (
   1460                     AllocateMaxAddress,
   1461                     EfiBootServicesData,
   1462                     IsaMapInfo->NumberOfPages,
   1463                     &IsaMapInfo->MappedHostAddress
   1464                     );
   1465     if (EFI_ERROR (Status)) {
   1466       FreePool (IsaMapInfo);
   1467       *NumberOfBytes  = 0;
   1468       *Mapping        = NULL;
   1469       return Status;
   1470     }
   1471     //
   1472     // If this is a read operation from the DMA agents's point of view,
   1473     // then copy the contents of the real buffer into the mapped buffer
   1474     // so the DMA agent can read the contents of the real buffer.
   1475     //
   1476     if (Operation == EfiIsaIoOperationBusMasterRead) {
   1477       CopyMem (
   1478         (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
   1479         (VOID *) (UINTN) IsaMapInfo->HostAddress,
   1480         IsaMapInfo->NumberOfBytes
   1481         );
   1482     }
   1483     //
   1484     // The DeviceAddress is the address of the maped buffer below 16 MB
   1485     //
   1486     *DeviceAddress = IsaMapInfo->MappedHostAddress;
   1487   } else {
   1488     //
   1489     // The transfer is below 16 MB, so the DeviceAddress is simply the
   1490     // HostAddress
   1491     //
   1492     *DeviceAddress = PhysicalAddress;
   1493   }
   1494   //
   1495   // If this is a Bus Master operation then return
   1496   //
   1497   if (Master) {
   1498     return EFI_SUCCESS;
   1499   }
   1500   //
   1501   // Figure out what to program into the DMA Channel Mode Register
   1502   //
   1503   DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
   1504   if (Read) {
   1505     DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
   1506   } else {
   1507     DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
   1508   }
   1509 
   1510   if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {
   1511     DmaMode |= B_8237_DMA_CHMODE_AE;
   1512   }
   1513 
   1514   if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
   1515     DmaMode |= V_8237_DMA_CHMODE_DEMAND;
   1516   }
   1517 
   1518   if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
   1519     DmaMode |= V_8237_DMA_CHMODE_SINGLE;
   1520   }
   1521   //
   1522   // A Slave DMA transfer can not cross a 64K boundary.
   1523   // Compute *NumberOfBytes based on this restriction.
   1524   //
   1525   MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
   1526   if (*NumberOfBytes > MaxNumberOfBytes) {
   1527     *NumberOfBytes = MaxNumberOfBytes;
   1528   }
   1529   //
   1530   // Compute the values to program into the BaseAddress and Count registers
   1531   // of the Slave DMA controller
   1532   //
   1533   if (ChannelNumber < 4) {
   1534     BaseAddress = (UINT32) (*DeviceAddress);
   1535     Count       = (UINT16) (*NumberOfBytes - 1);
   1536   } else {
   1537     BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
   1538     Count       = (UINT16) ((*NumberOfBytes - 1) >> 1);
   1539   }
   1540   //
   1541   // Program the DMA Write Single Mask Register for ChannelNumber
   1542   // Clear the DMA Byte Pointer Register
   1543   //
   1544   if (ChannelNumber < 4) {
   1545     DmaMask         = R_8237_DMA_WRSMSK_CH0_3;
   1546     DmaClear        = R_8237_DMA_CBPR_CH0_3;
   1547     DmaChannelMode  = R_8237_DMA_CHMODE_CH0_3;
   1548   } else {
   1549     DmaMask         = R_8237_DMA_WRSMSK_CH4_7;
   1550     DmaClear        = R_8237_DMA_CBPR_CH4_7;
   1551     DmaChannelMode  = R_8237_DMA_CHMODE_CH4_7;
   1552   }
   1553 
   1554   Status = WritePort (
   1555              This,
   1556              DmaMask,
   1557              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
   1558              );
   1559   if (EFI_ERROR (Status)) {
   1560     return Status;
   1561   }
   1562 
   1563   Status = WritePort (
   1564              This,
   1565              DmaClear,
   1566              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
   1567              );
   1568   if (EFI_ERROR (Status)) {
   1569     return Status;
   1570   }
   1571 
   1572   Status = WritePort (This, DmaChannelMode, DmaMode);
   1573   if (EFI_ERROR (Status)) {
   1574     return Status;
   1575   }
   1576 
   1577   Status = WriteDmaPort (
   1578              This,
   1579              mDmaRegisters[ChannelNumber].Address,
   1580              mDmaRegisters[ChannelNumber].Page,
   1581              mDmaRegisters[ChannelNumber].Count,
   1582              BaseAddress,
   1583              Count
   1584              );
   1585   if (EFI_ERROR (Status)) {
   1586     return Status;
   1587   }
   1588 
   1589   Status = WritePort (
   1590              This,
   1591              DmaMask,
   1592              (UINT8) (ChannelNumber & 0x03)
   1593              );
   1594   if (EFI_ERROR (Status)) {
   1595     return Status;
   1596   }
   1597 
   1598   return EFI_SUCCESS;
   1599 }
   1600 
   1601 /**
   1602   Maps a memory region for DMA
   1603 
   1604   @param This                    A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1605   @param Operation               Indicates the type of DMA (slave or bus master), and if
   1606                                  the DMA operation is going to read or write to system memory.
   1607   @param ChannelNumber           The slave channel number to use for this DMA operation.
   1608                                  If Operation and ChannelAttributes shows that this device
   1609                                  performs bus mastering DMA, then this field is ignored.
   1610                                  The legal range for this field is 0..7.
   1611   @param ChannelAttributes       The attributes of the DMA channel to use for this DMA operation
   1612   @param HostAddress             The system memory address to map to the device.
   1613   @param NumberOfBytes           On input the number of bytes to map.  On output the number
   1614                                  of bytes that were mapped.
   1615   @param DeviceAddress           The resulting map address for the bus master device to use
   1616                                  to access the hosts HostAddress.
   1617   @param Mapping                 A resulting value to pass to EFI_ISA_IO.Unmap().
   1618 
   1619   @retval EFI_SUCCESS            The range was mapped for the returned NumberOfBytes.
   1620   @retval EFI_INVALID_PARAMETER  The Operation or HostAddress is undefined.
   1621   @retval EFI_UNSUPPORTED        The HostAddress can not be mapped as a common buffer.
   1622   @retval EFI_DEVICE_ERROR       The system hardware could not map the requested address.
   1623   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
   1624 **/
   1625 EFI_STATUS
   1626 EFIAPI
   1627 IsaIoMap (
   1628   IN     EFI_ISA_IO_PROTOCOL            *This,
   1629   IN     EFI_ISA_IO_PROTOCOL_OPERATION  Operation,
   1630   IN     UINT8                          ChannelNumber  OPTIONAL,
   1631   IN     UINT32                         ChannelAttributes,
   1632   IN     VOID                           *HostAddress,
   1633   IN OUT UINTN                          *NumberOfBytes,
   1634   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
   1635   OUT    VOID                           **Mapping
   1636   )
   1637 {
   1638   //
   1639   // Check if DMA is supported.
   1640   //
   1641   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
   1642     return EFI_UNSUPPORTED;
   1643   }
   1644   //
   1645   // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
   1646   // ISA Bus Master.
   1647   //
   1648   // So we just return EFI_UNSUPPORTED for these functions.
   1649   //
   1650   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {
   1651     return IsaIoMapOnlySupportSlaveReadWrite (
   1652              This,
   1653              Operation,
   1654              ChannelNumber,
   1655              ChannelAttributes,
   1656              HostAddress,
   1657              NumberOfBytes,
   1658              DeviceAddress,
   1659              Mapping
   1660              );
   1661 
   1662   } else {
   1663     return IsaIoMapFullSupport (
   1664              This,
   1665              Operation,
   1666              ChannelNumber,
   1667              ChannelAttributes,
   1668              HostAddress,
   1669              NumberOfBytes,
   1670              DeviceAddress,
   1671              Mapping
   1672              );
   1673   }
   1674 }
   1675 
   1676 /**
   1677   Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
   1678 
   1679   @param[in]  This               A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1680   @param[in]  Type               The type allocation to perform.
   1681   @param[in]  MemoryType         The type of memory to allocate.
   1682   @param[in]  Pages              The number of pages to allocate.
   1683   @param[out] HostAddress        A pointer to store the base address of the allocated range.
   1684   @param[in]  Attributes         The requested bit mask of attributes for the allocated range.
   1685 
   1686   @retval EFI_SUCCESS            The requested memory pages were allocated.
   1687   @retval EFI_INVALID_PARAMETER  Type is invalid or MemoryType is invalid or HostAddress is NULL
   1688   @retval EFI_UNSUPPORTED        Attributes is unsupported or the memory range specified
   1689                                  by HostAddress, Pages, and Type is not available for common buffer use.
   1690   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
   1691 **/
   1692 EFI_STATUS
   1693 EFIAPI
   1694 IsaIoAllocateBuffer (
   1695   IN  EFI_ISA_IO_PROTOCOL  *This,
   1696   IN  EFI_ALLOCATE_TYPE    Type,
   1697   IN  EFI_MEMORY_TYPE      MemoryType,
   1698   IN  UINTN                Pages,
   1699   OUT VOID                 **HostAddress,
   1700   IN  UINT64               Attributes
   1701   )
   1702 {
   1703   EFI_STATUS            Status;
   1704   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
   1705 
   1706   //
   1707   // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
   1708   // ISA Bus Master.
   1709   // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
   1710   //
   1711   if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
   1712       ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
   1713     return EFI_UNSUPPORTED;
   1714   }
   1715 
   1716   if (HostAddress == NULL) {
   1717     return EFI_INVALID_PARAMETER;
   1718   }
   1719 
   1720   if ((UINT32)Type >= MaxAllocateType) {
   1721     return EFI_INVALID_PARAMETER;
   1722   }
   1723   //
   1724   // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
   1725   //
   1726   if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
   1727     return EFI_INVALID_PARAMETER;
   1728   }
   1729 
   1730   if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {
   1731     return EFI_UNSUPPORTED;
   1732   }
   1733 
   1734   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (BASE_16MB - 1);
   1735   if (Type == AllocateAddress) {
   1736     if ((UINTN) (*HostAddress) >= BASE_16MB) {
   1737       return EFI_UNSUPPORTED;
   1738     } else {
   1739       PhysicalAddress = (UINTN) (*HostAddress);
   1740     }
   1741   }
   1742 
   1743   if (Type == AllocateAnyPages) {
   1744     Type = AllocateMaxAddress;
   1745   }
   1746 
   1747   Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
   1748   if (EFI_ERROR (Status)) {
   1749     REPORT_STATUS_CODE (
   1750       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1751       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
   1752       );
   1753     return Status;
   1754   }
   1755 
   1756   *HostAddress = (VOID *) (UINTN) PhysicalAddress;
   1757   return Status;
   1758 }
   1759 
   1760 /**
   1761   Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
   1762 
   1763   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1764   @param[in] Pages               The number of pages to free.
   1765   @param[in] HostAddress         The base address of the allocated range.
   1766 
   1767   @retval EFI_SUCCESS            The requested memory pages were freed.
   1768   @retval EFI_INVALID_PARAMETER  The memory was not allocated with EFI_ISA_IO.AllocateBufer().
   1769 **/
   1770 EFI_STATUS
   1771 EFIAPI
   1772 IsaIoFreeBuffer (
   1773   IN EFI_ISA_IO_PROTOCOL  *This,
   1774   IN UINTN                Pages,
   1775   IN VOID                 *HostAddress
   1776   )
   1777 {
   1778   EFI_STATUS  Status;
   1779 
   1780   //
   1781   // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
   1782   // ISA Bus Master.
   1783   // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
   1784   //
   1785   if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
   1786       ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
   1787     return EFI_UNSUPPORTED;
   1788   }
   1789 
   1790   Status = gBS->FreePages (
   1791                   (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
   1792                   Pages
   1793                   );
   1794   if (EFI_ERROR (Status)) {
   1795     REPORT_STATUS_CODE (
   1796       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1797       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
   1798       );
   1799   }
   1800 
   1801   return Status;
   1802 }
   1803 
   1804