2 The implementation for EFI_ISA_IO_PROTOCOL.
4 Copyright (c) 2006 - 2007, 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"
18 // Driver Support Global Variables
20 EFI_ISA_IO_PROTOCOL IsaIoInterface
= {
40 EFI_ISA_DMA_REGISTERS DmaRegisters
[8] = {
65 }, // Channel 4 is invalid
84 report a error Status code of PCI bus driver controller
86 @param Code - The error status code.
88 @return EFI_SUCCESS - Success to report status code.
91 ReportErrorStatusCode (
92 EFI_STATUS_CODE_VALUE Code
96 return REPORT_STATUS_CODE (
97 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
103 // Driver Support Functions
107 Initializes an ISA I/O Instance
109 @param IsaIoDevice - The iso device to be initialized.
110 @param IsaDeviceResourceList - The resource list.
112 @retval EFI_SUCCESS - Initial success.
116 InitializeIsaIoInstance (
117 IN ISA_IO_DEVICE
*IsaIoDevice
,
118 IN EFI_ISA_ACPI_RESOURCE_LIST
*IsaDeviceResourceList
122 // Initializes an ISA I/O Instance
127 sizeof (EFI_ISA_IO_PROTOCOL
)
130 IsaIoDevice
->IsaIo
.ResourceList
= IsaDeviceResourceList
;
136 Performs an ISA I/O Read Cycle
138 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
139 @param Width - Signifies the width of the I/O operation.
140 @param Offset - The offset in ISA I/O space to start the I/O operation.
141 @param Count - The number of I/O operations to perform.
142 @param Buffer - The destination buffer to store the results
144 @retval EFI_SUCCESS - The data was read from the device sucessfully.
145 @retval EFI_UNSUPPORTED - The Offset is not valid for this device.
146 @retval EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.
147 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
153 IN EFI_ISA_IO_PROTOCOL
*This
,
154 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
162 ISA_IO_DEVICE
*IsaIoDevice
;
164 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
167 // Verify Isa IO Access
169 Status
= IsaIoVerifyAccess (
176 if (EFI_ERROR (Status
)) {
180 // Call PciIo->Io.Read
182 Status
= IsaIoDevice
->PciIo
->Io
.Read (
184 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
185 EFI_PCI_IO_PASS_THROUGH_BAR
,
191 if (EFI_ERROR (Status
)) {
192 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
199 Performs an ISA I/O Write Cycle
201 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
202 @param Width - Signifies the width of the I/O operation.
203 @param Offset - The offset in ISA I/O space to start the I/O operation.
204 @param Count - The number of I/O operations to perform.
205 @param Buffer - The source buffer to write data from
207 @retval EFI_SUCCESS - The data was writen to the device sucessfully.
208 @retval EFI_UNSUPPORTED - The Offset is not valid for this device.
209 @retval EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.
210 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
216 IN EFI_ISA_IO_PROTOCOL
*This
,
217 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
224 ISA_IO_DEVICE
*IsaIoDevice
;
226 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
229 // Verify Isa IO Access
231 Status
= IsaIoVerifyAccess (
238 if (EFI_ERROR (Status
)) {
242 // Call PciIo->Io.Write
244 Status
= IsaIoDevice
->PciIo
->Io
.Write (
246 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
247 EFI_PCI_IO_PASS_THROUGH_BAR
,
253 if (EFI_ERROR (Status
)) {
254 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
261 Writes an 8 bit I/O Port
263 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
264 @param Offset - The offset in ISA IO space to start the IO operation.
265 @param Value - The data to write port.
267 @retval EFI_SUCCESS - Success.
268 @retval EFI_INVALID_PARAMETER - Parameter is invalid.
269 @retval EFI_UNSUPPORTED - The address range specified by Offset is not valid.
270 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
275 IN EFI_ISA_IO_PROTOCOL
*This
,
282 ISA_IO_DEVICE
*IsaIoDevice
;
284 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
287 // Call PciIo->Io.Write
289 Status
= IsaIoDevice
->PciIo
->Io
.Write (
292 EFI_PCI_IO_PASS_THROUGH_BAR
,
297 if (EFI_ERROR (Status
)) {
298 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
308 Writes I/O operation base address and count number to a 8 bit I/O Port.
310 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
311 @param AddrOffset - The address' offset.
312 @param PageOffset - The page's offest.
313 @param CountOffset - The count's offset.
314 @param BaseAddress - The base address.
315 @param Count - The number of I/O operations to perform.
317 @retval EFI_SUCCESS - Success.
318 @retval EFI_INVALID_PARAMETER - Parameter is invalid.
319 @retval EFI_UNSUPPORTED - The address range specified by these Offsets and Count is not valid.
320 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
325 IN EFI_ISA_IO_PROTOCOL
*This
,
326 IN UINT32 AddrOffset
,
327 IN UINT32 PageOffset
,
328 IN UINT32 CountOffset
,
329 IN UINT32 BaseAddress
,
336 Status
= WritePort (This
, AddrOffset
, (UINT8
) (BaseAddress
& 0xff));
337 if (EFI_ERROR (Status
)) {
341 Status
= WritePort (This
, AddrOffset
, (UINT8
) ((BaseAddress
>> 8) & 0xff));
342 if (EFI_ERROR (Status
)) {
346 Status
= WritePort (This
, PageOffset
, (UINT8
) ((BaseAddress
>> 16) & 0xff));
347 if (EFI_ERROR (Status
)) {
351 Status
= WritePort (This
, CountOffset
, (UINT8
) (Count
& 0xff));
352 if (EFI_ERROR (Status
)) {
356 Status
= WritePort (This
, CountOffset
, (UINT8
) ((Count
>> 8) & 0xff));
357 if (EFI_ERROR (Status
)) {
365 Unmaps a memory region for DMA
367 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
368 @param Mapping - The mapping value returned from EFI_ISA_IO.Map().
370 @retval EFI_SUCCESS - The range was unmapped.
371 @retval EFI_DEVICE_ERROR - The data was not committed to the target system memory.
377 IN EFI_ISA_IO_PROTOCOL
*This
,
381 ISA_MAP_INFO
*IsaMapInfo
;
384 // Unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
386 if (!FeaturePcdGet (PcdIsaBusSupportDma
)) {
387 return EFI_UNSUPPORTED
;
391 // See if the Map() operation associated with this Unmap() required a mapping
392 // buffer.If a mapping buffer was not required, then this function simply
393 // returns EFI_SUCCESS.
395 if (Mapping
!= NULL
) {
397 // Get the MAP_INFO structure from Mapping
399 IsaMapInfo
= (ISA_MAP_INFO
*) Mapping
;
402 // If this is a write operation from the Agent's point of view,
403 // then copy the contents of the mapped buffer into the real buffer
404 // so the processor can read the contents of the real buffer.
406 if (IsaMapInfo
->Operation
== EfiIsaIoOperationBusMasterWrite
) {
408 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
409 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
410 IsaMapInfo
->NumberOfBytes
414 // Free the mapped buffer and the MAP_INFO structure.
416 gBS
->FreePages (IsaMapInfo
->MappedHostAddress
, IsaMapInfo
->NumberOfPages
);
417 gBS
->FreePool (IsaMapInfo
);
426 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
428 @retval EFI_SUCCESS - The buffers were flushed.
429 @retval EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error.
435 IN EFI_ISA_IO_PROTOCOL
*This
440 ISA_IO_DEVICE
*IsaIoDevice
;
442 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
447 Status
= IsaIoDevice
->PciIo
->Flush (IsaIoDevice
->PciIo
);
449 if (EFI_ERROR (Status
)) {
450 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
457 Verifies access to an ISA device
459 @param IsaIoDevice - The ISA device to be verified.
460 @param Type - The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
461 @param Width - Signifies the width of the memory operation.
462 @param Count - The number of memory operations to perform.
463 @param Offset - The offset in ISA memory space to start the memory operation.
465 @retval EFI_SUCCESS - Verify success.
466 @retval EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
467 @retval EFI_UNSUPPORTED - The device ont support the access type.
472 IN ISA_IO_DEVICE
*IsaIoDevice
,
473 IN ISA_ACCESS_TYPE Type
,
474 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
476 IN OUT UINT32
*Offset
480 EFI_ISA_ACPI_RESOURCE
*Item
;
483 if (Width
< EfiIsaIoWidthUint8
||
484 Width
>= EfiIsaIoWidthMaximum
||
485 Width
== EfiIsaIoWidthReserved
||
486 Width
== EfiIsaIoWidthFifoReserved
||
487 Width
== EfiIsaIoWidthFillReserved
489 return EFI_INVALID_PARAMETER
;
493 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
494 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
496 if (Width
>= EfiIsaIoWidthFifoUint8
&& Width
<= EfiIsaIoWidthFifoReserved
) {
500 Width
= (EFI_ISA_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
502 Status
= EFI_UNSUPPORTED
;
503 Item
= IsaIoDevice
->IsaIo
.ResourceList
->ResourceItem
;
504 while (Item
->Type
!= EfiIsaAcpiResourceEndOfList
) {
505 if ((Type
== IsaAccessTypeMem
&& Item
->Type
== EfiIsaAcpiResourceMemory
) ||
506 (Type
== IsaAccessTypeIo
&& Item
->Type
== EfiIsaAcpiResourceIo
)
508 if (*Offset
>= Item
->StartRange
&& (*Offset
+ Count
* (UINT32
)(1 << Width
)) - 1 <= Item
->EndRange
) {
512 if (*Offset
>= Item
->StartRange
&& *Offset
<= Item
->EndRange
) {
513 Status
= EFI_INVALID_PARAMETER
;
525 Performs an ISA Memory Read Cycle
527 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
528 @param Width - Signifies the width of the memory operation.
529 @param Offset - The offset in ISA memory space to start the memory operation.
530 @param Count - The number of memory operations to perform.
531 @param Buffer - The destination buffer to store the results
533 @retval EFI_SUCCESS - The data was read from the device successfully.
534 @retval EFI_UNSUPPORTED - The Offset is not valid for this device.
535 @retval EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.
536 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
542 IN EFI_ISA_IO_PROTOCOL
*This
,
543 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
551 ISA_IO_DEVICE
*IsaIoDevice
;
554 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
557 // So we just return EFI_UNSUPPORTED for these functions.
559 if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory
)) {
560 return EFI_UNSUPPORTED
;
563 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
566 // Verify the Isa Io Access
568 Status
= IsaIoVerifyAccess (
575 if (EFI_ERROR (Status
)) {
579 // Call PciIo->Mem.Read
581 Status
= IsaIoDevice
->PciIo
->Mem
.Read (
583 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
584 EFI_PCI_IO_PASS_THROUGH_BAR
,
590 if (EFI_ERROR (Status
)) {
591 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
598 Performs an ISA Memory Write Cycle
600 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
601 @param Width - Signifies the width of the memory operation.
602 @param Offset - The offset in ISA memory space to start the memory operation.
603 @param Count - The number of memory operations to perform.
604 @param Buffer - The source buffer to write data from
606 @retval EFI_SUCCESS - The data was written to the device sucessfully.
607 @retval EFI_UNSUPPORTED - The Offset is not valid for this device.
608 @retval EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.
609 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
615 IN EFI_ISA_IO_PROTOCOL
*This
,
616 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
623 ISA_IO_DEVICE
*IsaIoDevice
;
626 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
629 // So we just return EFI_UNSUPPORTED for these functions.
631 if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory
)) {
632 return EFI_UNSUPPORTED
;
635 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
638 // Verify Isa IO Access
640 Status
= IsaIoVerifyAccess (
647 if (EFI_ERROR (Status
)) {
651 // Call PciIo->Mem.Write
653 Status
= IsaIoDevice
->PciIo
->Mem
.Write (
655 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
656 EFI_PCI_IO_PASS_THROUGH_BAR
,
662 if (EFI_ERROR (Status
)) {
663 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
670 Performs an ISA I/O Copy Memory
672 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
673 @param Width - Signifies the width of the memory copy operation.
674 @param DestOffset - The offset of the destination
675 @param SrcOffset - The offset of the source
676 @param Count - The number of memory copy operations to perform
678 @retval EFI_SUCCESS - The data was copied sucessfully.
679 @retval EFI_UNSUPPORTED - The DestOffset or SrcOffset is not valid for this device.
680 @retval EFI_INVALID_PARAMETER - Width or Count, or both, were invalid.
681 @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
687 IN EFI_ISA_IO_PROTOCOL
*This
,
688 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
689 IN UINT32 DestOffset
,
696 ISA_IO_DEVICE
*IsaIoDevice
;
699 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
702 // So we just return EFI_UNSUPPORTED for these functions.
704 if (!FeaturePcdGet (PcdIsaBusSupportIsaMemory
)) {
705 return EFI_UNSUPPORTED
;
708 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
711 // Verify Isa IO Access for destination and source
713 Status
= IsaIoVerifyAccess (
720 if (EFI_ERROR (Status
)) {
724 Status
= IsaIoVerifyAccess (
731 if (EFI_ERROR (Status
)) {
735 // Call PciIo->CopyMem
737 Status
= IsaIoDevice
->PciIo
->CopyMem (
739 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
740 EFI_PCI_IO_PASS_THROUGH_BAR
,
742 EFI_PCI_IO_PASS_THROUGH_BAR
,
747 if (EFI_ERROR (Status
)) {
748 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
755 Maps a memory region for DMA, note this implementation
756 only supports slave read/write operation to save code size.
758 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
759 @param Operation - Indicates the type of DMA (slave or bus master), and if
760 the DMA operation is going to read or write to system memory.
761 @param ChannelNumber - The slave channel number to use for this DMA operation.
762 If Operation and ChannelAttributes shows that this device
763 performs bus mastering DMA, then this field is ignored.
764 The legal range for this field is 0..7.
765 @param ChannelAttributes - The attributes of the DMA channel to use for this DMA operation
766 @param HostAddress - The system memory address to map to the device.
767 @param NumberOfBytes - On input the number of bytes to map. On output the number
768 of bytes that were mapped.
769 @param DeviceAddress - The resulting map address for the bus master device to use
770 to access the hosts HostAddress.
771 @param Mapping - A resulting value to pass to EFI_ISA_IO.Unmap().
773 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
774 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
775 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
776 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
777 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
781 IsaIoMap_OnlySupportSlaveReadWrite (
782 IN EFI_ISA_IO_PROTOCOL
*This
,
783 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
784 IN UINT8 ChannelNumber OPTIONAL
,
785 IN UINT32 ChannelAttributes
,
786 IN VOID
*HostAddress
,
787 IN OUT UINTN
*NumberOfBytes
,
788 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
794 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
795 ISA_MAP_INFO
*IsaMapInfo
;
797 UINTN MaxNumberOfBytes
;
803 UINT8 DmaChannelMode
;
805 if ((NULL
== This
) ||
806 (NULL
== HostAddress
) ||
807 (NULL
== NumberOfBytes
) ||
808 (NULL
== DeviceAddress
) ||
811 return EFI_INVALID_PARAMETER
;
816 // Initialize the return values to their defaults
821 // Make sure the Operation parameter is valid.
822 // Light IsaIo only supports two operations.
824 if (!(Operation
== EfiIsaIoOperationSlaveRead
||
825 Operation
== EfiIsaIoOperationSlaveWrite
)) {
826 return EFI_INVALID_PARAMETER
;
829 if (ChannelNumber
>= 4) {
831 // The Light IsaIo doesn't support channelNumber larger than 4.
833 return EFI_INVALID_PARAMETER
;
837 // Map the HostAddress to a DeviceAddress.
839 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
840 if ((PhysicalAddress
+*NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
842 // Common Buffer operations can not be remapped. If the common buffer
843 // is above 16MB, then it is not possible to generate a mapping, so return
846 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
847 return EFI_UNSUPPORTED
;
850 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
853 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
854 if (IsaMapInfo
== NULL
) {
856 return EFI_OUT_OF_RESOURCES
;
859 // Return a pointer to the MAP_INFO structure in Mapping
861 *Mapping
= IsaMapInfo
;
864 // Initialize the MAP_INFO structure
866 IsaMapInfo
->Operation
= Operation
;
867 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
868 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
869 IsaMapInfo
->HostAddress
= PhysicalAddress
;
870 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
873 // Allocate a buffer below 16MB to map the transfer to.
875 Status
= gBS
->AllocatePages (
878 IsaMapInfo
->NumberOfPages
,
879 &IsaMapInfo
->MappedHostAddress
881 if (EFI_ERROR (Status
)) {
882 gBS
->FreePool (IsaMapInfo
);
888 // If this is a read operation from the DMA agents's point of view,
889 // then copy the contents of the real buffer into the mapped buffer
890 // so the DMA agent can read the contents of the real buffer.
892 if (Operation
== EfiIsaIoOperationSlaveRead
) {
894 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
895 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
896 IsaMapInfo
->NumberOfBytes
900 // The DeviceAddress is the address of the maped buffer below 16 MB
902 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
905 // The transfer is below 16 MB, so the DeviceAddress is simply the
908 *DeviceAddress
= PhysicalAddress
;
912 // Figure out what to program into the DMA Channel Mode Register
914 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
915 if (Operation
== EfiIsaIoOperationSlaveRead
) {
916 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
918 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
921 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
923 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
926 // A Slave DMA transfer can not cross a 64K boundary.
927 // Compute *NumberOfBytes based on this restriction.
929 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
930 if (*NumberOfBytes
> MaxNumberOfBytes
) {
931 *NumberOfBytes
= MaxNumberOfBytes
;
934 // Compute the values to program into the BaseAddress and Count registers
935 // of the Slave DMA controller
937 BaseAddress
= (UINT32
) (*DeviceAddress
);
938 Count
= (UINT16
) (*NumberOfBytes
- 1);
940 // Program the DMA Write Single Mask Register for ChannelNumber
941 // Clear the DMA Byte Pointer Register
943 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
944 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
945 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
950 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
952 if (EFI_ERROR (Status
)) {
959 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
961 if (EFI_ERROR (Status
)) {
965 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
966 if (EFI_ERROR (Status
)) {
970 Status
= WriteDmaPort (
972 DmaRegisters
[ChannelNumber
].Address
,
973 DmaRegisters
[ChannelNumber
].Page
,
974 DmaRegisters
[ChannelNumber
].Count
,
978 if (EFI_ERROR (Status
)) {
985 (UINT8
) (ChannelNumber
& 0x03)
987 if (EFI_ERROR (Status
)) {
995 Maps a memory region for DMA. This implementation implement the
996 the full mapping support.
998 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
999 @param Operation - Indicates the type of DMA (slave or bus master), and if
1000 the DMA operation is going to read or write to system memory.
1001 @param ChannelNumber - The slave channel number to use for this DMA operation.
1002 If Operation and ChannelAttributes shows that this device
1003 performs bus mastering DMA, then this field is ignored.
1004 The legal range for this field is 0..7.
1005 @param ChannelAttributes - The attributes of the DMA channel to use for this DMA operation
1006 @param HostAddress - The system memory address to map to the device.
1007 @param NumberOfBytes - On input the number of bytes to map. On output the number
1008 of bytes that were mapped.
1009 @param DeviceAddress - The resulting map address for the bus master device to use
1010 - to access the hosts HostAddress.
1011 @param Mapping - A resulting value to pass to EFI_ISA_IO.Unmap().
1013 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
1014 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
1015 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
1016 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
1017 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
1021 IsaIoMap_FullSupport (
1022 IN EFI_ISA_IO_PROTOCOL
*This
,
1023 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
1024 IN UINT8 ChannelNumber OPTIONAL
,
1025 IN UINT32 ChannelAttributes
,
1026 IN VOID
*HostAddress
,
1027 IN OUT UINTN
*NumberOfBytes
,
1028 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
1036 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1037 ISA_MAP_INFO
*IsaMapInfo
;
1039 UINTN MaxNumberOfBytes
;
1045 UINT8 DmaChannelMode
;
1047 if ((NULL
== This
) ||
1048 (NULL
== HostAddress
) ||
1049 (NULL
== NumberOfBytes
) ||
1050 (NULL
== DeviceAddress
) ||
1053 return EFI_INVALID_PARAMETER
;
1058 // Initialize the return values to their defaults
1063 // Make sure the Operation parameter is valid
1065 if (Operation
< 0 || Operation
>= EfiIsaIoOperationMaximum
) {
1066 return EFI_INVALID_PARAMETER
;
1069 // See if this is a Slave DMA Operation
1073 if (Operation
== EfiIsaIoOperationSlaveRead
) {
1074 Operation
= EfiIsaIoOperationBusMasterRead
;
1079 if (Operation
== EfiIsaIoOperationSlaveWrite
) {
1080 Operation
= EfiIsaIoOperationBusMasterWrite
;
1087 // Make sure that ChannelNumber is a valid channel number
1088 // Channel 4 is used to cascade, so it is illegal.
1090 if (ChannelNumber
== 4 || ChannelNumber
> 7) {
1091 return EFI_INVALID_PARAMETER
;
1094 // This implementation only support COMPATIBLE DMA Transfers
1096 if (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE
)) {
1097 return EFI_INVALID_PARAMETER
;
1100 if (ChannelAttributes
&
1102 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A
|
1103 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B
|
1104 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
1107 return EFI_INVALID_PARAMETER
;
1110 if (ChannelNumber
< 4) {
1112 // If this is Channel 0..3, then the width must be 8 bit
1114 if (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) ||
1115 (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
)
1117 return EFI_INVALID_PARAMETER
;
1121 // If this is Channel 4..7, then the width must be 16 bit
1123 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) ||
1124 (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
))
1126 return EFI_INVALID_PARAMETER
;
1130 // Either Demand Mode or Single Mode must be selected, but not both
1132 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) {
1133 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) {
1134 return EFI_INVALID_PARAMETER
;
1137 if (!(ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
)) {
1138 return EFI_INVALID_PARAMETER
;
1143 // Map the HostAddress to a DeviceAddress.
1145 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
1146 if ((PhysicalAddress
+*NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
1148 // Common Buffer operations can not be remapped. If the common buffer
1149 // is above 16MB, then it is not possible to generate a mapping, so return
1152 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
1153 return EFI_UNSUPPORTED
;
1156 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1159 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
1160 if (IsaMapInfo
== NULL
) {
1162 return EFI_OUT_OF_RESOURCES
;
1165 // Return a pointer to the MAP_INFO structure in Mapping
1167 *Mapping
= IsaMapInfo
;
1170 // Initialize the MAP_INFO structure
1172 IsaMapInfo
->Operation
= Operation
;
1173 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
1174 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
1175 IsaMapInfo
->HostAddress
= PhysicalAddress
;
1176 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
1179 // Allocate a buffer below 16MB to map the transfer to.
1181 Status
= gBS
->AllocatePages (
1183 EfiBootServicesData
,
1184 IsaMapInfo
->NumberOfPages
,
1185 &IsaMapInfo
->MappedHostAddress
1187 if (EFI_ERROR (Status
)) {
1188 gBS
->FreePool (IsaMapInfo
);
1194 // If this is a read operation from the DMA agents's point of view,
1195 // then copy the contents of the real buffer into the mapped buffer
1196 // so the DMA agent can read the contents of the real buffer.
1198 if (Operation
== EfiIsaIoOperationBusMasterRead
) {
1200 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
1201 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
1202 IsaMapInfo
->NumberOfBytes
1206 // The DeviceAddress is the address of the maped buffer below 16 MB
1208 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
1211 // The transfer is below 16 MB, so the DeviceAddress is simply the
1214 *DeviceAddress
= PhysicalAddress
;
1217 // If this is a Bus Master operation then return
1223 // Figure out what to program into the DMA Channel Mode Register
1225 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
1227 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
1229 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
1232 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE
) {
1233 DmaMode
|= B_8237_DMA_CHMODE_AE
;
1236 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) {
1237 DmaMode
|= V_8237_DMA_CHMODE_DEMAND
;
1240 if (ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) {
1241 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
1244 // A Slave DMA transfer can not cross a 64K boundary.
1245 // Compute *NumberOfBytes based on this restriction.
1247 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
1248 if (*NumberOfBytes
> MaxNumberOfBytes
) {
1249 *NumberOfBytes
= MaxNumberOfBytes
;
1252 // Compute the values to program into the BaseAddress and Count registers
1253 // of the Slave DMA controller
1255 if (ChannelNumber
< 4) {
1256 BaseAddress
= (UINT32
) (*DeviceAddress
);
1257 Count
= (UINT16
) (*NumberOfBytes
- 1);
1259 BaseAddress
= (UINT32
) (((UINT32
) (*DeviceAddress
) & 0xff0000) | (((UINT32
) (*DeviceAddress
) & 0xffff) >> 1));
1260 Count
= (UINT16
) ((*NumberOfBytes
- 1) >> 1);
1263 // Program the DMA Write Single Mask Register for ChannelNumber
1264 // Clear the DMA Byte Pointer Register
1266 if (ChannelNumber
< 4) {
1267 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
1268 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
1269 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
1271 DmaMask
= R_8237_DMA_WRSMSK_CH4_7
;
1272 DmaClear
= R_8237_DMA_CBPR_CH4_7
;
1273 DmaChannelMode
= R_8237_DMA_CHMODE_CH4_7
;
1276 Status
= WritePort (
1279 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1281 if (EFI_ERROR (Status
)) {
1285 Status
= WritePort (
1288 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1290 if (EFI_ERROR (Status
)) {
1294 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
1295 if (EFI_ERROR (Status
)) {
1299 Status
= WriteDmaPort (
1301 DmaRegisters
[ChannelNumber
].Address
,
1302 DmaRegisters
[ChannelNumber
].Page
,
1303 DmaRegisters
[ChannelNumber
].Count
,
1307 if (EFI_ERROR (Status
)) {
1311 Status
= WritePort (
1314 (UINT8
) (ChannelNumber
& 0x03)
1316 if (EFI_ERROR (Status
)) {
1324 Maps a memory region for DMA
1326 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
1327 @param Operation - Indicates the type of DMA (slave or bus master), and if
1328 the DMA operation is going to read or write to system memory.
1329 @param ChannelNumber - The slave channel number to use for this DMA operation.
1330 If Operation and ChannelAttributes shows that this device
1331 performs bus mastering DMA, then this field is ignored.
1332 The legal range for this field is 0..7.
1333 @param ChannelAttributes - The attributes of the DMA channel to use for this DMA operation
1334 @param HostAddress - The system memory address to map to the device.
1335 @param NumberOfBytes - On input the number of bytes to map. On output the number
1336 of bytes that were mapped.
1337 @param DeviceAddress - The resulting map address for the bus master device to use
1338 - to access the hosts HostAddress.
1339 @param Mapping - A resulting value to pass to EFI_ISA_IO.Unmap().
1342 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
1343 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
1344 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
1345 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
1346 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
1352 IN EFI_ISA_IO_PROTOCOL
*This
,
1353 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
1354 IN UINT8 ChannelNumber OPTIONAL
,
1355 IN UINT32 ChannelAttributes
,
1356 IN VOID
*HostAddress
,
1357 IN OUT UINTN
*NumberOfBytes
,
1358 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
1364 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1366 if (!FeaturePcdGet (PcdIsaBusSupportDma
)) {
1367 return EFI_UNSUPPORTED
;
1370 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1373 // So we just return EFI_UNSUPPORTED for these functions.
1375 if (FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma
)) {
1376 return IsaIoMap_OnlySupportSlaveReadWrite (
1388 return IsaIoMap_FullSupport (
1402 Allocates a common buffer for DMA
1404 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
1405 @param Type - The type allocation to perform.
1406 @param MemoryType - The type of memory to allocate.
1407 @param Pages - The number of pages to allocate.
1408 @param HostAddress - A pointer to store the base address of the allocated range.
1409 @param Attributes - The requested bit mask of attributes for the allocated range.
1411 @retval EFI_SUCCESS - The requested memory pages were allocated.
1412 @retval EFI_INVALID_PARAMETER - Type is invalid or MemoryType is invalid or HostAddress is NULL
1413 @retval EFI_UNSUPPORTED - Attributes is unsupported or the memory range specified
1414 by HostAddress, Pages, and Type is not available for common buffer use.
1415 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
1420 IsaIoAllocateBuffer (
1421 IN EFI_ISA_IO_PROTOCOL
*This
,
1422 IN EFI_ALLOCATE_TYPE Type
,
1423 IN EFI_MEMORY_TYPE MemoryType
,
1425 OUT VOID
**HostAddress
,
1426 IN UINT64 Attributes
1430 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1433 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1435 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1437 if (!FeaturePcdGet (PcdIsaBusSupportDma
) || FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma
)) {
1438 return EFI_UNSUPPORTED
;
1441 if (HostAddress
== NULL
) {
1442 return EFI_INVALID_PARAMETER
;
1445 if (Type
< AllocateAnyPages
|| Type
>= MaxAllocateType
) {
1446 return EFI_INVALID_PARAMETER
;
1449 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1451 if (MemoryType
!= EfiBootServicesData
&& MemoryType
!= EfiRuntimeServicesData
) {
1452 return EFI_INVALID_PARAMETER
;
1455 if (Attributes
&~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
| EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED
)) {
1456 return EFI_UNSUPPORTED
;
1459 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (ISA_MAX_MEMORY_ADDRESS
- 1);
1460 if (Type
== AllocateAddress
) {
1461 if ((UINTN
) (*HostAddress
) >= ISA_MAX_MEMORY_ADDRESS
) {
1462 return EFI_UNSUPPORTED
;
1464 PhysicalAddress
= (UINTN
) (*HostAddress
);
1468 if (Type
== AllocateAnyPages
) {
1469 Type
= AllocateMaxAddress
;
1472 Status
= gBS
->AllocatePages (Type
, MemoryType
, Pages
, &PhysicalAddress
);
1473 if (EFI_ERROR (Status
)) {
1474 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
1478 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
1484 Frees a common buffer
1486 @param This - A pointer to the EFI_ISA_IO_PROTOCOL instance.
1487 @param Pages - The number of pages to free.
1488 @param HostAddress - The base address of the allocated range.
1491 @retval EFI_SUCCESS - The requested memory pages were freed.
1492 @retval EFI_INVALID_PARAMETER - The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1499 IN EFI_ISA_IO_PROTOCOL
*This
,
1501 IN VOID
*HostAddress
1505 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1508 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1510 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1512 if (!FeaturePcdGet (PcdIsaBusSupportDma
) || FeaturePcdGet (PcdIsaBusOnlySupportSlaveDma
)) {
1513 return EFI_UNSUPPORTED
;
1516 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
1517 Status
= gBS
->FreePages (
1521 if (EFI_ERROR (Status
)) {
1522 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);