Home | History | Annotate | Download | only in IsaBusDxe
      1 /** @file
      2   The implementation for EFI_ISA_IO_PROTOCOL.
      3 
      4 Copyright (c) 2006 - 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 "InternalIsaIo.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   Initializes an ISA I/O Instance
     85 
     86   @param[in] IsaIoDevice            The iso device to be initialized.
     87   @param[in] IsaDeviceResourceList  The resource list.
     88 
     89 **/
     90 VOID
     91 InitializeIsaIoInstance (
     92   IN ISA_IO_DEVICE               *IsaIoDevice,
     93   IN EFI_ISA_ACPI_RESOURCE_LIST  *IsaDeviceResourceList
     94   )
     95 {
     96   //
     97   // Use the ISA IO Protocol structure template to initialize the ISA IO instance
     98   //
     99   CopyMem (
    100     &IsaIoDevice->IsaIo,
    101     &mIsaIoInterface,
    102     sizeof (EFI_ISA_IO_PROTOCOL)
    103     );
    104 
    105   IsaIoDevice->IsaIo.ResourceList = IsaDeviceResourceList;
    106 }
    107 
    108 /**
    109   Performs an ISA I/O Read Cycle
    110 
    111   @param[in]  This              A pointer to the EFI_ISA_IO_PROTOCOL instance.
    112   @param[in]  Width             Specifies the width of the I/O operation.
    113   @param[in]  Offset            The offset in ISA I/O space to start the I/O operation.
    114   @param[in]  Count             The number of I/O operations to perform.
    115   @param[out] Buffer            The destination buffer to store the results
    116 
    117   @retval EFI_SUCCESS           The data was read from the device sucessfully.
    118   @retval EFI_UNSUPPORTED       The Offset is not valid for this device.
    119   @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
    120   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
    121 **/
    122 EFI_STATUS
    123 EFIAPI
    124 IsaIoIoRead (
    125   IN  EFI_ISA_IO_PROTOCOL        *This,
    126   IN  EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    127   IN  UINT32                     Offset,
    128   IN  UINTN                      Count,
    129   OUT VOID                       *Buffer
    130   )
    131 {
    132   EFI_STATUS    Status;
    133   ISA_IO_DEVICE *IsaIoDevice;
    134 
    135   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    136 
    137   //
    138   // Verify Isa IO Access
    139   //
    140   Status = IsaIoVerifyAccess (
    141              IsaIoDevice,
    142              IsaAccessTypeIo,
    143              Width,
    144              Count,
    145              Offset
    146              );
    147   if (EFI_ERROR (Status)) {
    148     return Status;
    149   }
    150 
    151   Status = IsaIoDevice->PciIo->Io.Read (
    152                                     IsaIoDevice->PciIo,
    153                                     (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    154                                     EFI_PCI_IO_PASS_THROUGH_BAR,
    155                                     Offset,
    156                                     Count,
    157                                     Buffer
    158                                     );
    159 
    160   if (EFI_ERROR (Status)) {
    161     REPORT_STATUS_CODE (
    162       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    163       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    164       );
    165   }
    166 
    167   return Status;
    168 }
    169 
    170 /**
    171   Performs an ISA I/O Write Cycle
    172 
    173   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    174   @param[in] Width               Specifies the width of the I/O operation.
    175   @param[in] Offset              The offset in ISA I/O space to start the I/O operation.
    176   @param[in] Count               The number of I/O operations to perform.
    177   @param[in] Buffer              The source buffer to write data from
    178 
    179   @retval EFI_SUCCESS            The data was writen to the device sucessfully.
    180   @retval EFI_UNSUPPORTED        The Offset is not valid for this device.
    181   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    182   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    183 **/
    184 EFI_STATUS
    185 EFIAPI
    186 IsaIoIoWrite (
    187   IN EFI_ISA_IO_PROTOCOL        *This,
    188   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    189   IN UINT32                     Offset,
    190   IN UINTN                      Count,
    191   IN VOID                       *Buffer
    192   )
    193 {
    194   EFI_STATUS    Status;
    195   ISA_IO_DEVICE *IsaIoDevice;
    196 
    197   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    198 
    199   //
    200   // Verify Isa IO Access
    201   //
    202   Status = IsaIoVerifyAccess (
    203              IsaIoDevice,
    204              IsaAccessTypeIo,
    205              Width,
    206              Count,
    207              Offset
    208              );
    209   if (EFI_ERROR (Status)) {
    210     return Status;
    211   }
    212 
    213   Status = IsaIoDevice->PciIo->Io.Write (
    214                                     IsaIoDevice->PciIo,
    215                                     (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    216                                     EFI_PCI_IO_PASS_THROUGH_BAR,
    217                                     Offset,
    218                                     Count,
    219                                     Buffer
    220                                     );
    221 
    222   if (EFI_ERROR (Status)) {
    223     REPORT_STATUS_CODE (
    224       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    225       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    226       );
    227   }
    228 
    229   return Status;
    230 }
    231 
    232 /**
    233   Writes an 8-bit I/O Port
    234 
    235   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    236   @param[in] Offset              The offset in ISA IO space to start the IO operation.
    237   @param[in] Value               The data to write port.
    238 
    239   @retval EFI_SUCCESS            Success.
    240   @retval EFI_INVALID_PARAMETER  Parameter is invalid.
    241   @retval EFI_UNSUPPORTED        The address range specified by Offset is not valid.
    242   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    243 **/
    244 EFI_STATUS
    245 WritePort (
    246   IN EFI_ISA_IO_PROTOCOL  *This,
    247   IN UINT32               Offset,
    248   IN UINT8                Value
    249   )
    250 {
    251   EFI_STATUS    Status;
    252   ISA_IO_DEVICE *IsaIoDevice;
    253 
    254   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    255 
    256   Status = IsaIoDevice->PciIo->Io.Write (
    257                                     IsaIoDevice->PciIo,
    258                                     EfiPciIoWidthUint8,
    259                                     EFI_PCI_IO_PASS_THROUGH_BAR,
    260                                     Offset,
    261                                     1,
    262                                     &Value
    263                                     );
    264   if (EFI_ERROR (Status)) {
    265     REPORT_STATUS_CODE (
    266       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    267       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    268       );
    269     return Status;
    270   }
    271 
    272   gBS->Stall (50);
    273 
    274   return EFI_SUCCESS;
    275 }
    276 
    277 /**
    278   Writes I/O operation base address and count number to a 8 bit I/O Port.
    279 
    280   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    281   @param[in] AddrOffset          The address' offset.
    282   @param[in] PageOffset          The page's offest.
    283   @param[in] CountOffset         The count's offset.
    284   @param[in] BaseAddress         The base address.
    285   @param[in] Count               The number of I/O operations to perform.
    286 
    287   @retval EFI_SUCCESS            Success.
    288   @retval EFI_INVALID_PARAMETER  Parameter is invalid.
    289   @retval EFI_UNSUPPORTED        The address range specified by these Offsets and Count is not valid.
    290   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    291 **/
    292 EFI_STATUS
    293 WriteDmaPort (
    294   IN EFI_ISA_IO_PROTOCOL  *This,
    295   IN UINT32               AddrOffset,
    296   IN UINT32               PageOffset,
    297   IN UINT32               CountOffset,
    298   IN UINT32               BaseAddress,
    299   IN UINT16               Count
    300   )
    301 {
    302   EFI_STATUS  Status;
    303 
    304   Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));
    305   if (EFI_ERROR (Status)) {
    306     return Status;
    307   }
    308 
    309   Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));
    310   if (EFI_ERROR (Status)) {
    311     return Status;
    312   }
    313 
    314   Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));
    315   if (EFI_ERROR (Status)) {
    316     return Status;
    317   }
    318 
    319   Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));
    320   if (EFI_ERROR (Status)) {
    321     return Status;
    322   }
    323 
    324   Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));
    325   return Status;
    326 }
    327 
    328 /**
    329   Unmaps a memory region for DMA
    330 
    331   @param[in] This           A pointer to the EFI_ISA_IO_PROTOCOL instance.
    332   @param[in] Mapping        The mapping value returned from EFI_ISA_IO.Map().
    333 
    334   @retval EFI_SUCCESS       The range was unmapped.
    335   @retval EFI_DEVICE_ERROR  The data was not committed to the target system memory.
    336 **/
    337 EFI_STATUS
    338 EFIAPI
    339 IsaIoUnmap (
    340   IN EFI_ISA_IO_PROTOCOL  *This,
    341   IN VOID                 *Mapping
    342   )
    343 {
    344   ISA_MAP_INFO  *IsaMapInfo;
    345 
    346   //
    347   // Check if DMA is supported.
    348   //
    349   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
    350     return EFI_UNSUPPORTED;
    351   }
    352 
    353   //
    354   // See if the Map() operation associated with this Unmap() required a mapping
    355   // buffer.If a mapping buffer was not required, then this function simply
    356   // returns EFI_SUCCESS.
    357   //
    358   if (Mapping != NULL) {
    359     //
    360     // Get the MAP_INFO structure from Mapping
    361     //
    362     IsaMapInfo = (ISA_MAP_INFO *) Mapping;
    363 
    364     //
    365     // If this is a write operation from the Agent's point of view,
    366     // then copy the contents of the mapped buffer into the real buffer
    367     // so the processor can read the contents of the real buffer.
    368     //
    369     if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {
    370       CopyMem (
    371         (VOID *) (UINTN) IsaMapInfo->HostAddress,
    372         (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
    373         IsaMapInfo->NumberOfBytes
    374         );
    375     }
    376     //
    377     // Free the mapped buffer and the MAP_INFO structure.
    378     //
    379     gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);
    380     FreePool (IsaMapInfo);
    381   }
    382 
    383   return EFI_SUCCESS;
    384 }
    385 
    386 /**
    387   Flushes any posted write data to the system memory.
    388 
    389   @param[in] This             A pointer to the EFI_ISA_IO_PROTOCOL instance.
    390 
    391   @retval  EFI_SUCCESS        The buffers were flushed.
    392   @retval  EFI_DEVICE_ERROR   The buffers were not flushed due to a hardware error.
    393 **/
    394 EFI_STATUS
    395 EFIAPI
    396 IsaIoFlush (
    397   IN EFI_ISA_IO_PROTOCOL  *This
    398   )
    399 {
    400   EFI_STATUS    Status;
    401   ISA_IO_DEVICE *IsaIoDevice;
    402 
    403   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    404 
    405   Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);
    406 
    407   if (EFI_ERROR (Status)) {
    408     REPORT_STATUS_CODE (
    409       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    410       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    411       );
    412   }
    413 
    414   return Status;
    415 }
    416 
    417 /**
    418   Verifies access to an ISA device
    419 
    420   @param[in] IsaIoDevice         The ISA device to be verified.
    421   @param[in] Type                The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
    422   @param[in] Width               The width of the memory operation.
    423   @param[in] Count               The number of memory operations to perform.
    424   @param[in] Offset              The offset in ISA memory space to start the memory operation.
    425 
    426   @retval EFI_SUCCESS            Verify success.
    427   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.
    428   @retval EFI_UNSUPPORTED        The device ont support the access type.
    429 **/
    430 EFI_STATUS
    431 IsaIoVerifyAccess (
    432   IN ISA_IO_DEVICE              *IsaIoDevice,
    433   IN ISA_ACCESS_TYPE            Type,
    434   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    435   IN UINTN                      Count,
    436   IN UINT32                     Offset
    437   )
    438 {
    439   EFI_ISA_ACPI_RESOURCE *Item;
    440   EFI_STATUS            Status;
    441 
    442   if ((UINT32)Width >= EfiIsaIoWidthMaximum ||
    443       Width == EfiIsaIoWidthReserved ||
    444       Width == EfiIsaIoWidthFifoReserved ||
    445       Width == EfiIsaIoWidthFillReserved
    446       ) {
    447     return EFI_INVALID_PARAMETER;
    448   }
    449 
    450   //
    451   // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
    452   // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
    453   //
    454   if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {
    455     Count = 1;
    456   }
    457 
    458   Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);
    459 
    460   Status  = EFI_UNSUPPORTED;
    461   Item    = IsaIoDevice->IsaIo.ResourceList->ResourceItem;
    462   while (Item->Type != EfiIsaAcpiResourceEndOfList) {
    463     if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||
    464         (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {
    465       if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {
    466         return EFI_SUCCESS;
    467       }
    468 
    469       if (Offset >= Item->StartRange && Offset <= Item->EndRange) {
    470         Status = EFI_INVALID_PARAMETER;
    471       }
    472     }
    473 
    474     Item++;
    475   }
    476 
    477   return Status;
    478 }
    479 
    480 /**
    481   Performs an ISA Memory Read Cycle
    482 
    483   @param[in]  This               A pointer to the EFI_ISA_IO_PROTOCOL instance.
    484   @param[in]  Width              Specifies the width of the memory operation.
    485   @param[in]  Offset             The offset in ISA memory space to start the memory operation.
    486   @param[in]  Count              The number of memory operations to perform.
    487   @param[out] Buffer             The destination buffer to store the results
    488 
    489   @retval EFI_SUCCESS            The data was read from the device successfully.
    490   @retval EFI_UNSUPPORTED        The Offset is not valid for this device.
    491   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    492   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    493 **/
    494 EFI_STATUS
    495 EFIAPI
    496 IsaIoMemRead (
    497   IN  EFI_ISA_IO_PROTOCOL        *This,
    498   IN  EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    499   IN  UINT32                     Offset,
    500   IN  UINTN                      Count,
    501   OUT VOID                       *Buffer
    502   )
    503 {
    504   EFI_STATUS    Status;
    505   ISA_IO_DEVICE *IsaIoDevice;
    506 
    507   //
    508   // Check if ISA memory is supported.
    509   //
    510   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
    511     return EFI_UNSUPPORTED;
    512   }
    513 
    514   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    515 
    516   //
    517   // Verify the Isa Io Access
    518   //
    519   Status = IsaIoVerifyAccess (
    520              IsaIoDevice,
    521              IsaAccessTypeMem,
    522              Width,
    523              Count,
    524              Offset
    525              );
    526   if (EFI_ERROR (Status)) {
    527     return Status;
    528   }
    529 
    530   Status = IsaIoDevice->PciIo->Mem.Read (
    531                                      IsaIoDevice->PciIo,
    532                                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    533                                      EFI_PCI_IO_PASS_THROUGH_BAR,
    534                                      Offset,
    535                                      Count,
    536                                      Buffer
    537                                      );
    538 
    539   if (EFI_ERROR (Status)) {
    540     REPORT_STATUS_CODE (
    541       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    542       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    543       );
    544   }
    545 
    546   return Status;
    547 }
    548 
    549 /**
    550   Performs an ISA Memory Write Cycle
    551 
    552   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
    553   @param[in] Width               Specifies the width of the memory operation.
    554   @param[in] Offset              The offset in ISA memory space to start the memory operation.
    555   @param[in] Count               The number of memory operations to perform.
    556   @param[in] Buffer              The source buffer to write data from
    557 
    558   @retval EFI_SUCCESS            The data was written to the device sucessfully.
    559   @retval EFI_UNSUPPORTED        The Offset is not valid for this device.
    560   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    561   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    562 **/
    563 EFI_STATUS
    564 EFIAPI
    565 IsaIoMemWrite (
    566   IN EFI_ISA_IO_PROTOCOL        *This,
    567   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    568   IN UINT32                     Offset,
    569   IN UINTN                      Count,
    570   IN VOID                       *Buffer
    571   )
    572 {
    573   EFI_STATUS    Status;
    574   ISA_IO_DEVICE *IsaIoDevice;
    575 
    576   //
    577   // Check if ISA memory is supported.
    578   //
    579   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
    580     return EFI_UNSUPPORTED;
    581   }
    582 
    583   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    584 
    585   //
    586   // Verify Isa IO Access
    587   //
    588   Status = IsaIoVerifyAccess (
    589              IsaIoDevice,
    590              IsaAccessTypeMem,
    591              Width,
    592              Count,
    593              Offset
    594              );
    595   if (EFI_ERROR (Status)) {
    596     return Status;
    597   }
    598 
    599   Status = IsaIoDevice->PciIo->Mem.Write (
    600                                      IsaIoDevice->PciIo,
    601                                      (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    602                                      EFI_PCI_IO_PASS_THROUGH_BAR,
    603                                      Offset,
    604                                      Count,
    605                                      Buffer
    606                                      );
    607 
    608   if (EFI_ERROR (Status)) {
    609     REPORT_STATUS_CODE (
    610       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    611       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    612       );
    613   }
    614 
    615   return Status;
    616 }
    617 
    618 /**
    619   Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
    620 
    621   @param[in]  This               A pointer to the EFI_ISA_IO_PROTOCOL instance.
    622   @param[in]  Width              Specifies the width of the memory copy operation.
    623   @param[in]  DestOffset         The offset of the destination
    624   @param[in]  SrcOffset          The offset of the source
    625   @param[in]  Count              The number of memory copy  operations to perform
    626 
    627   @retval EFI_SUCCESS            The data was copied sucessfully.
    628   @retval EFI_UNSUPPORTED        The DestOffset or SrcOffset is not valid for this device.
    629   @retval EFI_INVALID_PARAMETER  Width or Count, or both, were invalid.
    630   @retval EFI_OUT_OF_RESOURCES   The request could not be completed due to a lack of resources.
    631 **/
    632 EFI_STATUS
    633 EFIAPI
    634 IsaIoCopyMem (
    635   IN EFI_ISA_IO_PROTOCOL        *This,
    636   IN EFI_ISA_IO_PROTOCOL_WIDTH  Width,
    637   IN UINT32                     DestOffset,
    638   IN UINT32                     SrcOffset,
    639   IN UINTN                      Count
    640   )
    641 {
    642   EFI_STATUS    Status;
    643   ISA_IO_DEVICE *IsaIoDevice;
    644 
    645   //
    646   // Check if ISA memory is supported.
    647   //
    648   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
    649     return EFI_UNSUPPORTED;
    650   }
    651 
    652   IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
    653 
    654   //
    655   // Verify Isa IO Access for destination and source
    656   //
    657   Status = IsaIoVerifyAccess (
    658              IsaIoDevice,
    659              IsaAccessTypeMem,
    660              Width,
    661              Count,
    662              DestOffset
    663              );
    664   if (EFI_ERROR (Status)) {
    665     return Status;
    666   }
    667 
    668   Status = IsaIoVerifyAccess (
    669              IsaIoDevice,
    670              IsaAccessTypeMem,
    671              Width,
    672              Count,
    673              SrcOffset
    674              );
    675   if (EFI_ERROR (Status)) {
    676     return Status;
    677   }
    678 
    679   Status = IsaIoDevice->PciIo->CopyMem (
    680                                  IsaIoDevice->PciIo,
    681                                  (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
    682                                  EFI_PCI_IO_PASS_THROUGH_BAR,
    683                                  DestOffset,
    684                                  EFI_PCI_IO_PASS_THROUGH_BAR,
    685                                  SrcOffset,
    686                                  Count
    687                                  );
    688 
    689   if (EFI_ERROR (Status)) {
    690     REPORT_STATUS_CODE (
    691       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    692       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
    693       );
    694   }
    695 
    696   return Status;
    697 }
    698 
    699 /**
    700   Maps a memory region for DMA, note this implementation
    701   only supports slave read/write operation to save code size.
    702 
    703   @param This                    A pointer to the EFI_ISA_IO_PROTOCOL instance.
    704   @param Operation               Indicates the type of DMA (slave or bus master), and if
    705                                  the DMA operation is going to read or write to system memory.
    706   @param ChannelNumber           The slave channel number to use for this DMA operation.
    707                                  If Operation and ChannelAttributes shows that this device
    708                                  performs bus mastering DMA, then this field is ignored.
    709                                  The legal range for this field is 0..7.
    710   @param ChannelAttributes       The attributes of the DMA channel to use for this DMA operation
    711   @param HostAddress             The system memory address to map to the device.
    712   @param NumberOfBytes           On input the number of bytes to map.  On output the number
    713                                  of bytes that were mapped.
    714   @param DeviceAddress           The resulting map address for the bus master device to use
    715                                  to access the hosts HostAddress.
    716   @param Mapping                 A resulting value to pass to EFI_ISA_IO.Unmap().
    717 
    718   @retval EFI_SUCCESS            The range was mapped for the returned NumberOfBytes.
    719   @retval EFI_INVALID_PARAMETER  The Operation or HostAddress is undefined.
    720   @retval EFI_UNSUPPORTED        The HostAddress can not be mapped as a common buffer.
    721   @retval EFI_DEVICE_ERROR       The system hardware could not map the requested address.
    722   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
    723 **/
    724 EFI_STATUS
    725 IsaIoMapOnlySupportSlaveReadWrite (
    726   IN     EFI_ISA_IO_PROTOCOL            *This,
    727   IN     EFI_ISA_IO_PROTOCOL_OPERATION  Operation,
    728   IN     UINT8                          ChannelNumber  OPTIONAL,
    729   IN     UINT32                         ChannelAttributes,
    730   IN     VOID                           *HostAddress,
    731   IN OUT UINTN                          *NumberOfBytes,
    732   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
    733   OUT    VOID                           **Mapping
    734   )
    735 {
    736   EFI_STATUS            Status;
    737   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
    738   ISA_MAP_INFO          *IsaMapInfo;
    739   UINT8                 DmaMode;
    740   UINTN                 MaxNumberOfBytes;
    741   UINT32                BaseAddress;
    742   UINT16                Count;
    743   UINT8                 DmaMask;
    744   UINT8                 DmaClear;
    745   UINT8                 DmaChannelMode;
    746 
    747   if ((NULL == This) ||
    748       (NULL == HostAddress) ||
    749       (NULL == NumberOfBytes) ||
    750       (NULL == DeviceAddress) ||
    751       (NULL == Mapping)
    752       ) {
    753     return EFI_INVALID_PARAMETER;
    754   }
    755 
    756   //
    757   // Initialize the return values to their defaults
    758   //
    759   *Mapping = NULL;
    760 
    761   //
    762   // Make sure the Operation parameter is valid.
    763   // Light IsaIo only supports two operations.
    764   //
    765   if (!(Operation == EfiIsaIoOperationSlaveRead ||
    766         Operation == EfiIsaIoOperationSlaveWrite)) {
    767     return EFI_INVALID_PARAMETER;
    768   }
    769 
    770   if (ChannelNumber >= 4) {
    771     //
    772     // The Light IsaIo doesn't support channelNumber larger than 4.
    773     //
    774     return EFI_INVALID_PARAMETER;
    775   }
    776 
    777   //
    778   // Map the HostAddress to a DeviceAddress.
    779   //
    780   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
    781   if ((PhysicalAddress + *NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {
    782     //
    783     // Common Buffer operations can not be remapped.  If the common buffer
    784     // is above 16MB, then it is not possible to generate a mapping, so return
    785     // an error.
    786     //
    787     if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
    788       return EFI_UNSUPPORTED;
    789     }
    790     //
    791     // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
    792     // is called later.
    793     //
    794     IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
    795     if (IsaMapInfo == NULL) {
    796       *NumberOfBytes = 0;
    797       return EFI_OUT_OF_RESOURCES;
    798     }
    799     //
    800     // Return a pointer to the MAP_INFO structure in Mapping
    801     //
    802     *Mapping = IsaMapInfo;
    803 
    804     //
    805     // Initialize the MAP_INFO structure
    806     //
    807     IsaMapInfo->Operation         = Operation;
    808     IsaMapInfo->NumberOfBytes     = *NumberOfBytes;
    809     IsaMapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (*NumberOfBytes);
    810     IsaMapInfo->HostAddress       = PhysicalAddress;
    811     IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;
    812 
    813     //
    814     // Allocate a buffer below 16MB to map the transfer to.
    815     //
    816     Status = gBS->AllocatePages (
    817                     AllocateMaxAddress,
    818                     EfiBootServicesData,
    819                     IsaMapInfo->NumberOfPages,
    820                     &IsaMapInfo->MappedHostAddress
    821                     );
    822     if (EFI_ERROR (Status)) {
    823       FreePool (IsaMapInfo);
    824       *NumberOfBytes  = 0;
    825       *Mapping        = NULL;
    826       return Status;
    827     }
    828     //
    829     // If this is a read operation from the DMA agents's point of view,
    830     // then copy the contents of the real buffer into the mapped buffer
    831     // so the DMA agent can read the contents of the real buffer.
    832     //
    833     if (Operation == EfiIsaIoOperationSlaveRead) {
    834       CopyMem (
    835         (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
    836         (VOID *) (UINTN) IsaMapInfo->HostAddress,
    837         IsaMapInfo->NumberOfBytes
    838         );
    839     }
    840     //
    841     // The DeviceAddress is the address of the maped buffer below 16 MB
    842     //
    843     *DeviceAddress = IsaMapInfo->MappedHostAddress;
    844   } else {
    845     //
    846     // The transfer is below 16 MB, so the DeviceAddress is simply the
    847     // HostAddress
    848     //
    849     *DeviceAddress = PhysicalAddress;
    850   }
    851 
    852   //
    853   // Figure out what to program into the DMA Channel Mode Register
    854   //
    855   DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
    856   if (Operation == EfiIsaIoOperationSlaveRead) {
    857     DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
    858   } else {
    859     DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
    860   }
    861   //
    862   // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
    863   //
    864   DmaMode |= V_8237_DMA_CHMODE_SINGLE;
    865 
    866   //
    867   // A Slave DMA transfer can not cross a 64K boundary.
    868   // Compute *NumberOfBytes based on this restriction.
    869   //
    870   MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
    871   if (*NumberOfBytes > MaxNumberOfBytes) {
    872     *NumberOfBytes = MaxNumberOfBytes;
    873   }
    874   //
    875   // Compute the values to program into the BaseAddress and Count registers
    876   // of the Slave DMA controller
    877   //
    878   BaseAddress = (UINT32) (*DeviceAddress);
    879   Count       = (UINT16) (*NumberOfBytes - 1);
    880   //
    881   // Program the DMA Write Single Mask Register for ChannelNumber
    882   // Clear the DMA Byte Pointer Register
    883   //
    884   DmaMask         = R_8237_DMA_WRSMSK_CH0_3;
    885   DmaClear        = R_8237_DMA_CBPR_CH0_3;
    886   DmaChannelMode  = R_8237_DMA_CHMODE_CH0_3;
    887 
    888   Status = WritePort (
    889              This,
    890              DmaMask,
    891              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
    892              );
    893   if (EFI_ERROR (Status)) {
    894     return Status;
    895   }
    896 
    897   Status = WritePort (
    898              This,
    899              DmaClear,
    900              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
    901              );
    902   if (EFI_ERROR (Status)) {
    903     return Status;
    904   }
    905 
    906   Status = WritePort (This, DmaChannelMode, DmaMode);
    907   if (EFI_ERROR (Status)) {
    908     return Status;
    909   }
    910 
    911   Status = WriteDmaPort (
    912              This,
    913              mDmaRegisters[ChannelNumber].Address,
    914              mDmaRegisters[ChannelNumber].Page,
    915              mDmaRegisters[ChannelNumber].Count,
    916              BaseAddress,
    917              Count
    918              );
    919   if (EFI_ERROR (Status)) {
    920     return Status;
    921   }
    922 
    923   Status = WritePort (
    924              This,
    925              DmaMask,
    926              (UINT8) (ChannelNumber & 0x03)
    927              );
    928   if (EFI_ERROR (Status)) {
    929     return Status;
    930   }
    931 
    932   return EFI_SUCCESS;
    933 }
    934 
    935 /**
    936   Maps a memory region for DMA. This implementation implement the
    937   the full mapping support.
    938 
    939   @param This                    A pointer to the EFI_ISA_IO_PROTOCOL instance.
    940   @param Operation               Indicates the type of DMA (slave or bus master), and if
    941                                  the DMA operation is going to read or write to system memory.
    942   @param ChannelNumber           The slave channel number to use for this DMA operation.
    943                                  If Operation and ChannelAttributes shows that this device
    944                                  performs bus mastering DMA, then this field is ignored.
    945                                  The legal range for this field is 0..7.
    946   @param ChannelAttributes       The attributes of the DMA channel to use for this DMA operation
    947   @param HostAddress             The system memory address to map to the device.
    948   @param NumberOfBytes           On input the number of bytes to map.  On output the number
    949                                  of bytes that were mapped.
    950   @param DeviceAddress           The resulting map address for the bus master device to use
    951                                  to access the hosts HostAddress.
    952   @param Mapping                 A resulting value to pass to EFI_ISA_IO.Unmap().
    953 
    954   @retval EFI_SUCCESS           - The range was mapped for the returned NumberOfBytes.
    955   @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
    956   @retval EFI_UNSUPPORTED       - The HostAddress can not be mapped as a common buffer.
    957   @retval EFI_DEVICE_ERROR      - The system hardware could not map the requested address.
    958   @retval EFI_OUT_OF_RESOURCES  - The memory pages could not be allocated.
    959 **/
    960 EFI_STATUS
    961 IsaIoMapFullSupport (
    962   IN     EFI_ISA_IO_PROTOCOL                                  *This,
    963   IN     EFI_ISA_IO_PROTOCOL_OPERATION                        Operation,
    964   IN     UINT8                                                ChannelNumber         OPTIONAL,
    965   IN     UINT32                                               ChannelAttributes,
    966   IN     VOID                                                 *HostAddress,
    967   IN OUT UINTN                                                *NumberOfBytes,
    968   OUT    EFI_PHYSICAL_ADDRESS                                 *DeviceAddress,
    969   OUT    VOID                                                 **Mapping
    970   )
    971 {
    972   EFI_STATUS            Status;
    973   BOOLEAN               Master;
    974   BOOLEAN               Read;
    975   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
    976   ISA_MAP_INFO          *IsaMapInfo;
    977   UINT8                 DmaMode;
    978   UINTN                 MaxNumberOfBytes;
    979   UINT32                BaseAddress;
    980   UINT16                Count;
    981   UINT8                 DmaMask;
    982   UINT8                 DmaClear;
    983   UINT8                 DmaChannelMode;
    984 
    985   if ((NULL == This) ||
    986       (NULL == HostAddress) ||
    987       (NULL == NumberOfBytes) ||
    988       (NULL == DeviceAddress) ||
    989       (NULL == Mapping)
    990       ) {
    991     return EFI_INVALID_PARAMETER;
    992   }
    993 
    994   //
    995   // Initialize the return values to their defaults
    996   //
    997   *Mapping = NULL;
    998 
    999   //
   1000   // Make sure the Operation parameter is valid
   1001   //
   1002   if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {
   1003     return EFI_INVALID_PARAMETER;
   1004   }
   1005 
   1006   if (ChannelNumber >= 8) {
   1007     return EFI_INVALID_PARAMETER;
   1008   }
   1009 
   1010   //
   1011   // See if this is a Slave DMA Operation
   1012   //
   1013   Master  = TRUE;
   1014   Read    = FALSE;
   1015   if (Operation == EfiIsaIoOperationSlaveRead) {
   1016     Operation = EfiIsaIoOperationBusMasterRead;
   1017     Master    = FALSE;
   1018     Read      = TRUE;
   1019   }
   1020 
   1021   if (Operation == EfiIsaIoOperationSlaveWrite) {
   1022     Operation = EfiIsaIoOperationBusMasterWrite;
   1023     Master    = FALSE;
   1024     Read      = FALSE;
   1025   }
   1026 
   1027   if (!Master) {
   1028     //
   1029     // Make sure that ChannelNumber is a valid channel number
   1030     // Channel 4 is used to cascade, so it is illegal.
   1031     //
   1032     if (ChannelNumber == 4 || ChannelNumber > 7) {
   1033       return EFI_INVALID_PARAMETER;
   1034     }
   1035     //
   1036     // This implementation only support COMPATIBLE DMA Transfers
   1037     //
   1038     if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {
   1039       return EFI_INVALID_PARAMETER;
   1040     }
   1041 
   1042     if ((ChannelAttributes &
   1043          (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
   1044           EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
   1045           EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {
   1046       return EFI_INVALID_PARAMETER;
   1047     }
   1048 
   1049     if (ChannelNumber < 4) {
   1050       //
   1051       // If this is Channel 0..3, then the width must be 8 bit
   1052       //
   1053       if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||
   1054           ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)
   1055           ) {
   1056         return EFI_INVALID_PARAMETER;
   1057       }
   1058     } else {
   1059       //
   1060       // If this is Channel 4..7, then the width must be 16 bit
   1061       //
   1062       if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||
   1063           ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {
   1064         return EFI_INVALID_PARAMETER;
   1065       }
   1066     }
   1067     //
   1068     // Either Demand Mode or Single Mode must be selected, but not both
   1069     //
   1070     if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
   1071       if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
   1072         return EFI_INVALID_PARAMETER;
   1073       }
   1074     } else {
   1075       if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {
   1076         return EFI_INVALID_PARAMETER;
   1077       }
   1078     }
   1079   }
   1080   //
   1081   // Map the HostAddress to a DeviceAddress.
   1082   //
   1083   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
   1084   if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {
   1085     //
   1086     // Common Buffer operations can not be remapped.  If the common buffer
   1087     // is above 16MB, then it is not possible to generate a mapping, so return
   1088     // an error.
   1089     //
   1090     if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
   1091       return EFI_UNSUPPORTED;
   1092     }
   1093     //
   1094     // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
   1095     // is called later.
   1096     //
   1097     IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
   1098     if (IsaMapInfo == NULL) {
   1099       *NumberOfBytes = 0;
   1100       return EFI_OUT_OF_RESOURCES;
   1101     }
   1102     //
   1103     // Return a pointer to the MAP_INFO structure in Mapping
   1104     //
   1105     *Mapping = IsaMapInfo;
   1106 
   1107     //
   1108     // Initialize the MAP_INFO structure
   1109     //
   1110     IsaMapInfo->Operation         = Operation;
   1111     IsaMapInfo->NumberOfBytes     = *NumberOfBytes;
   1112     IsaMapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (*NumberOfBytes);
   1113     IsaMapInfo->HostAddress       = PhysicalAddress;
   1114     IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;
   1115 
   1116     //
   1117     // Allocate a buffer below 16MB to map the transfer to.
   1118     //
   1119     Status = gBS->AllocatePages (
   1120                     AllocateMaxAddress,
   1121                     EfiBootServicesData,
   1122                     IsaMapInfo->NumberOfPages,
   1123                     &IsaMapInfo->MappedHostAddress
   1124                     );
   1125     if (EFI_ERROR (Status)) {
   1126       FreePool (IsaMapInfo);
   1127       *NumberOfBytes  = 0;
   1128       *Mapping        = NULL;
   1129       return Status;
   1130     }
   1131     //
   1132     // If this is a read operation from the DMA agents's point of view,
   1133     // then copy the contents of the real buffer into the mapped buffer
   1134     // so the DMA agent can read the contents of the real buffer.
   1135     //
   1136     if (Operation == EfiIsaIoOperationBusMasterRead) {
   1137       CopyMem (
   1138         (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
   1139         (VOID *) (UINTN) IsaMapInfo->HostAddress,
   1140         IsaMapInfo->NumberOfBytes
   1141         );
   1142     }
   1143     //
   1144     // The DeviceAddress is the address of the maped buffer below 16 MB
   1145     //
   1146     *DeviceAddress = IsaMapInfo->MappedHostAddress;
   1147   } else {
   1148     //
   1149     // The transfer is below 16 MB, so the DeviceAddress is simply the
   1150     // HostAddress
   1151     //
   1152     *DeviceAddress = PhysicalAddress;
   1153   }
   1154   //
   1155   // If this is a Bus Master operation then return
   1156   //
   1157   if (Master) {
   1158     return EFI_SUCCESS;
   1159   }
   1160   //
   1161   // Figure out what to program into the DMA Channel Mode Register
   1162   //
   1163   DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
   1164   if (Read) {
   1165     DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
   1166   } else {
   1167     DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
   1168   }
   1169 
   1170   if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {
   1171     DmaMode |= B_8237_DMA_CHMODE_AE;
   1172   }
   1173 
   1174   if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
   1175     DmaMode |= V_8237_DMA_CHMODE_DEMAND;
   1176   }
   1177 
   1178   if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
   1179     DmaMode |= V_8237_DMA_CHMODE_SINGLE;
   1180   }
   1181   //
   1182   // A Slave DMA transfer can not cross a 64K boundary.
   1183   // Compute *NumberOfBytes based on this restriction.
   1184   //
   1185   MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
   1186   if (*NumberOfBytes > MaxNumberOfBytes) {
   1187     *NumberOfBytes = MaxNumberOfBytes;
   1188   }
   1189   //
   1190   // Compute the values to program into the BaseAddress and Count registers
   1191   // of the Slave DMA controller
   1192   //
   1193   if (ChannelNumber < 4) {
   1194     BaseAddress = (UINT32) (*DeviceAddress);
   1195     Count       = (UINT16) (*NumberOfBytes - 1);
   1196   } else {
   1197     BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
   1198     Count       = (UINT16) ((*NumberOfBytes - 1) >> 1);
   1199   }
   1200   //
   1201   // Program the DMA Write Single Mask Register for ChannelNumber
   1202   // Clear the DMA Byte Pointer Register
   1203   //
   1204   if (ChannelNumber < 4) {
   1205     DmaMask         = R_8237_DMA_WRSMSK_CH0_3;
   1206     DmaClear        = R_8237_DMA_CBPR_CH0_3;
   1207     DmaChannelMode  = R_8237_DMA_CHMODE_CH0_3;
   1208   } else {
   1209     DmaMask         = R_8237_DMA_WRSMSK_CH4_7;
   1210     DmaClear        = R_8237_DMA_CBPR_CH4_7;
   1211     DmaChannelMode  = R_8237_DMA_CHMODE_CH4_7;
   1212   }
   1213 
   1214   Status = WritePort (
   1215              This,
   1216              DmaMask,
   1217              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
   1218              );
   1219   if (EFI_ERROR (Status)) {
   1220     return Status;
   1221   }
   1222 
   1223   Status = WritePort (
   1224              This,
   1225              DmaClear,
   1226              (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
   1227              );
   1228   if (EFI_ERROR (Status)) {
   1229     return Status;
   1230   }
   1231 
   1232   Status = WritePort (This, DmaChannelMode, DmaMode);
   1233   if (EFI_ERROR (Status)) {
   1234     return Status;
   1235   }
   1236 
   1237   Status = WriteDmaPort (
   1238              This,
   1239              mDmaRegisters[ChannelNumber].Address,
   1240              mDmaRegisters[ChannelNumber].Page,
   1241              mDmaRegisters[ChannelNumber].Count,
   1242              BaseAddress,
   1243              Count
   1244              );
   1245   if (EFI_ERROR (Status)) {
   1246     return Status;
   1247   }
   1248 
   1249   Status = WritePort (
   1250              This,
   1251              DmaMask,
   1252              (UINT8) (ChannelNumber & 0x03)
   1253              );
   1254   if (EFI_ERROR (Status)) {
   1255     return Status;
   1256   }
   1257 
   1258   return EFI_SUCCESS;
   1259 }
   1260 
   1261 /**
   1262   Maps a memory region for DMA
   1263 
   1264   @param This                    A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1265   @param Operation               Indicates the type of DMA (slave or bus master), and if
   1266                                  the DMA operation is going to read or write to system memory.
   1267   @param ChannelNumber           The slave channel number to use for this DMA operation.
   1268                                  If Operation and ChannelAttributes shows that this device
   1269                                  performs bus mastering DMA, then this field is ignored.
   1270                                  The legal range for this field is 0..7.
   1271   @param ChannelAttributes       The attributes of the DMA channel to use for this DMA operation
   1272   @param HostAddress             The system memory address to map to the device.
   1273   @param NumberOfBytes           On input the number of bytes to map.  On output the number
   1274                                  of bytes that were mapped.
   1275   @param DeviceAddress           The resulting map address for the bus master device to use
   1276                                  to access the hosts HostAddress.
   1277   @param Mapping                 A resulting value to pass to EFI_ISA_IO.Unmap().
   1278 
   1279   @retval EFI_SUCCESS            The range was mapped for the returned NumberOfBytes.
   1280   @retval EFI_INVALID_PARAMETER  The Operation or HostAddress is undefined.
   1281   @retval EFI_UNSUPPORTED        The HostAddress can not be mapped as a common buffer.
   1282   @retval EFI_DEVICE_ERROR       The system hardware could not map the requested address.
   1283   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
   1284 **/
   1285 EFI_STATUS
   1286 EFIAPI
   1287 IsaIoMap (
   1288   IN     EFI_ISA_IO_PROTOCOL            *This,
   1289   IN     EFI_ISA_IO_PROTOCOL_OPERATION  Operation,
   1290   IN     UINT8                          ChannelNumber  OPTIONAL,
   1291   IN     UINT32                         ChannelAttributes,
   1292   IN     VOID                           *HostAddress,
   1293   IN OUT UINTN                          *NumberOfBytes,
   1294   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
   1295   OUT    VOID                           **Mapping
   1296   )
   1297 {
   1298   //
   1299   // Check if DMA is supported.
   1300   //
   1301   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
   1302     return EFI_UNSUPPORTED;
   1303   }
   1304   //
   1305   // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
   1306   // ISA Bus Master.
   1307   //
   1308   // So we just return EFI_UNSUPPORTED for these functions.
   1309   //
   1310   if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {
   1311     return IsaIoMapOnlySupportSlaveReadWrite (
   1312              This,
   1313              Operation,
   1314              ChannelNumber,
   1315              ChannelAttributes,
   1316              HostAddress,
   1317              NumberOfBytes,
   1318              DeviceAddress,
   1319              Mapping
   1320              );
   1321 
   1322   } else {
   1323     return IsaIoMapFullSupport (
   1324              This,
   1325              Operation,
   1326              ChannelNumber,
   1327              ChannelAttributes,
   1328              HostAddress,
   1329              NumberOfBytes,
   1330              DeviceAddress,
   1331              Mapping
   1332              );
   1333   }
   1334 }
   1335 
   1336 /**
   1337   Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
   1338 
   1339   @param[in]  This               A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1340   @param[in]  Type               The type allocation to perform.
   1341   @param[in]  MemoryType         The type of memory to allocate.
   1342   @param[in]  Pages              The number of pages to allocate.
   1343   @param[out] HostAddress        A pointer to store the base address of the allocated range.
   1344   @param[in]  Attributes         The requested bit mask of attributes for the allocated range.
   1345 
   1346   @retval EFI_SUCCESS            The requested memory pages were allocated.
   1347   @retval EFI_INVALID_PARAMETER  Type is invalid or MemoryType is invalid or HostAddress is NULL
   1348   @retval EFI_UNSUPPORTED        Attributes is unsupported or the memory range specified
   1349                                  by HostAddress, Pages, and Type is not available for common buffer use.
   1350   @retval EFI_OUT_OF_RESOURCES   The memory pages could not be allocated.
   1351 **/
   1352 EFI_STATUS
   1353 EFIAPI
   1354 IsaIoAllocateBuffer (
   1355   IN  EFI_ISA_IO_PROTOCOL  *This,
   1356   IN  EFI_ALLOCATE_TYPE    Type,
   1357   IN  EFI_MEMORY_TYPE      MemoryType,
   1358   IN  UINTN                Pages,
   1359   OUT VOID                 **HostAddress,
   1360   IN  UINT64               Attributes
   1361   )
   1362 {
   1363   EFI_STATUS            Status;
   1364   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
   1365 
   1366   //
   1367   // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
   1368   // ISA Bus Master.
   1369   // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
   1370   //
   1371   if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
   1372       ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
   1373     return EFI_UNSUPPORTED;
   1374   }
   1375 
   1376   if (HostAddress == NULL) {
   1377     return EFI_INVALID_PARAMETER;
   1378   }
   1379 
   1380   if ((UINT32)Type >= MaxAllocateType) {
   1381     return EFI_INVALID_PARAMETER;
   1382   }
   1383   //
   1384   // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
   1385   //
   1386   if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
   1387     return EFI_INVALID_PARAMETER;
   1388   }
   1389 
   1390   if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {
   1391     return EFI_UNSUPPORTED;
   1392   }
   1393 
   1394   PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (ISA_MAX_MEMORY_ADDRESS - 1);
   1395   if (Type == AllocateAddress) {
   1396     if ((UINTN) (*HostAddress) >= ISA_MAX_MEMORY_ADDRESS) {
   1397       return EFI_UNSUPPORTED;
   1398     } else {
   1399       PhysicalAddress = (UINTN) (*HostAddress);
   1400     }
   1401   }
   1402 
   1403   if (Type == AllocateAnyPages) {
   1404     Type = AllocateMaxAddress;
   1405   }
   1406 
   1407   Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
   1408   if (EFI_ERROR (Status)) {
   1409     REPORT_STATUS_CODE (
   1410       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1411       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
   1412       );
   1413     return Status;
   1414   }
   1415 
   1416   *HostAddress = (VOID *) (UINTN) PhysicalAddress;
   1417   return Status;
   1418 }
   1419 
   1420 /**
   1421   Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
   1422 
   1423   @param[in] This                A pointer to the EFI_ISA_IO_PROTOCOL instance.
   1424   @param[in] Pages               The number of pages to free.
   1425   @param[in] HostAddress         The base address of the allocated range.
   1426 
   1427   @retval EFI_SUCCESS            The requested memory pages were freed.
   1428   @retval EFI_INVALID_PARAMETER  The memory was not allocated with EFI_ISA_IO.AllocateBufer().
   1429 **/
   1430 EFI_STATUS
   1431 EFIAPI
   1432 IsaIoFreeBuffer (
   1433   IN EFI_ISA_IO_PROTOCOL  *This,
   1434   IN UINTN                Pages,
   1435   IN VOID                 *HostAddress
   1436   )
   1437 {
   1438   EFI_STATUS  Status;
   1439 
   1440   //
   1441   // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
   1442   // ISA Bus Master.
   1443   // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
   1444   //
   1445   if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
   1446       ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
   1447     return EFI_UNSUPPORTED;
   1448   }
   1449 
   1450   Status = gBS->FreePages (
   1451                   (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
   1452                   Pages
   1453                   );
   1454   if (EFI_ERROR (Status)) {
   1455     REPORT_STATUS_CODE (
   1456       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1457       EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
   1458       );
   1459   }
   1460 
   1461   return Status;
   1462 }
   1463 
   1464