isaio.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 778 行 · 第 1/2 页

C
778
字号

  IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);

  //
  // Initialize the return values to their defaults
  //
  *Mapping = NULL;

  //
  // Make sure the Operation parameter is valid
  //
  if (Operation < 0 || Operation >= EfiIsaIoOperationMaximum) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // See if this is a Slave DMA Operation
  //
  Master  = TRUE;
  Read    = FALSE;
  if (Operation == EfiIsaIoOperationSlaveRead) {
    Operation = EfiIsaIoOperationBusMasterRead;
    Master    = FALSE;
    Read      = TRUE;
  }

  if (Operation == EfiIsaIoOperationSlaveWrite) {
    Operation = EfiIsaIoOperationBusMasterWrite;
    Master    = FALSE;
    Read      = FALSE;
  }

  if (!Master) {
    //
    // Make sure that ChannelNumber is a valid channel number
    // Channel 4 is used to cascade, so it is illegal.
    //
    if (ChannelNumber == 4 || ChannelNumber > 7) {
      return EFI_INVALID_PARAMETER;
    }
    //
    // This implementation only support COMPATIBLE DMA Transfers
    //
    if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE)) {
      return EFI_INVALID_PARAMETER;
    }

    if (ChannelAttributes &
       (
         EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
         EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
         EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
       )
       ) {
      return EFI_INVALID_PARAMETER;
    }

    if (ChannelNumber < 4) {
      //
      // If this is Channel 0..3, then the width must be 8 bit
      //
      if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) ||
          (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16)
          ) {
        return EFI_INVALID_PARAMETER;
      }
    } else {
      //
      // If this is Channel 4..7, then the width must be 16 bit
      //
      if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) ||
          (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16))
          ) {
        return EFI_INVALID_PARAMETER;
      }
    }
    //
    // Either Demand Mode or Single Mode must be selected, but not both
    //
    if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) {
      if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) {
        return EFI_INVALID_PARAMETER;
      }
    } else {
      if (!(ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE)) {
        return EFI_INVALID_PARAMETER;
      }
    }
  }
  //
  // Map the HostAddress to a DeviceAddress.
  //
  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
  if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {
    //
    // Common Buffer operations can not be remapped.  If the common buffer
    // is above 16MB, then it is not possible to generate a mapping, so return
    // an error.
    //
    if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
      return EFI_UNSUPPORTED;
    }
    //
    // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
    // is called later.
    //
    IsaMapInfo = EfiLibAllocatePool (sizeof (ISA_MAP_INFO));
    if (IsaMapInfo == NULL) {
      *NumberOfBytes = 0;
      return EFI_OUT_OF_RESOURCES;
    }
    //
    // Return a pointer to the MAP_INFO structure in Mapping
    //
    *Mapping = IsaMapInfo;

    //
    // Initialize the MAP_INFO structure
    //
    IsaMapInfo->Operation         = Operation;
    IsaMapInfo->NumberOfBytes     = *NumberOfBytes;
    IsaMapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (*NumberOfBytes);
    IsaMapInfo->HostAddress       = PhysicalAddress;
    IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;

    //
    // Allocate a buffer below 4GB to map the transfer to.
    //
    Status = gBS->AllocatePages (
                    AllocateMaxAddress,
                    EfiBootServicesData,
                    IsaMapInfo->NumberOfPages,
                    &IsaMapInfo->MappedHostAddress
                    );
    if (EFI_ERROR (Status)) {
      gBS->FreePool (IsaMapInfo);
      *NumberOfBytes  = 0;
      *Mapping        = NULL;
      return Status;
    }
    //
    // If this is a read operation from the DMA agents's point of view,
    // then copy the contents of the real buffer into the mapped buffer
    // so the DMA agent can read the contents of the real buffer.
    //
    if (Operation == EfiIsaIoOperationBusMasterRead) {
      EfiCopyMem (
        (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
        (VOID *) (UINTN) IsaMapInfo->HostAddress,
        IsaMapInfo->NumberOfBytes
        );
    }
    //
    // The DeviceAddress is the address of the maped buffer below 16 MB
    //
    *DeviceAddress = IsaMapInfo->MappedHostAddress;
  } else {
    //
    // The transfer is below 16 MB, so the DeviceAddress is simply the
    // HostAddress
    //
    *DeviceAddress = PhysicalAddress;
  }
  //
  // If this is a Bus Master operation then return
  //
  if (Master) {
    return EFI_SUCCESS;
  }
  //
  // Figure out what to program into the DMA Channel Mode Register
  //
  DmaMode = (UINT8) (DMA_MODE_INCREMENT | (ChannelNumber & 0x03));
  if (Read) {
    DmaMode |= DMA_MODE_READ;
  } else {
    DmaMode |= DMA_MODE_WRITE;
  }

  if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) {
    DmaMode |= DMA_MODE_AUTO_INITIALIZE;
  }

  if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) {
    DmaMode |= DMA_MODE_DEMAND;
  }

  if (ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) {
    DmaMode |= DMA_MODE_SINGLE;
  }
  //
  // A Slave DMA transfer can not cross a 64K boundary.
  // Compute *NumberOfBytes based on this restriction.
  //
  MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
  if (*NumberOfBytes > MaxNumberOfBytes) {
    *NumberOfBytes = MaxNumberOfBytes;
  }
  //
  // Compute the values to program into the BaseAddress and Count registers
  // of the Slave DMA controller
  //
  if (ChannelNumber < 4) {
    BaseAddress = (UINT32) (*DeviceAddress);
    Count       = (UINT16) (*NumberOfBytes - 1);
  } else {
    BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
    Count       = (UINT16) ((*NumberOfBytes - 1) >> 1);
  }
  //
  // Program the DMA Write Single Mask Register for ChannelNumber
  // Clear the DMA Byte Pointer Register
  //
  if (ChannelNumber < 4) {
    DmaMask         = DMA_SINGLE_MASK_0_3;
    DmaClear        = DMA_CLEAR_0_3;
    DmaChannelMode  = DMA_MODE_0_3;
  } else {
    DmaMask         = DMA_SINGLE_MASK_4_7;
    DmaClear        = DMA_CLEAR_4_7;
    DmaChannelMode  = DMA_MODE_4_7;
  }

  Status = WritePort (
             This,
             DmaMask,
             (UINT8) (DMA_CHANNEL_MASK_SELECT | (ChannelNumber & 0x03))
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = WritePort (
             This,
             DmaClear,
             (UINT8) (DMA_CHANNEL_MASK_SELECT | (ChannelNumber & 0x03))
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = WritePort (This, DmaChannelMode, DmaMode);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = WriteDmaPort (
             This,
             DmaRegisters[ChannelNumber].Address,
             DmaRegisters[ChannelNumber].Page,
             DmaRegisters[ChannelNumber].Count,
             BaseAddress,
             Count
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = WritePort (
             This,
             DmaMask,
             (UINT8) (ChannelNumber & 0x03)
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
IsaIoAllocateBuffer (
  IN  EFI_INTERFACE_DEFINITION_FOR_ISA_IO  *This,
  IN  EFI_ALLOCATE_TYPE                    Type,
  IN  EFI_MEMORY_TYPE                      MemoryType,
  IN  UINTN                                Pages,
  OUT VOID                                 **HostAddress,
  IN  UINT64                               Attributes
  )
/*++

Routine Description:

  Allocates a common buffer for DMA

Arguments:

  This                  - A pointer to the EFI_ISA_IO_PROTOCOL instance.
  Type                  - The type allocation to perform.
  MemoryType            - The type of memory to allocate.
  Pages                 - The number of pages to allocate.
  HostAddress           - A pointer to store the base address of the allocated range.
  Attributes            - The requested bit mask of attributes for the allocated range.

Returns:

  EFI_SUCCESS           - The requested memory pages were allocated.
  EFI_INVALID_PARAMETER - Type is invalid or MemoryType is invalid or HostAddress is NULL
  EFI_UNSUPPORTED       - Attributes is unsupported or the memory range specified 
                          by HostAddress, Pages, and Type is not available for common buffer use.
  EFI_OUT_OF_RESOURCES  - The memory pages could not be allocated.

--*/
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PhysicalAddress;

  if (HostAddress == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Type < AllocateAnyPages || Type >= MaxAllocateType) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
  //
  if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
    return EFI_INVALID_PARAMETER;
  }

  if (Attributes &~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) {
    return EFI_UNSUPPORTED;
  }

  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (ISA_MAX_MEMORY_ADDRESS - 1);
  if (Type == AllocateAddress) {
    if ((UINTN) (*HostAddress) >= ISA_MAX_MEMORY_ADDRESS) {
      return EFI_UNSUPPORTED;
    } else {
      PhysicalAddress = (UINTN) (*HostAddress);
    }
  }

  if (Type == AllocateAnyPages) {
    Type = AllocateMaxAddress;
  }

  Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);
    return Status;
  }

  *HostAddress = (VOID *) (UINTN) PhysicalAddress;
  return Status;
}

EFI_STATUS
EFIAPI
IsaIoFreeBuffer (
  IN EFI_INTERFACE_DEFINITION_FOR_ISA_IO  *This,
  IN UINTN                                Pages,
  IN VOID                                 *HostAddress
  )
/*++

Routine Description:

  Frees a common buffer 

Arguments:

  This                  - A pointer to the EFI_ISA_IO_PROTOCOL instance.
  Pages                 - The number of pages to free.
  HostAddress           - The base address of the allocated range.

Returns:

  EFI_SUCCESS           - The requested memory pages were freed.
  EFI_INVALID_PARAMETER - The memory was not allocated with EFI_ISA_IO.AllocateBufer().

--*/
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PhysicalAddress;

  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
  Status = gBS->FreePages (
                  PhysicalAddress,
                  Pages
                  );
  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?