2 The implementation for EFI_ISA_IO_PROTOCOL.
4 Copyright (c) 2006 - 2009, Intel Corporation.<BR>
5 All rights reserved. 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
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.
15 #include "InternalIsaIo.h"
20 EFI_ISA_IO_PROTOCOL mIsaIoInterface
= {
40 EFI_ISA_DMA_REGISTERS mDmaRegisters
[8] = {
65 }, // Channel 4 is invalid
84 report a error Status code
86 @param Code The error status code.
88 @return EFI_SUCCESS Success to report status code.
91 ReportErrorStatusCode (
92 EFI_STATUS_CODE_VALUE Code
95 return REPORT_STATUS_CODE (
96 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
102 Initializes an ISA I/O Instance
104 @param[in] IsaIoDevice The iso device to be initialized.
105 @param[in] IsaDeviceResourceList The resource list.
110 InitializeIsaIoInstance (
111 IN ISA_IO_DEVICE
*IsaIoDevice
,
112 IN EFI_ISA_ACPI_RESOURCE_LIST
*IsaDeviceResourceList
116 // Use the ISA IO Protocol structure template to initialize the ISA IO instance
121 sizeof (EFI_ISA_IO_PROTOCOL
)
124 IsaIoDevice
->IsaIo
.ResourceList
= IsaDeviceResourceList
;
128 Performs an ISA I/O Read Cycle
130 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
131 @param[in] Width Specifies the width of the I/O operation.
132 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
133 @param[in] Count The number of I/O operations to perform.
134 @param[out] Buffer The destination buffer to store the results
136 @retval EFI_SUCCESS The data was read from the device sucessfully.
137 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
138 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
139 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
144 IN EFI_ISA_IO_PROTOCOL
*This
,
145 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
152 ISA_IO_DEVICE
*IsaIoDevice
;
154 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
157 // Verify Isa IO Access
159 Status
= IsaIoVerifyAccess (
166 if (EFI_ERROR (Status
)) {
170 Status
= IsaIoDevice
->PciIo
->Io
.Read (
172 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
173 EFI_PCI_IO_PASS_THROUGH_BAR
,
179 if (EFI_ERROR (Status
)) {
180 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
187 Performs an ISA I/O Write Cycle
189 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
190 @param[in] Width Specifies the width of the I/O operation.
191 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
192 @param[in] Count The number of I/O operations to perform.
193 @param[in] Buffer The source buffer to write data from
195 @retval EFI_SUCCESS The data was writen to the device sucessfully.
196 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
197 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
198 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
203 IN EFI_ISA_IO_PROTOCOL
*This
,
204 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
211 ISA_IO_DEVICE
*IsaIoDevice
;
213 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
216 // Verify Isa IO Access
218 Status
= IsaIoVerifyAccess (
225 if (EFI_ERROR (Status
)) {
229 Status
= IsaIoDevice
->PciIo
->Io
.Write (
231 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
232 EFI_PCI_IO_PASS_THROUGH_BAR
,
238 if (EFI_ERROR (Status
)) {
239 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
246 Writes an 8-bit I/O Port
248 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
249 @param[in] Offset The offset in ISA IO space to start the IO operation.
250 @param[in] Value The data to write port.
252 @retval EFI_SUCCESS Success.
253 @retval EFI_INVALID_PARAMETER Parameter is invalid.
254 @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
255 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
259 IN EFI_ISA_IO_PROTOCOL
*This
,
265 ISA_IO_DEVICE
*IsaIoDevice
;
267 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
269 Status
= IsaIoDevice
->PciIo
->Io
.Write (
272 EFI_PCI_IO_PASS_THROUGH_BAR
,
277 if (EFI_ERROR (Status
)) {
278 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
288 Writes I/O operation base address and count number to a 8 bit I/O Port.
290 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
291 @param[in] AddrOffset The address' offset.
292 @param[in] PageOffset The page's offest.
293 @param[in] CountOffset The count's offset.
294 @param[in] BaseAddress The base address.
295 @param[in] Count The number of I/O operations to perform.
297 @retval EFI_SUCCESS Success.
298 @retval EFI_INVALID_PARAMETER Parameter is invalid.
299 @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
300 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
304 IN EFI_ISA_IO_PROTOCOL
*This
,
305 IN UINT32 AddrOffset
,
306 IN UINT32 PageOffset
,
307 IN UINT32 CountOffset
,
308 IN UINT32 BaseAddress
,
314 Status
= WritePort (This
, AddrOffset
, (UINT8
) (BaseAddress
& 0xff));
315 if (EFI_ERROR (Status
)) {
319 Status
= WritePort (This
, AddrOffset
, (UINT8
) ((BaseAddress
>> 8) & 0xff));
320 if (EFI_ERROR (Status
)) {
324 Status
= WritePort (This
, PageOffset
, (UINT8
) ((BaseAddress
>> 16) & 0xff));
325 if (EFI_ERROR (Status
)) {
329 Status
= WritePort (This
, CountOffset
, (UINT8
) (Count
& 0xff));
330 if (EFI_ERROR (Status
)) {
334 Status
= WritePort (This
, CountOffset
, (UINT8
) ((Count
>> 8) & 0xff));
339 Unmaps a memory region for DMA
341 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
342 @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
344 @retval EFI_SUCCESS The range was unmapped.
345 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
350 IN EFI_ISA_IO_PROTOCOL
*This
,
354 ISA_MAP_INFO
*IsaMapInfo
;
357 // Unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
359 if (!FeaturePcdGet (PcdIsaBusSupportDma
)) {
360 return EFI_UNSUPPORTED
;
364 // See if the Map() operation associated with this Unmap() required a mapping
365 // buffer.If a mapping buffer was not required, then this function simply
366 // returns EFI_SUCCESS.
368 if (Mapping
!= NULL
) {
370 // Get the MAP_INFO structure from Mapping
372 IsaMapInfo
= (ISA_MAP_INFO
*) Mapping
;
375 // If this is a write operation from the Agent's point of view,
376 // then copy the contents of the mapped buffer into the real buffer
377 // so the processor can read the contents of the real buffer.
379 if (IsaMapInfo
->Operation
== EfiIsaIoOperationBusMasterWrite
) {
381 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
382 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
383 IsaMapInfo
->NumberOfBytes
387 // Free the mapped buffer and the MAP_INFO structure.
389 gBS
->FreePages (IsaMapInfo
->MappedHostAddress
, IsaMapInfo
->NumberOfPages
);
390 FreePool (IsaMapInfo
);
397 Flushes any posted write data to the system memory.
399 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
401 @retval EFI_SUCCESS The buffers were flushed.
402 @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
407 IN EFI_ISA_IO_PROTOCOL
*This
411 ISA_IO_DEVICE
*IsaIoDevice
;
413 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
415 Status
= IsaIoDevice
->PciIo
->Flush (IsaIoDevice
->PciIo
);
417 if (EFI_ERROR (Status
)) {
418 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
425 Verifies access to an ISA device
427 @param[in] IsaIoDevice The ISA device to be verified.
428 @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
429 @param[in] Width The width of the memory operation.
430 @param[in] Count The number of memory operations to perform.
431 @param[in] Offset The offset in ISA memory space to start the memory operation.
433 @retval EFI_SUCCESS Verify success.
434 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
435 @retval EFI_UNSUPPORTED The device ont support the access type.
439 IN ISA_IO_DEVICE
*IsaIoDevice
,
440 IN ISA_ACCESS_TYPE Type
,
441 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
446 EFI_ISA_ACPI_RESOURCE
*Item
;
449 if (Width
< EfiIsaIoWidthUint8
||
450 Width
>= EfiIsaIoWidthMaximum
||
451 Width
== EfiIsaIoWidthReserved
||
452 Width
== EfiIsaIoWidthFifoReserved
||
453 Width
== EfiIsaIoWidthFillReserved
455 return EFI_INVALID_PARAMETER
;
459 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
460 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
462 if (Width
>= EfiIsaIoWidthFifoUint8
&& Width
< EfiIsaIoWidthFifoReserved
) {
466 Width
= (EFI_ISA_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
468 Status
= EFI_UNSUPPORTED
;
469 Item
= IsaIoDevice
->IsaIo
.ResourceList
->ResourceItem
;
470 while (Item
->Type
!= EfiIsaAcpiResourceEndOfList
) {
471 if ((Type
== IsaAccessTypeMem
&& Item
->Type
== EfiIsaAcpiResourceMemory
) ||
472 (Type
== IsaAccessTypeIo
&& Item
->Type
== EfiIsaAcpiResourceIo
)) {
473 if (Offset
>= Item
->StartRange
&& (Offset
+ Count
* (UINT32
)(1 << Width
)) - 1 <= Item
->EndRange
) {
477 if (Offset
>= Item
->StartRange
&& Offset
<= Item
->EndRange
) {
478 Status
= EFI_INVALID_PARAMETER
;
489 Performs an ISA Memory Read Cycle
491 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
492 @param[in] Width Specifies the width of the memory operation.
493 @param[in] Offset The offset in ISA memory space to start the memory operation.
494 @param[in] Count The number of memory operations to perform.
495 @param[out] Buffer The destination buffer to store the results
497 @retval EFI_SUCCESS The data was read from the device successfully.
498 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
499 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
500 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
505 IN EFI_ISA_IO_PROTOCOL
*This
,
506 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
513 ISA_IO_DEVICE
*IsaIoDevice
;
516 // Set Feature Flag PcdIsaBusSupportIsaMemory to FALSE to disable support for
517 // ISA bus memory read/write operations.
519 if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory
)) {
520 return EFI_UNSUPPORTED
;
523 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
526 // Verify the Isa Io Access
528 Status
= IsaIoVerifyAccess (
535 if (EFI_ERROR (Status
)) {
539 Status
= IsaIoDevice
->PciIo
->Mem
.Read (
541 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
542 EFI_PCI_IO_PASS_THROUGH_BAR
,
548 if (EFI_ERROR (Status
)) {
549 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
556 Performs an ISA Memory Write Cycle
558 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
559 @param[in] Width Specifies the width of the memory operation.
560 @param[in] Offset The offset in ISA memory space to start the memory operation.
561 @param[in] Count The number of memory operations to perform.
562 @param[in] Buffer The source buffer to write data from
564 @retval EFI_SUCCESS The data was written to the device sucessfully.
565 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
566 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
567 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
572 IN EFI_ISA_IO_PROTOCOL
*This
,
573 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
580 ISA_IO_DEVICE
*IsaIoDevice
;
583 // Set Feature Flag PcdIsaBusSupportIsaMemory to FALSE to disable support for
584 // ISA bus memory read/write operations.
586 if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory
)) {
587 return EFI_UNSUPPORTED
;
590 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
593 // Verify Isa IO Access
595 Status
= IsaIoVerifyAccess (
602 if (EFI_ERROR (Status
)) {
606 Status
= IsaIoDevice
->PciIo
->Mem
.Write (
608 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
609 EFI_PCI_IO_PASS_THROUGH_BAR
,
615 if (EFI_ERROR (Status
)) {
616 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
623 Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
625 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
626 @param[in] Width Specifies the width of the memory copy operation.
627 @param[out] DestOffset The offset of the destination
628 @param[in] SrcOffset The offset of the source
629 @param[in] Count The number of memory copy operations to perform
631 @retval EFI_SUCCESS The data was copied sucessfully.
632 @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
633 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
634 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
639 IN EFI_ISA_IO_PROTOCOL
*This
,
640 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
641 IN UINT32 DestOffset
,
647 ISA_IO_DEVICE
*IsaIoDevice
;
650 // Set Feature Flag PcdIsaBusSupportIsaMemory to FALSE to disable support for
651 // ISA bus memory read/write operations.
653 if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory
)) {
654 return EFI_UNSUPPORTED
;
657 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
660 // Verify Isa IO Access for destination and source
662 Status
= IsaIoVerifyAccess (
669 if (EFI_ERROR (Status
)) {
673 Status
= IsaIoVerifyAccess (
680 if (EFI_ERROR (Status
)) {
684 Status
= IsaIoDevice
->PciIo
->CopyMem (
686 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
687 EFI_PCI_IO_PASS_THROUGH_BAR
,
689 EFI_PCI_IO_PASS_THROUGH_BAR
,
694 if (EFI_ERROR (Status
)) {
695 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
702 Maps a memory region for DMA, note this implementation
703 only supports slave read/write operation to save code size.
705 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
706 @param Operation Indicates the type of DMA (slave or bus master), and if
707 the DMA operation is going to read or write to system memory.
708 @param ChannelNumber The slave channel number to use for this DMA operation.
709 If Operation and ChannelAttributes shows that this device
710 performs bus mastering DMA, then this field is ignored.
711 The legal range for this field is 0..7.
712 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
713 @param HostAddress The system memory address to map to the device.
714 @param NumberOfBytes On input the number of bytes to map. On output the number
715 of bytes that were mapped.
716 @param DeviceAddress The resulting map address for the bus master device to use
717 to access the hosts HostAddress.
718 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
720 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
721 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
722 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
723 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
724 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
727 IsaIoMapOnlySupportSlaveReadWrite (
728 IN EFI_ISA_IO_PROTOCOL
*This
,
729 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
730 IN UINT8 ChannelNumber OPTIONAL
,
731 IN UINT32 ChannelAttributes
,
732 IN VOID
*HostAddress
,
733 IN OUT UINTN
*NumberOfBytes
,
734 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
739 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
740 ISA_MAP_INFO
*IsaMapInfo
;
742 UINTN MaxNumberOfBytes
;
747 UINT8 DmaChannelMode
;
749 if ((NULL
== This
) ||
750 (NULL
== HostAddress
) ||
751 (NULL
== NumberOfBytes
) ||
752 (NULL
== DeviceAddress
) ||
755 return EFI_INVALID_PARAMETER
;
759 // Initialize the return values to their defaults
764 // Make sure the Operation parameter is valid.
765 // Light IsaIo only supports two operations.
767 if (!(Operation
== EfiIsaIoOperationSlaveRead
||
768 Operation
== EfiIsaIoOperationSlaveWrite
)) {
769 return EFI_INVALID_PARAMETER
;
772 if (ChannelNumber
>= 4) {
774 // The Light IsaIo doesn't support channelNumber larger than 4.
776 return EFI_INVALID_PARAMETER
;
780 // Map the HostAddress to a DeviceAddress.
782 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
783 if ((PhysicalAddress
+ *NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
785 // Common Buffer operations can not be remapped. If the common buffer
786 // is above 16MB, then it is not possible to generate a mapping, so return
789 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
790 return EFI_UNSUPPORTED
;
793 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
796 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
797 if (IsaMapInfo
== NULL
) {
799 return EFI_OUT_OF_RESOURCES
;
802 // Return a pointer to the MAP_INFO structure in Mapping
804 *Mapping
= IsaMapInfo
;
807 // Initialize the MAP_INFO structure
809 IsaMapInfo
->Operation
= Operation
;
810 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
811 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
812 IsaMapInfo
->HostAddress
= PhysicalAddress
;
813 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
816 // Allocate a buffer below 16MB to map the transfer to.
818 Status
= gBS
->AllocatePages (
821 IsaMapInfo
->NumberOfPages
,
822 &IsaMapInfo
->MappedHostAddress
824 if (EFI_ERROR (Status
)) {
825 FreePool (IsaMapInfo
);
831 // If this is a read operation from the DMA agents's point of view,
832 // then copy the contents of the real buffer into the mapped buffer
833 // so the DMA agent can read the contents of the real buffer.
835 if (Operation
== EfiIsaIoOperationSlaveRead
) {
837 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
838 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
839 IsaMapInfo
->NumberOfBytes
843 // The DeviceAddress is the address of the maped buffer below 16 MB
845 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
848 // The transfer is below 16 MB, so the DeviceAddress is simply the
851 *DeviceAddress
= PhysicalAddress
;
855 // Figure out what to program into the DMA Channel Mode Register
857 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
858 if (Operation
== EfiIsaIoOperationSlaveRead
) {
859 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
861 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
864 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
866 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
869 // A Slave DMA transfer can not cross a 64K boundary.
870 // Compute *NumberOfBytes based on this restriction.
872 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
873 if (*NumberOfBytes
> MaxNumberOfBytes
) {
874 *NumberOfBytes
= MaxNumberOfBytes
;
877 // Compute the values to program into the BaseAddress and Count registers
878 // of the Slave DMA controller
880 BaseAddress
= (UINT32
) (*DeviceAddress
);
881 Count
= (UINT16
) (*NumberOfBytes
- 1);
883 // Program the DMA Write Single Mask Register for ChannelNumber
884 // Clear the DMA Byte Pointer Register
886 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
887 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
888 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
893 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
895 if (EFI_ERROR (Status
)) {
902 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
904 if (EFI_ERROR (Status
)) {
908 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
909 if (EFI_ERROR (Status
)) {
913 Status
= WriteDmaPort (
915 mDmaRegisters
[ChannelNumber
].Address
,
916 mDmaRegisters
[ChannelNumber
].Page
,
917 mDmaRegisters
[ChannelNumber
].Count
,
921 if (EFI_ERROR (Status
)) {
928 (UINT8
) (ChannelNumber
& 0x03)
930 if (EFI_ERROR (Status
)) {
938 Maps a memory region for DMA. This implementation implement the
939 the full mapping support.
941 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
942 @param Operation Indicates the type of DMA (slave or bus master), and if
943 the DMA operation is going to read or write to system memory.
944 @param ChannelNumber The slave channel number to use for this DMA operation.
945 If Operation and ChannelAttributes shows that this device
946 performs bus mastering DMA, then this field is ignored.
947 The legal range for this field is 0..7.
948 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
949 @param HostAddress The system memory address to map to the device.
950 @param NumberOfBytes On input the number of bytes to map. On output the number
951 of bytes that were mapped.
952 @param DeviceAddress The resulting map address for the bus master device to use
953 to access the hosts HostAddress.
954 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
956 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
957 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
958 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
959 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
960 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
963 IsaIoMapFullSupport (
964 IN EFI_ISA_IO_PROTOCOL
*This
,
965 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
966 IN UINT8 ChannelNumber OPTIONAL
,
967 IN UINT32 ChannelAttributes
,
968 IN VOID
*HostAddress
,
969 IN OUT UINTN
*NumberOfBytes
,
970 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
977 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
978 ISA_MAP_INFO
*IsaMapInfo
;
980 UINTN MaxNumberOfBytes
;
985 UINT8 DmaChannelMode
;
987 if ((NULL
== This
) ||
988 (NULL
== HostAddress
) ||
989 (NULL
== NumberOfBytes
) ||
990 (NULL
== DeviceAddress
) ||
993 return EFI_INVALID_PARAMETER
;
997 // Initialize the return values to their defaults
1002 // Make sure the Operation parameter is valid
1004 if (Operation
< 0 || Operation
>= EfiIsaIoOperationMaximum
) {
1005 return EFI_INVALID_PARAMETER
;
1008 if (ChannelNumber
>= 8) {
1009 return EFI_INVALID_PARAMETER
;
1013 // See if this is a Slave DMA Operation
1017 if (Operation
== EfiIsaIoOperationSlaveRead
) {
1018 Operation
= EfiIsaIoOperationBusMasterRead
;
1023 if (Operation
== EfiIsaIoOperationSlaveWrite
) {
1024 Operation
= EfiIsaIoOperationBusMasterWrite
;
1031 // Make sure that ChannelNumber is a valid channel number
1032 // Channel 4 is used to cascade, so it is illegal.
1034 if (ChannelNumber
== 4 || ChannelNumber
> 7) {
1035 return EFI_INVALID_PARAMETER
;
1038 // This implementation only support COMPATIBLE DMA Transfers
1040 if (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE
)) {
1041 return EFI_INVALID_PARAMETER
;
1044 if (ChannelAttributes
&
1046 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A
|
1047 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B
|
1048 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
1051 return EFI_INVALID_PARAMETER
;
1054 if (ChannelNumber
< 4) {
1056 // If this is Channel 0..3, then the width must be 8 bit
1058 if (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) ||
1059 (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
)
1061 return EFI_INVALID_PARAMETER
;
1065 // If this is Channel 4..7, then the width must be 16 bit
1067 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) ||
1068 (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
))
1070 return EFI_INVALID_PARAMETER
;
1074 // Either Demand Mode or Single Mode must be selected, but not both
1076 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) {
1077 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) {
1078 return EFI_INVALID_PARAMETER
;
1081 if (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
)) {
1082 return EFI_INVALID_PARAMETER
;
1087 // Map the HostAddress to a DeviceAddress.
1089 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
1090 if ((PhysicalAddress
+*NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
1092 // Common Buffer operations can not be remapped. If the common buffer
1093 // is above 16MB, then it is not possible to generate a mapping, so return
1096 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
1097 return EFI_UNSUPPORTED
;
1100 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1103 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
1104 if (IsaMapInfo
== NULL
) {
1106 return EFI_OUT_OF_RESOURCES
;
1109 // Return a pointer to the MAP_INFO structure in Mapping
1111 *Mapping
= IsaMapInfo
;
1114 // Initialize the MAP_INFO structure
1116 IsaMapInfo
->Operation
= Operation
;
1117 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
1118 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
1119 IsaMapInfo
->HostAddress
= PhysicalAddress
;
1120 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
1123 // Allocate a buffer below 16MB to map the transfer to.
1125 Status
= gBS
->AllocatePages (
1127 EfiBootServicesData
,
1128 IsaMapInfo
->NumberOfPages
,
1129 &IsaMapInfo
->MappedHostAddress
1131 if (EFI_ERROR (Status
)) {
1132 FreePool (IsaMapInfo
);
1138 // If this is a read operation from the DMA agents's point of view,
1139 // then copy the contents of the real buffer into the mapped buffer
1140 // so the DMA agent can read the contents of the real buffer.
1142 if (Operation
== EfiIsaIoOperationBusMasterRead
) {
1144 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
1145 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
1146 IsaMapInfo
->NumberOfBytes
1150 // The DeviceAddress is the address of the maped buffer below 16 MB
1152 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
1155 // The transfer is below 16 MB, so the DeviceAddress is simply the
1158 *DeviceAddress
= PhysicalAddress
;
1161 // If this is a Bus Master operation then return
1167 // Figure out what to program into the DMA Channel Mode Register
1169 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
1171 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
1173 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
1176 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE
) {
1177 DmaMode
|= B_8237_DMA_CHMODE_AE
;
1180 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) {
1181 DmaMode
|= V_8237_DMA_CHMODE_DEMAND
;
1184 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) {
1185 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
1188 // A Slave DMA transfer can not cross a 64K boundary.
1189 // Compute *NumberOfBytes based on this restriction.
1191 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
1192 if (*NumberOfBytes
> MaxNumberOfBytes
) {
1193 *NumberOfBytes
= MaxNumberOfBytes
;
1196 // Compute the values to program into the BaseAddress and Count registers
1197 // of the Slave DMA controller
1199 if (ChannelNumber
< 4) {
1200 BaseAddress
= (UINT32
) (*DeviceAddress
);
1201 Count
= (UINT16
) (*NumberOfBytes
- 1);
1203 BaseAddress
= (UINT32
) (((UINT32
) (*DeviceAddress
) & 0xff0000) | (((UINT32
) (*DeviceAddress
) & 0xffff) >> 1));
1204 Count
= (UINT16
) ((*NumberOfBytes
- 1) >> 1);
1207 // Program the DMA Write Single Mask Register for ChannelNumber
1208 // Clear the DMA Byte Pointer Register
1210 if (ChannelNumber
< 4) {
1211 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
1212 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
1213 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
1215 DmaMask
= R_8237_DMA_WRSMSK_CH4_7
;
1216 DmaClear
= R_8237_DMA_CBPR_CH4_7
;
1217 DmaChannelMode
= R_8237_DMA_CHMODE_CH4_7
;
1220 Status
= WritePort (
1223 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1225 if (EFI_ERROR (Status
)) {
1229 Status
= WritePort (
1232 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1234 if (EFI_ERROR (Status
)) {
1238 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
1239 if (EFI_ERROR (Status
)) {
1243 Status
= WriteDmaPort (
1245 mDmaRegisters
[ChannelNumber
].Address
,
1246 mDmaRegisters
[ChannelNumber
].Page
,
1247 mDmaRegisters
[ChannelNumber
].Count
,
1251 if (EFI_ERROR (Status
)) {
1255 Status
= WritePort (
1258 (UINT8
) (ChannelNumber
& 0x03)
1260 if (EFI_ERROR (Status
)) {
1268 Maps a memory region for DMA
1270 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1271 @param Operation Indicates the type of DMA (slave or bus master), and if
1272 the DMA operation is going to read or write to system memory.
1273 @param ChannelNumber The slave channel number to use for this DMA operation.
1274 If Operation and ChannelAttributes shows that this device
1275 performs bus mastering DMA, then this field is ignored.
1276 The legal range for this field is 0..7.
1277 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1278 @param HostAddress The system memory address to map to the device.
1279 @param NumberOfBytes On input the number of bytes to map. On output the number
1280 of bytes that were mapped.
1281 @param DeviceAddress The resulting map address for the bus master device to use
1282 to access the hosts HostAddress.
1283 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1285 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1286 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1287 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1288 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1289 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1294 IN EFI_ISA_IO_PROTOCOL
*This
,
1295 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
1296 IN UINT8 ChannelNumber OPTIONAL
,
1297 IN UINT32 ChannelAttributes
,
1298 IN VOID
*HostAddress
,
1299 IN OUT UINTN
*NumberOfBytes
,
1300 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
1305 // Set Feature Flag PcdIsaBusSupportDma to FALSE to disable support for ISA DMA.
1307 if (!FeaturePcdGet (PcdIsaBusSupportDma
)) {
1308 return EFI_UNSUPPORTED
;
1311 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1314 // So we just return EFI_UNSUPPORTED for these functions.
1316 if (FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma
)) {
1317 return IsaIoMapOnlySupportSlaveReadWrite (
1329 return IsaIoMapFullSupport (
1343 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
1345 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1346 @param[in] Type The type allocation to perform.
1347 @param[in] MemoryType The type of memory to allocate.
1348 @param[in] Pages The number of pages to allocate.
1349 @param[out] HostAddress A pointer to store the base address of the allocated range.
1350 @param[in] Attributes The requested bit mask of attributes for the allocated range.
1352 @retval EFI_SUCCESS The requested memory pages were allocated.
1353 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
1354 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
1355 by HostAddress, Pages, and Type is not available for common buffer use.
1356 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1360 IsaIoAllocateBuffer (
1361 IN EFI_ISA_IO_PROTOCOL
*This
,
1362 IN EFI_ALLOCATE_TYPE Type
,
1363 IN EFI_MEMORY_TYPE MemoryType
,
1365 OUT VOID
**HostAddress
,
1366 IN UINT64 Attributes
1370 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1373 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1375 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1377 if (!FeaturePcdGet (PcdIsaBusSupportDma
) || FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma
)) {
1378 return EFI_UNSUPPORTED
;
1381 if (HostAddress
== NULL
) {
1382 return EFI_INVALID_PARAMETER
;
1385 if (Type
< AllocateAnyPages
|| Type
>= MaxAllocateType
) {
1386 return EFI_INVALID_PARAMETER
;
1389 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1391 if (MemoryType
!= EfiBootServicesData
&& MemoryType
!= EfiRuntimeServicesData
) {
1392 return EFI_INVALID_PARAMETER
;
1395 if (Attributes
& ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
| EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED
)) {
1396 return EFI_UNSUPPORTED
;
1399 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (ISA_MAX_MEMORY_ADDRESS
- 1);
1400 if (Type
== AllocateAddress
) {
1401 if ((UINTN
) (*HostAddress
) >= ISA_MAX_MEMORY_ADDRESS
) {
1402 return EFI_UNSUPPORTED
;
1404 PhysicalAddress
= (UINTN
) (*HostAddress
);
1408 if (Type
== AllocateAnyPages
) {
1409 Type
= AllocateMaxAddress
;
1412 Status
= gBS
->AllocatePages (Type
, MemoryType
, Pages
, &PhysicalAddress
);
1413 if (EFI_ERROR (Status
)) {
1414 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
1418 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
1423 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
1425 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1426 @param[in] Pages The number of pages to free.
1427 @param[in] HostAddress The base address of the allocated range.
1429 @retval EFI_SUCCESS The requested memory pages were freed.
1430 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1435 IN EFI_ISA_IO_PROTOCOL
*This
,
1437 IN VOID
*HostAddress
1443 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1445 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1447 if (!FeaturePcdGet (PcdIsaBusSupportDma
) || FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma
)) {
1448 return EFI_UNSUPPORTED
;
1451 Status
= gBS
->FreePages (
1452 (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
,
1455 if (EFI_ERROR (Status
)) {
1456 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);